{"action":"created","comment":{"url":"https://api.github.com/repos/broadinstitute/gatk/pulls/comments/186236786","pull_request_review_id":117785959,"id":186236786,"diff_hunk":"@@ -0,0 +1,856 @@\n+package org.broadinstitute.hellbender.tools.spark.sv.discovery.inference;\n+\n+import com.google.common.collect.Sets;\n+import htsjdk.samtools.SAMSequenceDictionary;\n+import htsjdk.variant.variantcontext.Allele;\n+import htsjdk.variant.variantcontext.VariantContext;\n+import htsjdk.variant.variantcontext.VariantContextBuilder;\n+import htsjdk.variant.vcf.VCFConstants;\n+import org.apache.commons.lang3.math.NumberUtils;\n+import org.apache.logging.log4j.LogManager;\n+import org.apache.logging.log4j.Logger;\n+import org.apache.spark.api.java.JavaRDD;\n+import org.apache.spark.api.java.JavaSparkContext;\n+import org.apache.spark.broadcast.Broadcast;\n+import org.broadinstitute.barclay.argparser.Argument;\n+import org.broadinstitute.barclay.argparser.ArgumentCollection;\n+import org.broadinstitute.barclay.argparser.BetaFeature;\n+import org.broadinstitute.barclay.argparser.CommandLineProgramProperties;\n+import org.broadinstitute.barclay.help.DocumentedFeature;\n+import org.broadinstitute.hellbender.cmdline.programgroups.StructuralVariantDiscoveryProgramGroup;\n+import org.broadinstitute.hellbender.engine.datasources.ReferenceMultiSource;\n+import org.broadinstitute.hellbender.engine.spark.GATKSparkTool;\n+import org.broadinstitute.hellbender.engine.spark.datasources.VariantsSparkSource;\n+import org.broadinstitute.hellbender.exceptions.GATKException;\n+import org.broadinstitute.hellbender.tools.spark.sv.StructuralVariationDiscoveryArgumentCollection;\n+import org.broadinstitute.hellbender.tools.spark.sv.StructuralVariationDiscoveryPipelineSpark;\n+import org.broadinstitute.hellbender.tools.spark.sv.discovery.SimpleSVType;\n+import org.broadinstitute.hellbender.tools.spark.sv.discovery.SvDiscoverFromLocalAssemblyContigAlignmentsSpark;\n+import org.broadinstitute.hellbender.tools.spark.sv.discovery.SvDiscoveryInputData;\n+import org.broadinstitute.hellbender.tools.spark.sv.discovery.alignment.AlignedContig;\n+import org.broadinstitute.hellbender.tools.spark.sv.discovery.alignment.AssemblyContigWithFineTunedAlignments;\n+import org.broadinstitute.hellbender.tools.spark.sv.utils.GATKSVVCFConstants;\n+import org.broadinstitute.hellbender.tools.spark.sv.utils.SVInterval;\n+import org.broadinstitute.hellbender.tools.spark.sv.utils.SVIntervalTree;\n+import org.broadinstitute.hellbender.tools.spark.sv.utils.SVVCFWriter;\n+import org.broadinstitute.hellbender.utils.SimpleInterval;\n+import org.broadinstitute.hellbender.utils.read.GATKRead;\n+import scala.Tuple2;\n+\n+import java.io.IOException;\n+import java.util.*;\n+import java.util.stream.Collectors;\n+import java.util.stream.IntStream;\n+import java.util.stream.Stream;\n+\n+import static org.broadinstitute.hellbender.tools.spark.sv.discovery.inference.AssemblyContigAlignmentSignatureClassifier.RawTypes.Cpx;\n+\n+/**\n+ * (Internal) Tries to extract simple variants from a provided GATK-SV CPX.vcf\n+ */\n+@DocumentedFeature\n+@BetaFeature\n+@CommandLineProgramProperties(\n+        oneLineSummary = \"(Internal) Tries to extract simple variants from a provided GATK-SV CPX.vcf\",\n+        summary =\n+                \"This tool is used in development and should not be of interest to most researchers.\" +\n+                \" It is a prototype of complex structural variant re-interpretation.\" +\n+                \" In particular, it tries to extract basic SVTYPE's from a user-provided GATK-SV CPX.vcf,\" +\n+                \" and outputs two VCF files containing bare bone information on the simple variants.\",\n+        programGroup = StructuralVariantDiscoveryProgramGroup.class)\n+public class CpxVariantReInterpreterSpark extends GATKSparkTool {\n+    private static final long serialVersionUID = 1L;\n+    private final Logger localLogger = LogManager.getLogger(CpxVariantReInterpreterSpark.class);\n+\n+    @Override\n+    public boolean requiresReference() {\n+        return true;\n+    }\n+\n+    @Override\n+    public boolean requiresReads() {\n+        return true;\n+    }\n+\n+    @ArgumentCollection\n+    private StructuralVariationDiscoveryArgumentCollection.DiscoverVariantsFromContigsAlignmentsSparkArgumentCollection\n+            discoverStageArgs\n+            = new StructuralVariationDiscoveryArgumentCollection.DiscoverVariantsFromContigsAlignmentsSparkArgumentCollection();\n+\n+    @Argument(doc = \"file containing non-canonical chromosome names (e.g chrUn_KI270588v1) in the reference, human reference (hg19 or hg38) assumed when omitted\",\n+            shortName = \"alt-tigs\",\n+            fullName = \"non-canonical-contig-names-file\", optional = true)\n+    public String nonCanonicalChromosomeNamesFile;\n+\n+    @Argument(doc = \"file containing complex variants as output by GATK-SV\",\n+            fullName = \"cpx-vcf\")\n+    private String complexVCF;\n+\n+    @Argument(doc = \"prefix for two files containing derived simple variants for complex variants having one/multiple entry in SEGMENT annotation\",\n+            fullName = \"prefix-out-vcf\")\n+    private String derivedSimpleVCFPrefix;\n+\n+    public static String EVENT_KEY = \"CPX_EVENT\"; // for use in output VCF to link to original CPX variant\n+\n+    @Override\n+    protected void runTool(final JavaSparkContext ctx) {\n+\n+        final List<VariantContext> complexVariants = new VariantsSparkSource(ctx)\n+                .getParallelVariantContexts(complexVCF, null).collect();\n+\n+        localLogger.info(\"Dealing with \" + complexVariants.size() + \" complex variants\");\n+\n+        final Broadcast<SVIntervalTree<VariantContext>> cnvCallsBroadcast =\n+                StructuralVariationDiscoveryPipelineSpark.broadcastCNVCalls(ctx, getHeaderForReads(),\n+                        discoverStageArgs.cnvCallsFile);\n+        final SvDiscoveryInputData svDiscoveryInputData =\n+                new SvDiscoveryInputData(ctx, discoverStageArgs, nonCanonicalChromosomeNamesFile, derivedSimpleVCFPrefix,\n+                        null, null, null,\n+                        cnvCallsBroadcast,\n+                        getUnfilteredReads(), getHeaderForReads(), getReference(), localLogger);\n+\n+        apiOpenToPipeline( complexVariants, svDiscoveryInputData);\n+    }\n+\n+    // exist for use by SV pipeline\n+    public static void apiOpenToPipeline(final List<VariantContext> complexVariants,\n+                                         final SvDiscoveryInputData svDiscoveryInputData) {\n+\n+        final ReferenceMultiSource reference = svDiscoveryInputData.inputMetaData.referenceBroadcast.getValue();\n+        final SAMSequenceDictionary refSeqDict = svDiscoveryInputData.inputMetaData.referenceSequenceDictionaryBroadcast.getValue();\n+\n+        final Stream<VariantContext> zeroSegmentCalls = complexVariants.stream()\n+                .filter(vc -> makeSureAttributeIsList(vc, GATKSVVCFConstants.CPX_SV_REF_SEGMENTS).isEmpty());\n+\n+        final Stream<VariantContext> oneSegmentCalls = complexVariants.stream()\n+                .filter(vc -> makeSureAttributeIsList(vc, GATKSVVCFConstants.CPX_SV_REF_SEGMENTS).size() == 1);\n+\n+        final Stream<VariantContext> multiSegmentCalls = complexVariants.stream()\n+                .filter(vc -> makeSureAttributeIsList(vc, GATKSVVCFConstants.CPX_SV_REF_SEGMENTS).size() > 1);\n+\n+        final List<VariantContext> reInterpretOneSegmentCalls = reInterpretZeroOrOneSegmentCalls(zeroSegmentCalls, oneSegmentCalls, reference);\n+\n+        final List<VariantContext> reInterpretMultiSegmentsCalls = reInterpretMultiSegmentsCalls(multiSegmentCalls, svDiscoveryInputData);\n+\n+        final String prefix = svDiscoveryInputData.outputPath;\n+        CpxVariantReInterpreterSpark.writeResults(reInterpretOneSegmentCalls, reInterpretMultiSegmentsCalls, refSeqDict,\n+                prefix + \"_1_seg.vcf\", prefix + \"_multi_seg.vcf\",\n+                svDiscoveryInputData.inputMetaData.toolLogger);\n+    }\n+\n+    //==================================================================================================================\n+\n+    /**\n+     * Re-interpret CPX vcf records whose {@link GATKSVVCFConstants#CPX_SV_REF_SEGMENTS} has only one entry,\n+     * aka \"one-segment\" calls, and those without such annotations, i.e. those with pure inserted sequence.\n+     *\n+     * @return the {@link SimpleSVType}-d variants extracted from the input {@code complexVariants}\n+     */\n+    private static List<VariantContext> reInterpretZeroOrOneSegmentCalls(final Stream<VariantContext> zeroSegmentCalls,\n+                                                                         final Stream<VariantContext> oneSegmentCalls,\n+                                                                         final ReferenceMultiSource reference) {\n+\n+        final Stream<VariantContext> reInterpreted = zeroSegmentCalls\n+                .map(vc -> {\n+                    final Allele anchorBaseRefAllele = Allele.create(vc.getAlleles().get(0).getBases()[0], true);\n+                    final Allele altSymbAlleleIns = Allele.create(SimpleSVType.createBracketedSymbAlleleString(GATKSVVCFConstants.SYMB_ALT_ALLELE_INS));\n+                    final int altSeqLength = vc.getAttributeAsString(GATKSVVCFConstants.SEQ_ALT_HAPLOTYPE, \"\").length() - 1;\n+                    final VariantContextBuilder vcBuilderForIns = new VariantContextBuilder()\n+                            .chr(vc.getContig()).start(vc.getStart()).stop(vc.getStart())\n+                            .id(makeIDForIns(vc.getContig(), vc.getStart(), vc.getStart()))\n+                            .alleles(Arrays.asList(anchorBaseRefAllele, altSymbAlleleIns))\n+                            .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INS.name())\n+                            .attribute(GATKSVVCFConstants.SVLEN, altSeqLength)\n+                            .attribute(EVENT_KEY, vc.getID())\n+                            .attribute(GATKSVVCFConstants.CONTIG_NAMES, makeSureAttributeIsList(vc, GATKSVVCFConstants.CONTIG_NAMES));\n+                    return vcBuilderForIns.make();\n+                });\n+\n+        return Stream.concat(\n+                reInterpreted,\n+                oneSegmentCalls.flatMap(vc -> CpxVariantReInterpreterSpark.workerForOneSegmentCalls(vc, reference))\n+        ).collect(Collectors.toList());\n+    }\n+\n+    /**\n+     * Depending on if the ref segment is present in alt arrangement, logic as follows:\n+     * <ul>\n+     *     <li>\n+     *         ref segment is absent\n+     *         <ul>\n+     *             <li> present inverted -> INV (if size > 49) and INS (if new material > 49) </li>\n+     *             <li> not at all       -> DEL (if size > 49) and INS (if new material > 49) </li>\n+     *         </ul>\n+     *     </li>\n+     *\n+     *     <li>\n+     *         ref segment is present\n+     *         <ul>\n+     *             <li> there's >=1 inverted presence -> INV (if size > 49) and INS (if new material subtracting the INV > 49) </li>\n+     *             <li> there's no  inverted presence -> INS (if new material > 49) </li>\n+     *         </ul>\n+     *     </li>\n+     * </ul>\n+     */\n+    private static Stream<VariantContext> workerForOneSegmentCalls(final VariantContext vc, final ReferenceMultiSource reference) {\n+\n+        final List<String> evidenceContigs = makeSureAttributeIsList(vc, GATKSVVCFConstants.CONTIG_NAMES);\n+        final SimpleInterval refSegment =\n+                new SimpleInterval(vc.getAttributeAsString(GATKSVVCFConstants.CPX_SV_REF_SEGMENTS, \"\"));\n+        final int segmentSize = refSegment.size();\n+\n+        final int altSeqLength = vc.getAttributeAsString(GATKSVVCFConstants.SEQ_ALT_HAPLOTYPE, \"\").length() - 1;\n+\n+        final List<String> altArrangement = makeSureAttributeIsList(vc, GATKSVVCFConstants.CPX_EVENT_ALT_ARRANGEMENTS);\n+\n+        final List<VariantContext> result = new ArrayList<>();\n+        final Allele anchorBaseRefAllele = Allele.create(vc.getAlleles().get(0).getBases()[0], true);\n+        final Allele fatInsertionRefAllele;\n+        try {\n+            fatInsertionRefAllele = Allele.create(reference.getReferenceBases(refSegment).getBases(), true);\n+        } catch (final IOException ioex) {\n+            throw new GATKException(\"\", ioex);\n+        }\n+        final Allele altSymbAlleleDel = Allele.create(SimpleSVType.createBracketedSymbAlleleString(GATKSVVCFConstants.SYMB_ALT_ALLELE_DEL));\n+        final Allele altSymbAlleleIns = Allele.create(SimpleSVType.createBracketedSymbAlleleString(GATKSVVCFConstants.SYMB_ALT_ALLELE_INS));\n+        final Allele altSymbAlleleInv = Allele.create(SimpleSVType.createBracketedSymbAlleleString(GATKSVVCFConstants.SYMB_ALT_ALLELE_INV));\n+        final long invertedAppearance = altArrangement.stream().filter(s -> s.equals(\"-1\")).count();\n+        final long asIsAppearance = altArrangement.stream().filter(s -> s.equals(\"1\")).count();\n+\n+        if (asIsAppearance == 0) {\n+            if (invertedAppearance == 0) {\n+                if ( segmentSize > 49 ) {\n+                    final VariantContextBuilder vcBuilderForDel = new VariantContextBuilder()\n+                            .chr(refSegment.getContig()).start(refSegment.getStart()).stop(refSegment.getEnd())\n+                            .id(makeIDForDel(refSegment))\n+                            .alleles(Arrays.asList(anchorBaseRefAllele, altSymbAlleleDel))\n+                            .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.DEL.name())\n+                            .attribute(GATKSVVCFConstants.SVLEN, -segmentSize)\n+                            .attribute(VCFConstants.END_KEY, refSegment.getEnd())\n+                            .attribute(EVENT_KEY, refSegment.getEnd())\n+                            .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+                    final VariantContext del = vcBuilderForDel.make();\n+                    result.add(del);\n+                }\n+                if ( altSeqLength > 49 ) { // depending on if the segment is > 49, the REF allele is either anchor or fat\n+                    if (segmentSize > 49) {\n+                        final VariantContextBuilder vcBuilderForIns = new VariantContextBuilder()\n+                                .chr(vc.getContig()).start(vc.getStart()).stop(vc.getStart())\n+                                .id(makeIDForIns(vc.getContig(), vc.getStart(), vc.getStart()))\n+                                .alleles(Arrays.asList(anchorBaseRefAllele, altSymbAlleleIns))\n+                                .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INS.name())\n+                                .attribute(GATKSVVCFConstants.SVLEN, altSeqLength)\n+                                .attribute(EVENT_KEY, vc.getID())\n+                                .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+                        final VariantContext ins = vcBuilderForIns.make();\n+                        result.add(ins);\n+                    } else { // fat insertion\n+                        final VariantContextBuilder vcBuilderForIns = new VariantContextBuilder()\n+                                .chr(refSegment.getContig()).start(refSegment.getStart()).stop(refSegment.getEnd())\n+                                .id(makeIDForIns(refSegment.getContig(), refSegment.getStart(), refSegment.getEnd()))\n+                                .alleles(Arrays.asList(fatInsertionRefAllele, altSymbAlleleIns))\n+                                .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INS.name())\n+                                .attribute(GATKSVVCFConstants.SVLEN, altSeqLength)\n+                                .attribute(EVENT_KEY, vc.getID())\n+                                .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+                        final VariantContext ins = vcBuilderForIns.make();\n+                        result.add(ins);\n+                    }\n+                }\n+            } else {\n+                if (segmentSize > 49) {\n+                    final VariantContextBuilder vcBuilderForInv = new VariantContextBuilder()\n+                            .chr(refSegment.getContig()).start(refSegment.getStart()).stop(refSegment.getEnd())\n+                            .id(makeIDForInv(refSegment))\n+                            .alleles(Arrays.asList(anchorBaseRefAllele, altSymbAlleleInv))\n+                            .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INV.name())\n+                            .attribute(GATKSVVCFConstants.SVLEN, 0) // per VCF spec, INV should have 0 length\n+                            .attribute(VCFConstants.END_KEY, refSegment.getEnd())\n+                            .attribute(EVENT_KEY, vc.getID())\n+                            .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+                    final VariantContext inv = vcBuilderForInv.make();\n+                    result.add(inv);\n+                    if ( altSeqLength - segmentSize > 49 ) {\n+                        final VariantContextBuilder vcBuilderForIns = new VariantContextBuilder()\n+                                .chr(vc.getContig()).start(vc.getStart()).stop(vc.getStart())\n+                                .id(makeIDForIns(vc.getContig(), vc.getStart(), vc.getStart()))\n+                                .alleles(Arrays.asList(anchorBaseRefAllele, altSymbAlleleIns))\n+                                .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INS.name())\n+                                .attribute(GATKSVVCFConstants.SVLEN, altSeqLength - segmentSize)\n+                                .attribute(EVENT_KEY, vc.getID())\n+                                .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+                        final VariantContext ins = vcBuilderForIns.make();\n+                        result.add(ins);\n+                    }\n+                } else if ( altSeqLength > 49 ){ // ref segment replace with fat INS (because the ref segment is not long enough to merit a deletion)\n+                    final VariantContextBuilder vcBuilderForIns = new VariantContextBuilder()\n+                            .chr(refSegment.getContig()).start(refSegment.getStart()).stop(refSegment.getEnd())\n+                            .id(makeIDForIns(refSegment.getContig(), refSegment.getStart(), refSegment.getEnd()))\n+                            .alleles(Arrays.asList(fatInsertionRefAllele, altSymbAlleleIns))\n+                            .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INS.name())\n+                            .attribute(GATKSVVCFConstants.SVLEN, altSeqLength)\n+                            .attribute(EVENT_KEY, vc.getID())\n+                            .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+                    final VariantContext ins = vcBuilderForIns.make();\n+                    result.add(ins);\n+                }\n+            }\n+        } else { // at least one \"1\", so no deletion can be emitted\n+            if (invertedAppearance == 0) {\n+                if ( altSeqLength - segmentSize > 49 ) { // long enough net gain\n+                    // distinguish between cases {\"1\", ....}, {.....,\"1\"}, and {.....,\"1\", ....} to know where to put the insertion\n+                    if (altArrangement.get(altArrangement.size() - 1).equals(\"1\")) {\n+                        final VariantContextBuilder vcBuilderForIns = new VariantContextBuilder()\n+                                .chr(vc.getContig()).start(vc.getStart()).stop(vc.getStart())\n+                                .id(makeIDForIns(vc.getContig(), vc.getStart(), vc.getStart()))\n+                                .alleles(Arrays.asList(anchorBaseRefAllele, altSymbAlleleIns))\n+                                .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INS.name())\n+                                .attribute(GATKSVVCFConstants.SVLEN, altSeqLength - segmentSize)\n+                                .attribute(EVENT_KEY, vc.getID())\n+                                .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+                        final VariantContext ins = vcBuilderForIns.make();\n+                        result.add(ins);\n+                    } else if (altArrangement.get(0).equals(\"1\")) {\n+                        final VariantContextBuilder vcBuilderForIns = new VariantContextBuilder()\n+                                .chr(vc.getContig()).start(vc.getStart()).stop(vc.getStart())\n+                                .id(makeIDForIns(vc.getContig(), vc.getStart(), vc.getStart()))\n+                                .alleles(Arrays.asList(anchorBaseRefAllele, altSymbAlleleIns))\n+                                .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INS.name())\n+                                .attribute(GATKSVVCFConstants.SVLEN, altSeqLength - segmentSize)\n+                                .attribute(EVENT_KEY, vc.getID())\n+                                .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+                        final VariantContext ins = vcBuilderForIns.make();\n+                        result.add(ins);\n+                    } else {\n+                        // find first index of \"1\" entry, collect new insertion length before that, then collect new bases length after that\n+                        final int idxFirstMatch = altArrangement.indexOf(\"1\");\n+                        final VariantContext frontIns = getFrontIns(vc, evidenceContigs, altArrangement, anchorBaseRefAllele, altSymbAlleleIns, idxFirstMatch);\n+                        result.add(frontIns);\n+\n+                        final byte[] refBases = vc.getReference().getBases();\n+                        final Allele anchorBaseRefAlleleRear = Allele.create(refBases[refBases.length - 1], true);\n+                        final VariantContext rearIns = getRearIns(vc, evidenceContigs, altArrangement, anchorBaseRefAlleleRear, altSymbAlleleIns, idxFirstMatch);\n+                        result.add(rearIns);\n+                    }\n+                }\n+            } else {\n+                if (segmentSize > 49) { // segment inverted long enough to warrant an inversion\n+                    final VariantContextBuilder vcBuilderForInv = new VariantContextBuilder()\n+                            .chr(refSegment.getContig()).start(refSegment.getStart()).stop(refSegment.getEnd())\n+                            .id(makeIDForIns(refSegment.getContig(), refSegment.getStart(), refSegment.getEnd()))\n+                            .alleles(Arrays.asList(anchorBaseRefAllele, altSymbAlleleInv))\n+                            .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INV.name())\n+                            .attribute(GATKSVVCFConstants.SVLEN, 0) // per VCF spec, INV should have 0 length\n+                            .attribute(VCFConstants.END_KEY, refSegment.getEnd())\n+                            .attribute(EVENT_KEY, vc.getID())\n+                            .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+                    final VariantContext inv = vcBuilderForInv.make();\n+                    result.add(inv);\n+                    if ( altSeqLength - segmentSize > 49 ) {\n+                        final VariantContextBuilder vcBuilderForIns = new VariantContextBuilder()\n+                                .chr(vc.getContig()).start(vc.getStart()).stop(vc.getStart())\n+                                .id(makeIDForIns(vc.getContig(), vc.getStart(), vc.getStart()))\n+                                .alleles(Arrays.asList(anchorBaseRefAllele, altSymbAlleleIns))\n+                                .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INS.name())\n+                                .attribute(GATKSVVCFConstants.SVLEN, altSeqLength - segmentSize)\n+                                .attribute(EVENT_KEY, vc.getID())\n+                                .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+                        final VariantContext ins = vcBuilderForIns.make();\n+                        result.add(ins);\n+                    }\n+                } else if ( altSeqLength - segmentSize > 49 ) { // inverted segment not long enough for an inversion call\n+                    final VariantContextBuilder vcBuilderForIns = new VariantContextBuilder()\n+                            .chr(vc.getContig()).start(vc.getStart()).stop(vc.getStart())\n+                            .id(makeIDForIns(vc.getContig(), vc.getStart(), vc.getStart()))\n+                            .alleles(Arrays.asList(anchorBaseRefAllele, altSymbAlleleIns))\n+                            .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INS.name())\n+                            .attribute(GATKSVVCFConstants.SVLEN, altSeqLength - segmentSize)\n+                            .attribute(EVENT_KEY, vc.getID())\n+                            .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+                    final VariantContext ins = vcBuilderForIns.make();\n+                    result.add(ins);\n+                }\n+            }\n+        }\n+        return result.stream();\n+    }\n+\n+    //==================================================================================================================\n+\n+    /**\n+     * Re-interpret CPX vcf records whose {@link GATKSVVCFConstants#CPX_SV_REF_SEGMENTS} has more than one entries,\n+     * aka \"multi-segment\" calls.\n+     *\n+     * @return the {@link SimpleSVType}-d variants extracted from the input {@code complexVariants}\n+     */\n+    private static List<VariantContext> reInterpretMultiSegmentsCalls(final Stream<VariantContext> multiSegmentCalls,\n+                                                                      final SvDiscoveryInputData svDiscoveryInputData) {\n+\n+        final List<VariantContext> collect = multiSegmentCalls.collect(Collectors.toList());\n+        final ReferenceMultiSource reference = svDiscoveryInputData.inputMetaData.referenceBroadcast.getValue();\n+        final Stream<VariantContext> oneSource = pairIterationWayOfReInterpretation(collect, svDiscoveryInputData);\n+        final Stream<VariantContext> concat = Stream.concat(\n+                oneSource,\n+                collect.stream().flatMap(vc -> workerForMultiSegmentsCalls(vc, reference))\n+        );\n+\n+        return removeDuplicates(concat);\n+    }\n+\n+\n+    /**\n+     * Get contigs who triggered multi-segment calls,\n+     * create a map from their read name to the corresponding CPX variant,\n+     * then collect their alignments for sending them through the pair-iteration-ed way of re-interpretation.\n+     */\n+    private static Stream<VariantContext> pairIterationWayOfReInterpretation(final List<VariantContext> multiSegmentCalls,\n+                                                                             final SvDiscoveryInputData svDiscoveryInputData) {\n+\n+        final Map<String, VariantContext> contigNameToCpxVariant = multiSegmentCalls.stream()\n+                .flatMap(vc -> makeSureAttributeIsList(vc, GATKSVVCFConstants.CONTIG_NAMES).stream().map(s -> new Tuple2<>(s, vc)))\n+                .collect(Collectors.toMap(pair -> pair._1, pair -> pair._2));\n+\n+        final JavaRDD<GATKRead> relevantAlignments =\n+                svDiscoveryInputData.assemblyRawAlignments.filter(read -> contigNameToCpxVariant.containsKey(read.getName()));\n+        final SvDiscoveryInputData filteredData =\n+                new SvDiscoveryInputData(svDiscoveryInputData.inputMetaData, relevantAlignments, svDiscoveryInputData.outputPath);\n+\n+        // resend the contigs through the pair-iteration-ed path\n+        final JavaRDD<AlignedContig> analysisReadyContigs =\n+                SvDiscoverFromLocalAssemblyContigAlignmentsSpark.preprocess(filteredData, false)\n+                        .get(Cpx)\n+                        .map(AssemblyContigWithFineTunedAlignments::getSourceContig);\n+\n+        @SuppressWarnings(\"deprecation\")\n+        final List<VariantContext> reInterpreted =\n+                org.broadinstitute.hellbender.tools.spark.sv.discovery\n+                        .DiscoverVariantsFromContigAlignmentsSAMSpark\n+                        .discoverVariantsFromChimeras(filteredData.inputMetaData, analysisReadyContigs);\n+\n+        // collect those CPX variants whose re-interpretation from above would be rejected, then re-interpret with workerForMultiSegmentsCalls()\n+        final Stream<VariantContext> consistent = reInterpreted\n+                .stream()\n+                .map(simpleVC -> {\n+                    final List<String> consistentComplexVariantIDs =\n+                            makeSureAttributeIsList(simpleVC, GATKSVVCFConstants.CONTIG_NAMES).stream()\n+                                    .map(contigNameToCpxVariant::get)\n+                                    .filter(cpx -> isConsistentWithCPX(simpleVC, cpx))\n+                                    .map(VariantContext::getID)\n+                                    .collect(Collectors.toList());\n+                    if (consistentComplexVariantIDs.isEmpty()) {\n+                        return null;\n+                    } else { // add new annotation for signalling that they were extracted from CPX variants\n+                        return new VariantContextBuilder(simpleVC)\n+                                .attribute(EVENT_KEY,\n+                                        String.join(VCFConstants.INFO_FIELD_ARRAY_SEPARATOR, consistentComplexVariantIDs))\n+                                .id(simpleVC.getID() + GATKSVVCFConstants.INTERVAL_VARIANT_ID_FIELD_SEPARATOR +\n+                                        CPX_DERIVED)\n+                                .make();\n+                    }\n+                })\n+                .filter(Objects::nonNull);\n+\n+        return consistent;\n+    }\n+\n+    /**\n+     * // TODO: 3/26/18 check consistency with CPX call, here we check consistency only for DEL and INV calls\n+     * @param simple   simple variant derived from pair-iteration logic that is to be checked\n+     * @param complex  CPX variant induced by the same contig that induced the simple variant\n+     */\n+    private static boolean isConsistentWithCPX(final VariantContext simple, final VariantContext complex) {\n+\n+        final List<SimpleInterval> refSegments = makeSureAttributeIsList(complex, GATKSVVCFConstants.CPX_SV_REF_SEGMENTS)\n+                .stream().map(SimpleInterval::new).collect(Collectors.toList());\n+\n+        final Tuple2<Set<Integer>, List<Integer>> presentAndInvertedSegments = getPresentAndInvertedSegments(complex);\n+\n+        final Set<Integer> presentSegments = presentAndInvertedSegments._1;\n+        final Set<Integer> invertedSegments = new HashSet<>( presentAndInvertedSegments._2 );\n+\n+        final String typeString = (String) simple.getAttribute(GATKSVVCFConstants.SVTYPE, \"\");\n+        if (typeString.equals(SimpleSVType.TYPES.DEL.name())) {\n+\n+            final List<SimpleInterval> missingSegments = IntStream.rangeClosed(1, refSegments.size()).boxed()\n+                    .filter(i -> !presentSegments.contains(i) && !invertedSegments.contains(i))\n+                    .map(i -> refSegments.get(i-1))\n+                    .collect(Collectors.toList());\n+            if (missingSegments.isEmpty())\n+                return false;\n+\n+            final SimpleInterval deletedRange = new SimpleInterval(simple.getContig(), simple.getStart(), simple.getEnd());\n+            // dummy number for chr to be used in constructing SVInterval, since 2 input AI's both map to the same chr by this point\n+            final int dummyChr = -1;\n+            final SVInterval intervalOne = new SVInterval(dummyChr, deletedRange.getStart() - 1, deletedRange.getEnd());\n+\n+            for (final SimpleInterval missing : missingSegments) {\n+                final SVInterval intervalTwo = new SVInterval(dummyChr, missing.getStart() - 1, missing.getEnd());\n+                // allow 1-base fuzziness from either end\n+                if ( Math.abs(missing.size() - deletedRange.size()) > 2 )\n+                    return false;\n+                if( 2 >= Math.abs( Math.min(missing.size(), deletedRange.size()) - intervalTwo.overlapLen(intervalOne) ) ){\n+                    return true;\n+                }\n+            }\n+            return false;\n+        } else if (typeString.equals(SimpleSVType.TYPES.INV.name())) {\n+\n+            if (invertedSegments.isEmpty())\n+                return false;\n+\n+            final SimpleInterval invertedRange = new SimpleInterval(simple.getContig(), simple.getStart(), simple.getEnd());\n+            // dummy number for chr to be used in constructing SVInterval, since 2 input AI's both map to the same chr by this point\n+            final int dummyChr = -1;\n+            final SVInterval intervalOne = new SVInterval(dummyChr, invertedRange.getStart() - 1, invertedRange.getEnd());\n+            for (int i = 0; i < refSegments.size(); ++i) {\n+                final SimpleInterval segment = refSegments.get(i);\n+                final SVInterval intervalTwo = new SVInterval(dummyChr, segment.getStart() - 1, segment.getEnd());\n+                // allow 1-base fuzziness from either end\n+                if( 2 >= Math.abs( Math.min(segment.size(), invertedRange.size()) - intervalTwo.overlapLen(intervalOne) ) ){ // this also gets rid of a case where a large deletion is interpreted but is actually a dispersed duplication (the stringent kills it)\n+                    return (invertedSegments.contains(i)) && (!presentSegments.contains(i)); // inverted range appears in inverted segments, but absent in alt description without the \"-\" sign (if present, treat as insertion)\n+                }\n+            }\n+            return false;\n+        } else\n+            return true; // TODO: 3/26/18 check consistency with CPX call, here we check consistency only for DEL and INV calls\n+    }\n+\n+    /**\n+     * Experimental way of re-interpreting the multi-segment calls,\n+     * doesn't seem to perform well yet for INS calls based on manual-inspection,\n+     * so we don't output insertion calls from this way of re-interpretation\n+     */\n+    private static Stream<? extends VariantContext> workerForMultiSegmentsCalls(final VariantContext complexVC,\n+                                                                                final ReferenceMultiSource reference) {\n+\n+        final Tuple2<Set<Integer>, List<Integer>> presentAndInvertedSegments = getPresentAndInvertedSegments(complexVC);\n+        final Set<Integer> presentSegments = presentAndInvertedSegments._1;\n+        final List<Integer> invertedSegments = presentAndInvertedSegments._2;\n+        final List<SimpleInterval> segments = makeSureAttributeIsList(complexVC, GATKSVVCFConstants.CPX_SV_REF_SEGMENTS).stream()\n+                .map(SimpleInterval::new)\n+                .collect(Collectors.toList());\n+\n+        final List<Integer> missingSegments = IntStream.rangeClosed(1, segments.size()).boxed()\n+                .filter(i -> !presentSegments.contains(i) && !invertedSegments.contains(i))\n+                .collect(Collectors.toList());\n+\n+        final List<String> evidenceContigs = makeSureAttributeIsList(complexVC, GATKSVVCFConstants.CONTIG_NAMES);\n+\n+        final List<VariantContext> result = new ArrayList<>();\n+\n+        // inversions\n+        if ( !invertedSegments.isEmpty() ) {\n+            result.addAll(\n+                    invertedSegments.stream()\n+                            .filter(i -> segments.get(i - 1).size() > 49 && (!presentSegments.contains(i)) ) // large enough; in addition, if both as-is and inverted versions exist, treat as insertions?\n+                            .map(i -> {\n+                                try {\n+                                    final SimpleInterval segment = segments.get(i - 1);\n+                                    final byte[] ref = reference.getReferenceBases(new SimpleInterval(segment.getContig(), segment.getStart(), segment.getStart())).getBases();\n+                                    return new VariantContextBuilder()\n+                                            .chr(segment.getContig()).start(segment.getStart()).stop(segment.getEnd())\n+                                            .id(makeIDForInv(segment))\n+                                            .alleles(Arrays.asList(\n+                                                    Allele.create(ref, true),\n+                                                    Allele.create(SimpleSVType.createBracketedSymbAlleleString(GATKSVVCFConstants.SYMB_ALT_ALLELE_INV)))\n+                                            )\n+                                            .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INV.name())\n+                                            .attribute(EVENT_KEY, complexVC.getID())\n+                                            .attribute(VCFConstants.END_KEY, segment.getEnd())\n+                                            .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs)\n+                                            .make();\n+                                } catch (final IOException ioex) {\n+                                    throw new GATKException(\"\", ioex);\n+                                }\n+                            })\n+                            .collect(Collectors.toList())\n+            );\n+        }\n+\n+        // deletions\n+        if ( !missingSegments.isEmpty() ){\n+            result.addAll(\n+                    missingSegments.stream()\n+                            .filter(i -> segments.get(i - 1).size() > 49) // large enough\n+                            .map(i -> {\n+                                try {\n+                                    final SimpleInterval segment = segments.get(i - 1);\n+                                    final byte[] ref = reference.getReferenceBases(new SimpleInterval(segment.getContig(), segment.getStart(), segment.getStart())).getBases();\n+                                    return new VariantContextBuilder()\n+                                            .chr(segment.getContig()).start(segment.getStart()).stop(segment.getEnd())\n+                                            .id(makeIDForDel(segment))\n+                                            .alleles(Arrays.asList(\n+                                                    Allele.create(ref, true),\n+                                                    Allele.create(SimpleSVType.createBracketedSymbAlleleString(GATKSVVCFConstants.SYMB_ALT_ALLELE_DEL)))\n+                                            )\n+                                            .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.DEL.name())\n+                                            .attribute(GATKSVVCFConstants.SVLEN, -segment.size())\n+                                            .attribute(EVENT_KEY, complexVC.getID())\n+                                            .attribute(VCFConstants.END_KEY, segment.getEnd())\n+                                            .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs)\n+                                            .make();\n+                                } catch (final IOException ioex) {\n+                                    throw new GATKException(\"\", ioex);\n+                                }\n+                            })\n+                            .collect(Collectors.toList())\n+            );\n+        }\n+\n+        // head and tail insertions only\n+        final List<String> altArrangement = makeSureAttributeIsList(complexVC, GATKSVVCFConstants.CPX_EVENT_ALT_ARRANGEMENTS);\n+        final byte[] refBases = complexVC.getReference().getBases();\n+        final Allele altSymbAlleleIns = Allele.create(SimpleSVType.createBracketedSymbAlleleString(GATKSVVCFConstants.SYMB_ALT_ALLELE_INS));\n+        int idx = -1;\n+        for (final String description : altArrangement) {\n+            if ( descriptionIndicatesInsertion(description)) {\n+                ++idx;\n+            } else {\n+                break;\n+            }\n+        }\n+        if (idx >= 0) {\n+            ++idx;\n+            final Allele anchorBaseRefAlleleFront = Allele.create(refBases[0], true);\n+            result.add( getFrontIns(complexVC, evidenceContigs, altArrangement, anchorBaseRefAlleleFront, altSymbAlleleIns, idx) );\n+        }\n+\n+        idx = altArrangement.size();\n+        for (int i = altArrangement.size() - 1; i > -1 ; --i) {\n+            if ( descriptionIndicatesInsertion(altArrangement.get(i))) {\n+                --idx;\n+            } else {\n+                break;\n+            }\n+        }\n+\n+        if (idx != altArrangement.size()) {\n+            --idx;\n+            final Allele anchorBaseRefAlleleRear = Allele.create(refBases[refBases.length-1], true);\n+            result.add( getRearIns(complexVC, evidenceContigs, altArrangement, anchorBaseRefAlleleRear, altSymbAlleleIns, idx) );\n+        }\n+\n+        return result.stream();\n+    }\n+\n+    private static boolean descriptionIndicatesInsertion(final String description) {\n+        if (description.startsWith(CpxVariantCanonicalRepresentation.UNMAPPED_INSERTION))\n+            return true;\n+        return !NumberUtils.isCreatable(description); // \"(-)?[0-9]+\" is describing segments, we don't count them as insertions\n+    }\n+\n+    /**\n+     * Retrieves from the provide {@code complexVC}, reference segments described in\n+     * {@link GATKSVVCFConstants#CPX_SV_REF_SEGMENTS}, that are\n+     *   a) present as is, i.e. not inverted\n+     *   b) inverted\n+     */\n+    private static Tuple2<Set<Integer>, List<Integer>> getPresentAndInvertedSegments(final VariantContext complexVC) {\n+        final List<Integer> invertedSegments = new ArrayList<>();\n+        final Set<Integer> presentSegments = new TreeSet<>();\n+        makeSureAttributeIsList(complexVC, GATKSVVCFConstants.CPX_EVENT_ALT_ARRANGEMENTS)\n+                .forEach(s -> {\n+                    if ( s.startsWith(\"-\") && ( !s.contains(\":\") )) { // some segment inverted\n+                        invertedSegments.add( Integer.valueOf(s.substring(1)) );\n+                    }\n+                    if ( !s.contains(\":\") && !s.startsWith(CpxVariantCanonicalRepresentation.UNMAPPED_INSERTION) && !s.startsWith(\"-\") ) { // a ref segment, but not inverted\n+                        presentSegments.add(Integer.valueOf(s));\n+                    }\n+                });\n+        return new Tuple2<>(presentSegments, invertedSegments);\n+    }\n+\n+    //==================================================================================================================\n+    private static VariantContext getFrontIns(final VariantContext vc,\n+                                              final List<String> evidenceContigs,\n+                                              final List<String> altArrangement,\n+                                              final Allele anchorBaseRefAllele,\n+                                              final Allele altSymbAlleleIns,\n+                                              final int idxFirstMatch) {\n+        int insLen = 0;\n+        for (int i = 0; i < idxFirstMatch; ++i) {\n+            final String description = altArrangement.get(i);\n+            insLen += getInsLen(description);\n+        }\n+\n+        final VariantContextBuilder vcBuilderForFrontIns = new VariantContextBuilder()\n+                .chr(vc.getContig()).start(vc.getStart()).stop(vc.getStart())\n+                .id(makeIDForIns(vc.getContig(), vc.getStart(), vc.getStart()))\n+                .alleles(Arrays.asList(anchorBaseRefAllele, altSymbAlleleIns))\n+                .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INS.name())\n+                .attribute(GATKSVVCFConstants.SVLEN, insLen)\n+                .attribute(VCFConstants.END_KEY, vc.getStart())\n+                .attribute(EVENT_KEY, vc.getID())\n+                .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+        return vcBuilderForFrontIns.make();\n+    }\n+\n+    private static VariantContext getRearIns(final VariantContext vc,\n+                                             final List<String> evidenceContigs,\n+                                             final List<String> altArrangement,\n+                                             final Allele anchorBaseRefAllele,\n+                                             final Allele altSymbAlleleIns,\n+                                             final int idxFirstMatch) {\n+        int insLen = 0;\n+        for (int i = idxFirstMatch + 1; i < altArrangement.size(); ++i) {\n+            insLen += getInsLen( altArrangement.get(i) );\n+        }\n+\n+        final VariantContextBuilder vcBuilderForRearIns = new VariantContextBuilder()\n+                .chr(vc.getContig()).start(vc.getEnd()).stop(vc.getEnd())\n+                .id(makeIDForIns(vc.getContig(), vc.getEnd(), vc.getEnd()))\n+                .alleles(Arrays.asList(anchorBaseRefAllele, altSymbAlleleIns))\n+                .attribute(GATKSVVCFConstants.SVTYPE, SimpleSVType.TYPES.INS.name())\n+                .attribute(GATKSVVCFConstants.SVLEN, insLen)\n+                .attribute(VCFConstants.END_KEY, vc.getEnd())\n+                .attribute(EVENT_KEY, vc.getID())\n+                .attribute(GATKSVVCFConstants.CONTIG_NAMES, evidenceContigs);\n+        return vcBuilderForRearIns.make();\n+    }\n+\n+    private static int getInsLen(final String description) {\n+        if(description.startsWith(CpxVariantCanonicalRepresentation.UNMAPPED_INSERTION)) {\n+            return Integer.valueOf( description.substring(CpxVariantCanonicalRepresentation.UNMAPPED_INSERTION.length() + 1) );\n+        } else {\n+            final int offset = description.startsWith(\"-\") ? 1 : 0;\n+            return new SimpleInterval (description.substring(offset) ).size();\n+        }\n+    }\n+\n+    private static List<VariantContext> removeDuplicates(final Stream<VariantContext> toBeDeDuplicated) {\n+        // separate by types {DEL, INS, INV} and compare with same type\n+        final List<VariantContext> deletions = new ArrayList<>();\n+        final List<VariantContext> insertions = new ArrayList<>();\n+        final List<VariantContext> inversions = new ArrayList<>();\n+\n+        toBeDeDuplicated.forEach(vc -> {\n+            final String type = vc.getAttributeAsString(GATKSVVCFConstants.SVTYPE, \"\");\n+            if(type.equals(SimpleSVType.TYPES.DEL.name())) {\n+                deletions.add(vc);\n+            } else if (type.equals(SimpleSVType.TYPES.INS.name())) {\n+                insertions.add(vc);\n+            } else {\n+                inversions.add(vc);\n+            }\n+        });\n+\n+        final List<VariantContext> result = new ArrayList<>(deletions.size() + insertions.size() + inversions.size());\n+        result.addAll(mergeSameVariants(deletions));\n+        result.addAll(mergeSameVariants(insertions));\n+        result.addAll(mergeSameVariants(inversions));\n+\n+        return result;\n+    }\n+\n+    private static final class Annotation {\n+        final String id;\n+        final String type;\n+        final int svlen;\n+        final List<Allele> alleles;\n+\n+        final Set<String> sourceCPXids;\n+        final Set<String> sourceTigs;\n+\n+        Annotation(final String id, final String type, final int svlen, final List<Allele> alleles, final Set<String> sourceCPXids, final Set<String> sourceTigs) {\n+            this.id = id;\n+            this.type = type;\n+            this.svlen = svlen;\n+            this.alleles = alleles;\n+            this.sourceCPXids = sourceCPXids;\n+            this.sourceTigs = sourceTigs;\n+        }\n+    }\n+    private static List<VariantContext> mergeSameVariants(final List<VariantContext> vcs) {\n+        final Map<SimpleInterval, Annotation> rangeToAnnotations = new HashMap<>();\n+\n+        for(final VariantContext vc : vcs) {\n+            final SimpleInterval range = new SimpleInterval(vc.getContig(), vc.getStart(), vc.getEnd());\n+            Annotation annotation = rangeToAnnotations.get(range);\n+            if (annotation == null) {\n+                rangeToAnnotations.put(\n+                        range,\n+                        new Annotation(vc.getID(),\n+                                vc.getAttributeAsString(GATKSVVCFConstants.SVTYPE, \"\"),\n+                                vc.getAttributeAsInt(GATKSVVCFConstants.SVLEN, 0),\n+                                vc.getAlleles(),\n+                                Sets.newHashSet(vc.getAttributeAsString(EVENT_KEY, \"\")),\n+                                new HashSet<>( makeSureAttributeIsList(vc, GATKSVVCFConstants.CONTIG_NAMES)))\n+                );\n+            } else {\n+                annotation.sourceCPXids.add(vc.getAttributeAsString(EVENT_KEY, \"\"));\n+                annotation.sourceTigs.addAll(makeSureAttributeIsList(vc, GATKSVVCFConstants.CONTIG_NAMES));\n+            }\n+        }\n+\n+        final List<VariantContext> result = new ArrayList<>();\n+        for (final Map.Entry<SimpleInterval, Annotation> entry: rangeToAnnotations.entrySet()) {\n+            final SimpleInterval range = entry.getKey();\n+            final Annotation annotation = entry.getValue();\n+            final VariantContextBuilder builder = new VariantContextBuilder()\n+                    .chr(range.getContig()).start(range.getStart()).stop(range.getEnd())\n+                    .id(annotation.id)\n+                    .alleles(annotation.alleles)\n+                    .attribute(GATKSVVCFConstants.SVTYPE, annotation.type)\n+                    .attribute(GATKSVVCFConstants.SVLEN, annotation.svlen)\n+                    .attribute(VCFConstants.END_KEY, range.getEnd())\n+                    .attribute(EVENT_KEY, String.join(VCFConstants.INFO_FIELD_ARRAY_SEPARATOR, annotation.sourceCPXids))\n+                    .attribute(GATKSVVCFConstants.CONTIG_NAMES, String.join(VCFConstants.INFO_FIELD_ARRAY_SEPARATOR, annotation.sourceTigs));\n+            result.add(builder.make());\n+        }\n+        return result;\n+    }\n+\n+    //==================================================================================================================\n+    private static void writeResults(final List<VariantContext> reInterpretOneSegmentCalls,\n+                                     final List<VariantContext> reInterpretMultiSegmentsCalls,\n+                                     final SAMSequenceDictionary sequenceDictionary,\n+                                     final String derivedOneSegmentSimpleVCF,\n+                                     final String derivedMultiSegmentSimpleVCF,\n+                                     final Logger logger) {\n+\n+        SVVCFWriter.writeVCF(reInterpretOneSegmentCalls, derivedOneSegmentSimpleVCF, sequenceDictionary, logger);\n+\n+        SVVCFWriter.writeVCF(reInterpretMultiSegmentsCalls, derivedMultiSegmentSimpleVCF, sequenceDictionary, logger);\n+    }\n+\n+    // this exist because for whatever reason, VC.getAttributeAsStringList() sometimes returns a giant single string\n+    // while using VC.getAttributeAsString() gives back an array.....\n+    private static List<String> makeSureAttributeIsList(final VariantContext vc, final String attributeKey) {","path":"src/main/java/org/broadinstitute/hellbender/tools/spark/sv/discovery/inference/CpxVariantReInterpreterSpark.java","position":null,"original_position":818,"commit_id":"05d8bc39074a80e4f5ba00d38279bdaedd9f8b05","original_commit_id":"13bf85904217f9644f0d41b55cfd4ce5117aa2f0","user":{"login":"SHuang-Broad","id":16310888,"avatar_url":"https://avatars3.githubusercontent.com/u/16310888?v=4","gravatar_id":"","url":"https://api.github.com/users/SHuang-Broad","html_url":"https://github.com/SHuang-Broad","followers_url":"https://api.github.com/users/SHuang-Broad/followers","following_url":"https://api.github.com/users/SHuang-Broad/following{/other_user}","gists_url":"https://api.github.com/users/SHuang-Broad/gists{/gist_id}","starred_url":"https://api.github.com/users/SHuang-Broad/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SHuang-Broad/subscriptions","organizations_url":"https://api.github.com/users/SHuang-Broad/orgs","repos_url":"https://api.github.com/users/SHuang-Broad/repos","events_url":"https://api.github.com/users/SHuang-Broad/events{/privacy}","received_events_url":"https://api.github.com/users/SHuang-Broad/received_events","type":"User","site_admin":false},"body":"renamed to `getAttributeAsStringList(...)` though that \"collides\" with the hdsjdk name a bit","created_at":"2018-05-04T22:38:32Z","updated_at":"2018-05-04T22:40:16Z","html_url":"https://github.com/broadinstitute/gatk/pull/4602#discussion_r186236786","pull_request_url":"https://api.github.com/repos/broadinstitute/gatk/pulls/4602","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/broadinstitute/gatk/pulls/comments/186236786"},"html":{"href":"https://github.com/broadinstitute/gatk/pull/4602#discussion_r186236786"},"pull_request":{"href":"https://api.github.com/repos/broadinstitute/gatk/pulls/4602"}},"in_reply_to_id":185038366},"pull_request":{"url":"https://api.github.com/repos/broadinstitute/gatk/pulls/4602","id":177893883,"html_url":"https://github.com/broadinstitute/gatk/pull/4602","diff_url":"https://github.com/broadinstitute/gatk/pull/4602.diff","patch_url":"https://github.com/broadinstitute/gatk/pull/4602.patch","issue_url":"https://api.github.com/repos/broadinstitute/gatk/issues/4602","number":4602,"state":"open","locked":false,"title":"(SV) re-interpreting CPX records by experimental interpretation tool","user":{"login":"SHuang-Broad","id":16310888,"avatar_url":"https://avatars3.githubusercontent.com/u/16310888?v=4","gravatar_id":"","url":"https://api.github.com/users/SHuang-Broad","html_url":"https://github.com/SHuang-Broad","followers_url":"https://api.github.com/users/SHuang-Broad/followers","following_url":"https://api.github.com/users/SHuang-Broad/following{/other_user}","gists_url":"https://api.github.com/users/SHuang-Broad/gists{/gist_id}","starred_url":"https://api.github.com/users/SHuang-Broad/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SHuang-Broad/subscriptions","organizations_url":"https://api.github.com/users/SHuang-Broad/orgs","repos_url":"https://api.github.com/users/SHuang-Broad/repos","events_url":"https://api.github.com/users/SHuang-Broad/events{/privacy}","received_events_url":"https://api.github.com/users/SHuang-Broad/received_events","type":"User","site_admin":false},"body":"A not-so-elegant way to tackle #4323, and part of #4111 .\r\n\r\n__UPDATE__: fixes #4323 \r\n\r\n---\r\nBrief explanation:\r\n\r\nThe `<CPX>` variants we currently output has an annotation `SEGMENTS`, which could contain\r\n\r\n* 0-entries (which will be simply omitted): this is when the head and tail alignments seamlessly stitch together on the reference, and middle alignments are all taken as inserted sequence\r\n* 1-entry: this is when head/tail alignment overlap on reference over the region specified in the entry, hence we have a deletion or duplication of that region (depending on if the segment is present in another annotation `ALT_ARRANGEMENT`, or if present, whether it is inverted), and insertion of more sequences\r\n* multiple entries: there are the truly complex ones\r\n\r\nwhile the first two cases are easy to deal with, the last one is very difficult to parse into simple variants, and has the inherent evil of ambiguity in representations (to demonstrate, a not very complicated one could be like this)\r\n```\r\nchr6\t166997615\tCPX_chr6:166997615-166997944\tACCCACAGACAGAAACACAGAGACATGTTTGGAAGCCAGTGTGGATGCCCTGTGATCTGTGTGTACACATGACAAGTGCATACACACGCACATAAAGGAACCCAGAGACGTGTTTGGAAGCCAGTGTGGACACCCTGTGATCTGTGCGTACACATTTGACACCTGCGTACACACTCACAGACAGAAACACAGAGATGTGTTTGGAAGCCAGTGTGGACATCCTGTGGTCTGCGCGTACACATGTGACAGGTACGTGCACGCCCACATACAGGAACACACAGAGGCCTTTGGAAGCCAGCATGGGCAGACAGGCCCTATCCCAAAGCGGCC\t<CPX>\t.\t.\tALIGN_LENGTHS=309;ALT_ARRANGEMENT=1,2,3,4,5,UINS-733,2,UINS-94,-6,-5,UINS-41,4,5,UINS-40,1,2,3,4,5,6;CTG_GOOD_NONCANONICAL_MAPPING=chrUn_JTFH01000473v1_decoy,1,-,51H1640M204H,60,0,1640;CTG_NAMES=asm011602:tig00001;END=166997944;HQ_MAPPINGS=1;MAPPING_QUALITIES=60;MAX_ALIGN_LENGTH=309;SEGMENTS=chr6:166997615-166997617,chr6:166997617-166997679,chr6:166997679-166997727,chr6:166997727-166997787,chr6:166997787-166997831,chr6:166997832-166997944;SEQ_ALT_HAPLOTYPE=ACCCACAGACAGAAACACAGAGACATGTTTGGAAGCCAGTGTGGATGCCCTGTGATCTGTGTGTACACATGACAAGTGCATACACACGCACATAAAGGAACCCAGAGACGTGTTTGGAAGCCAGTGTGGACACCCTGTGATCTGTGCGTACACATTTGACACCTGCGTACACACTCACAGACAGAAACACAGAGATGTGTTTGGAAGCCAGCGTGGATGCCCTGTGATCTCTGCATACACGTGACACATGCATGCACAGGCCCATACAGGAGCAGAGAGACACATTTGGAAGCCGATGTACGCCCTGTGATCTGTGCGTACACGTGACACATGCGTACACACCCACTGACAAGAACACAGAGACGTGTTTGGAAGCCAGTGTGGACGCCCTGTAATCTGTGTGTACACACGTGACACATGCGTGCACACCCACTGACAAGAACAGAGACCCATTTGGAAGCCAGTGTGGGTGCCCTGTGATCTGATCTGTGTGTACACATGTGACACGTGCATCCACACCCACTGACAAGCACACAAGAGACACATTTGAAAGCCAGTGTGGATGCCTTGTGATCTGTGTGTACACATGTGACATGGGCATATGCACCTACAGACAGAAACGCAGAGATGCATTTGGAAGTCACTGTGGATACCTTGTCATCTGTGTGTACACATGAGACACTTGCATACACACCCACATACAGGAACACAGAGACACGTTTGGAAGCCAGTGTGGATGTCCTGTGATCTGTGTGCACACGTTACACGTGTACACAACCACTGACAAGAACATGGAGACACATTTGGAAGCTAGTGTGGACGCCCTGTAATCTGTGCATACACATGTGATACGTGTGTGCACACCCACTGACAAGAACATGGAGACCCATTTGGAAGGCAGTGTGGATGCCCTGTGATCTGTGTGCACACATGTGACACGTGCATGCACATCCACAGACAGAAACACAGAGACACGTTTGGAAGGCAGTGTGGATGCCCTGTGATCTGTGTGTATACGTGACACATGCATGCAAACCCACTGACAAGAACACATAGATGCATTTGGAAGCCAGTGTGGACGCCATGTGATCTGTGCCCACATATCACATGGCCGCTTTGGGATAGGGCCTGTCTGCCCATACTGGCTTCCAAACGCCTCTGTGTGTTCCTGTATGTGGGTGTGCACGTACCTGTCACATGTGTATGCACAGACCACAGGATGTCCACACTGGCTTCCAAATGCGTCTCTGTGTTCCTGTCTGTGAGTTCCAAATGTGTGCACACCTACAGACAGGAACATGGAAACACATTTGGAAGCCAGTGTGGACACCCTGTGATCTGTGCGTACACATGTGACACGTGCATGCACACCCACAGACAGGAACACAGAGACACATTTGGAAGCCAGTGTGGACGCCCTGTGATCTGTGCCCACACACATCACACGTGCATACACACCCACAGACAGGAACACAGAGACACATTTGGAAGCCAGTGTGGATGCCCTGTGATCTGTGTGTACACGTGACACGTGCGTACACACCCACATACAGGAACACAGCCACATTTGGAAGCCAGTGCAGACGCCCTGTGATCTGTGTGTACACATGTGACACGTGCGTGCACACTCACAGACAGGAACACAGAGACGCATTTGGAAGCCAGTGTGGACATCCTGTGGTCTGCGCGTACACATGTGACAGGTACGTGCACGCCCACATACAGGAACACACAGAGGCCTTTGGAAGCCAGCATGGGCAGACAGGCCCTATCCCAAAGCGGCC;SVLEN=1454;SVTYPE=CPX;TOTAL_MAPPINGS=1\r\n```\r\n\r\nSo the strategy taken in this branch is\r\n* for the first two cases, re-interpretation is easy and done in this \"post-processing\" tool, and bare-bone annotated simple variants are given , annotated with `EVENT` that links the simple variants back to the complex variant\r\n* for the last case, \r\n    * re-collect the contigs that induced the CPX call, preprocess its alignment, then send the contig to the current pair-iteration algorithm for re-interpretation, the returned simple variants will be checked for consistency with the CPX variant that was induced by the same contig, and dropped if it is inconsistent (the two types of variants `<DEL>` and `<INV>`, are main concerns as they could easily stem from mis-interpretations of small dispersed duplications); then, \r\n    * the CPX variants who have rejected re-interpreted simple variants will be analyzed one last time, to extract `<DEL>` and `<INV>`; \r\n    * these variants will also be annotated with `EVENT` to link back to the CPX variants.\r\n\r\nBased on manual review, this salvages ~600 variants that would be dropped by evaluation scripts that would simply ignore the CPX variants.\r\n\r\n---\r\nTests will be added if this strategy is given the green light (so no merging yet).","created_at":"2018-03-27T23:38:52Z","updated_at":"2018-05-04T22:40:16Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f1a4462c8244336b63c3a7cd720ca39d6867af9c","assignee":{"login":"mwalker174","id":5686877,"avatar_url":"https://avatars2.githubusercontent.com/u/5686877?v=4","gravatar_id":"","url":"https://api.github.com/users/mwalker174","html_url":"https://github.com/mwalker174","followers_url":"https://api.github.com/users/mwalker174/followers","following_url":"https://api.github.com/users/mwalker174/following{/other_user}","gists_url":"https://api.github.com/users/mwalker174/gists{/gist_id}","starred_url":"https://api.github.com/users/mwalker174/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mwalker174/subscriptions","organizations_url":"https://api.github.com/users/mwalker174/orgs","repos_url":"https://api.github.com/users/mwalker174/repos","events_url":"https://api.github.com/users/mwalker174/events{/privacy}","received_events_url":"https://api.github.com/users/mwalker174/received_events","type":"User","site_admin":false},"assignees":[{"login":"mwalker174","id":5686877,"avatar_url":"https://avatars2.githubusercontent.com/u/5686877?v=4","gravatar_id":"","url":"https://api.github.com/users/mwalker174","html_url":"https://github.com/mwalker174","followers_url":"https://api.github.com/users/mwalker174/followers","following_url":"https://api.github.com/users/mwalker174/following{/other_user}","gists_url":"https://api.github.com/users/mwalker174/gists{/gist_id}","starred_url":"https://api.github.com/users/mwalker174/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mwalker174/subscriptions","organizations_url":"https://api.github.com/users/mwalker174/orgs","repos_url":"https://api.github.com/users/mwalker174/repos","events_url":"https://api.github.com/users/mwalker174/events{/privacy}","received_events_url":"https://api.github.com/users/mwalker174/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":284415544,"url":"https://api.github.com/repos/broadinstitute/gatk/labels/SV","name":"SV","color":"207de5","default":false},{"id":153552586,"url":"https://api.github.com/repos/broadinstitute/gatk/labels/enhancement","name":"enhancement","color":"009800","default":true}],"milestone":null,"commits_url":"https://api.github.com/repos/broadinstitute/gatk/pulls/4602/commits","review_comments_url":"https://api.github.com/repos/broadinstitute/gatk/pulls/4602/comments","review_comment_url":"https://api.github.com/repos/broadinstitute/gatk/pulls/comments{/number}","comments_url":"https://api.github.com/repos/broadinstitute/gatk/issues/4602/comments","statuses_url":"https://api.github.com/repos/broadinstitute/gatk/statuses/05d8bc39074a80e4f5ba00d38279bdaedd9f8b05","head":{"label":"broadinstitute:sh-sv-cpx-improve","ref":"sh-sv-cpx-improve","sha":"05d8bc39074a80e4f5ba00d38279bdaedd9f8b05","user":{"login":"broadinstitute","id":393552,"avatar_url":"https://avatars0.githubusercontent.com/u/393552?v=4","gravatar_id":"","url":"https://api.github.com/users/broadinstitute","html_url":"https://github.com/broadinstitute","followers_url":"https://api.github.com/users/broadinstitute/followers","following_url":"https://api.github.com/users/broadinstitute/following{/other_user}","gists_url":"https://api.github.com/users/broadinstitute/gists{/gist_id}","starred_url":"https://api.github.com/users/broadinstitute/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/broadinstitute/subscriptions","organizations_url":"https://api.github.com/users/broadinstitute/orgs","repos_url":"https://api.github.com/users/broadinstitute/repos","events_url":"https://api.github.com/users/broadinstitute/events{/privacy}","received_events_url":"https://api.github.com/users/broadinstitute/received_events","type":"Organization","site_admin":false},"repo":{"id":27452807,"name":"gatk","full_name":"broadinstitute/gatk","owner":{"login":"broadinstitute","id":393552,"avatar_url":"https://avatars0.githubusercontent.com/u/393552?v=4","gravatar_id":"","url":"https://api.github.com/users/broadinstitute","html_url":"https://github.com/broadinstitute","followers_url":"https://api.github.com/users/broadinstitute/followers","following_url":"https://api.github.com/users/broadinstitute/following{/other_user}","gists_url":"https://api.github.com/users/broadinstitute/gists{/gist_id}","starred_url":"https://api.github.com/users/broadinstitute/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/broadinstitute/subscriptions","organizations_url":"https://api.github.com/users/broadinstitute/orgs","repos_url":"https://api.github.com/users/broadinstitute/repos","events_url":"https://api.github.com/users/broadinstitute/events{/privacy}","received_events_url":"https://api.github.com/users/broadinstitute/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/broadinstitute/gatk","description":"Official code repository for GATK versions 4 and up","fork":false,"url":"https://api.github.com/repos/broadinstitute/gatk","forks_url":"https://api.github.com/repos/broadinstitute/gatk/forks","keys_url":"https://api.github.com/repos/broadinstitute/gatk/keys{/key_id}","collaborators_url":"https://api.github.com/repos/broadinstitute/gatk/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/broadinstitute/gatk/teams","hooks_url":"https://api.github.com/repos/broadinstitute/gatk/hooks","issue_events_url":"https://api.github.com/repos/broadinstitute/gatk/issues/events{/number}","events_url":"https://api.github.com/repos/broadinstitute/gatk/events","assignees_url":"https://api.github.com/repos/broadinstitute/gatk/assignees{/user}","branches_url":"https://api.github.com/repos/broadinstitute/gatk/branches{/branch}","tags_url":"https://api.github.com/repos/broadinstitute/gatk/tags","blobs_url":"https://api.github.com/repos/broadinstitute/gatk/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/broadinstitute/gatk/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/broadinstitute/gatk/git/refs{/sha}","trees_url":"https://api.github.com/repos/broadinstitute/gatk/git/trees{/sha}","statuses_url":"https://api.github.com/repos/broadinstitute/gatk/statuses/{sha}","languages_url":"https://api.github.com/repos/broadinstitute/gatk/languages","stargazers_url":"https://api.github.com/repos/broadinstitute/gatk/stargazers","contributors_url":"https://api.github.com/repos/broadinstitute/gatk/contributors","subscribers_url":"https://api.github.com/repos/broadinstitute/gatk/subscribers","subscription_url":"https://api.github.com/repos/broadinstitute/gatk/subscription","commits_url":"https://api.github.com/repos/broadinstitute/gatk/commits{/sha}","git_commits_url":"https://api.github.com/repos/broadinstitute/gatk/git/commits{/sha}","comments_url":"https://api.github.com/repos/broadinstitute/gatk/comments{/number}","issue_comment_url":"https://api.github.com/repos/broadinstitute/gatk/issues/comments{/number}","contents_url":"https://api.github.com/repos/broadinstitute/gatk/contents/{+path}","compare_url":"https://api.github.com/repos/broadinstitute/gatk/compare/{base}...{head}","merges_url":"https://api.github.com/repos/broadinstitute/gatk/merges","archive_url":"https://api.github.com/repos/broadinstitute/gatk/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/broadinstitute/gatk/downloads","issues_url":"https://api.github.com/repos/broadinstitute/gatk/issues{/number}","pulls_url":"https://api.github.com/repos/broadinstitute/gatk/pulls{/number}","milestones_url":"https://api.github.com/repos/broadinstitute/gatk/milestones{/number}","notifications_url":"https://api.github.com/repos/broadinstitute/gatk/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/broadinstitute/gatk/labels{/name}","releases_url":"https://api.github.com/repos/broadinstitute/gatk/releases{/id}","deployments_url":"https://api.github.com/repos/broadinstitute/gatk/deployments","created_at":"2014-12-02T20:50:36Z","updated_at":"2018-05-04T12:35:41Z","pushed_at":"2018-05-04T22:36:11Z","git_url":"git://github.com/broadinstitute/gatk.git","ssh_url":"git@github.com:broadinstitute/gatk.git","clone_url":"https://github.com/broadinstitute/gatk.git","svn_url":"https://github.com/broadinstitute/gatk","homepage":"https://software.broadinstitute.org/gatk","size":225137,"stargazers_count":388,"watchers_count":388,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":155,"mirror_url":null,"archived":false,"open_issues_count":901,"license":{"key":"bsd-3-clause","name":"BSD 3-Clause \"New\" or \"Revised\" License","spdx_id":"BSD-3-Clause","url":"https://api.github.com/licenses/bsd-3-clause"},"forks":155,"open_issues":901,"watchers":388,"default_branch":"master"}},"base":{"label":"broadinstitute:master","ref":"master","sha":"13b4bf56648043fb3a8f7697cde5e944ba0ef938","user":{"login":"broadinstitute","id":393552,"avatar_url":"https://avatars0.githubusercontent.com/u/393552?v=4","gravatar_id":"","url":"https://api.github.com/users/broadinstitute","html_url":"https://github.com/broadinstitute","followers_url":"https://api.github.com/users/broadinstitute/followers","following_url":"https://api.github.com/users/broadinstitute/following{/other_user}","gists_url":"https://api.github.com/users/broadinstitute/gists{/gist_id}","starred_url":"https://api.github.com/users/broadinstitute/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/broadinstitute/subscriptions","organizations_url":"https://api.github.com/users/broadinstitute/orgs","repos_url":"https://api.github.com/users/broadinstitute/repos","events_url":"https://api.github.com/users/broadinstitute/events{/privacy}","received_events_url":"https://api.github.com/users/broadinstitute/received_events","type":"Organization","site_admin":false},"repo":{"id":27452807,"name":"gatk","full_name":"broadinstitute/gatk","owner":{"login":"broadinstitute","id":393552,"avatar_url":"https://avatars0.githubusercontent.com/u/393552?v=4","gravatar_id":"","url":"https://api.github.com/users/broadinstitute","html_url":"https://github.com/broadinstitute","followers_url":"https://api.github.com/users/broadinstitute/followers","following_url":"https://api.github.com/users/broadinstitute/following{/other_user}","gists_url":"https://api.github.com/users/broadinstitute/gists{/gist_id}","starred_url":"https://api.github.com/users/broadinstitute/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/broadinstitute/subscriptions","organizations_url":"https://api.github.com/users/broadinstitute/orgs","repos_url":"https://api.github.com/users/broadinstitute/repos","events_url":"https://api.github.com/users/broadinstitute/events{/privacy}","received_events_url":"https://api.github.com/users/broadinstitute/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/broadinstitute/gatk","description":"Official code repository for GATK versions 4 and up","fork":false,"url":"https://api.github.com/repos/broadinstitute/gatk","forks_url":"https://api.github.com/repos/broadinstitute/gatk/forks","keys_url":"https://api.github.com/repos/broadinstitute/gatk/keys{/key_id}","collaborators_url":"https://api.github.com/repos/broadinstitute/gatk/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/broadinstitute/gatk/teams","hooks_url":"https://api.github.com/repos/broadinstitute/gatk/hooks","issue_events_url":"https://api.github.com/repos/broadinstitute/gatk/issues/events{/number}","events_url":"https://api.github.com/repos/broadinstitute/gatk/events","assignees_url":"https://api.github.com/repos/broadinstitute/gatk/assignees{/user}","branches_url":"https://api.github.com/repos/broadinstitute/gatk/branches{/branch}","tags_url":"https://api.github.com/repos/broadinstitute/gatk/tags","blobs_url":"https://api.github.com/repos/broadinstitute/gatk/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/broadinstitute/gatk/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/broadinstitute/gatk/git/refs{/sha}","trees_url":"https://api.github.com/repos/broadinstitute/gatk/git/trees{/sha}","statuses_url":"https://api.github.com/repos/broadinstitute/gatk/statuses/{sha}","languages_url":"https://api.github.com/repos/broadinstitute/gatk/languages","stargazers_url":"https://api.github.com/repos/broadinstitute/gatk/stargazers","contributors_url":"https://api.github.com/repos/broadinstitute/gatk/contributors","subscribers_url":"https://api.github.com/repos/broadinstitute/gatk/subscribers","subscription_url":"https://api.github.com/repos/broadinstitute/gatk/subscription","commits_url":"https://api.github.com/repos/broadinstitute/gatk/commits{/sha}","git_commits_url":"https://api.github.com/repos/broadinstitute/gatk/git/commits{/sha}","comments_url":"https://api.github.com/repos/broadinstitute/gatk/comments{/number}","issue_comment_url":"https://api.github.com/repos/broadinstitute/gatk/issues/comments{/number}","contents_url":"https://api.github.com/repos/broadinstitute/gatk/contents/{+path}","compare_url":"https://api.github.com/repos/broadinstitute/gatk/compare/{base}...{head}","merges_url":"https://api.github.com/repos/broadinstitute/gatk/merges","archive_url":"https://api.github.com/repos/broadinstitute/gatk/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/broadinstitute/gatk/downloads","issues_url":"https://api.github.com/repos/broadinstitute/gatk/issues{/number}","pulls_url":"https://api.github.com/repos/broadinstitute/gatk/pulls{/number}","milestones_url":"https://api.github.com/repos/broadinstitute/gatk/milestones{/number}","notifications_url":"https://api.github.com/repos/broadinstitute/gatk/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/broadinstitute/gatk/labels{/name}","releases_url":"https://api.github.com/repos/broadinstitute/gatk/releases{/id}","deployments_url":"https://api.github.com/repos/broadinstitute/gatk/deployments","created_at":"2014-12-02T20:50:36Z","updated_at":"2018-05-04T12:35:41Z","pushed_at":"2018-05-04T22:36:11Z","git_url":"git://github.com/broadinstitute/gatk.git","ssh_url":"git@github.com:broadinstitute/gatk.git","clone_url":"https://github.com/broadinstitute/gatk.git","svn_url":"https://github.com/broadinstitute/gatk","homepage":"https://software.broadinstitute.org/gatk","size":225137,"stargazers_count":388,"watchers_count":388,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":155,"mirror_url":null,"archived":false,"open_issues_count":901,"license":{"key":"bsd-3-clause","name":"BSD 3-Clause \"New\" or \"Revised\" License","spdx_id":"BSD-3-Clause","url":"https://api.github.com/licenses/bsd-3-clause"},"forks":155,"open_issues":901,"watchers":388,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/broadinstitute/gatk/pulls/4602"},"html":{"href":"https://github.com/broadinstitute/gatk/pull/4602"},"issue":{"href":"https://api.github.com/repos/broadinstitute/gatk/issues/4602"},"comments":{"href":"https://api.github.com/repos/broadinstitute/gatk/issues/4602/comments"},"review_comments":{"href":"https://api.github.com/repos/broadinstitute/gatk/pulls/4602/comments"},"review_comment":{"href":"https://api.github.com/repos/broadinstitute/gatk/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/broadinstitute/gatk/pulls/4602/commits"},"statuses":{"href":"https://api.github.com/repos/broadinstitute/gatk/statuses/05d8bc39074a80e4f5ba00d38279bdaedd9f8b05"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"SHuang-Broad"}}