{"action":"created","comment":{"url":"https://api.github.com/repos/broadinstitute/gatk/pulls/comments/149205937","pull_request_review_id":74564719,"id":149205937,"diff_hunk":"@@ -0,0 +1,1899 @@\n+/*\n+* Copyright 2012-2016 Broad Institute, Inc.\n+* \n+* Permission is hereby granted, free of charge, to any person\n+* obtaining a copy of this software and associated documentation\n+* files (the \"Software\"), to deal in the Software without\n+* restriction, including without limitation the rights to use,\n+* copy, modify, merge, publish, distribute, sublicense, and/or sell\n+* copies of the Software, and to permit persons to whom the\n+* Software is furnished to do so, subject to the following\n+* conditions:\n+* \n+* The above copyright notice and this permission notice shall be\n+* included in all copies or substantial portions of the Software.\n+* \n+* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR\n+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n+*/\n+\n+package org.broadinstitute.hellbender.tools.funcotator;\n+\n+/*\n+ * Copyright (c) 2010 The Broad Institute\n+ *\n+ * Permission is hereby granted, free of charge, to any person\n+ * obtaining a copy of this software and associated documentation\n+ * files (the \"Software\"), to deal in the Software without\n+ * restriction, including without limitation the rights to use,\n+ * copy, modify, merge, publish, distribute, sublicense, and/or sell\n+ * copies of the Software, and to permit persons to whom the\n+ * Software is furnished to do so, subject to the following\n+ * conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be\n+ * included in all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n+ * OTHER DEALINGS IN THE SOFTWARE.\n+ */\n+\n+import htsjdk.samtools.reference.ReferenceSequence;\n+import htsjdk.samtools.util.Locatable;\n+import htsjdk.samtools.util.SequenceUtil;\n+import htsjdk.tribble.annotation.Strand;\n+import htsjdk.variant.variantcontext.Allele;\n+import org.apache.log4j.Logger;\n+import org.broadinstitute.hellbender.engine.ReferenceContext;\n+import org.broadinstitute.hellbender.exceptions.GATKException;\n+import org.broadinstitute.hellbender.exceptions.UserException;\n+import org.broadinstitute.hellbender.utils.SimpleInterval;\n+import org.broadinstitute.hellbender.utils.Utils;\n+import org.broadinstitute.hellbender.utils.read.ReadUtils;\n+\n+import java.util.Arrays;\n+import java.util.HashMap;\n+import java.util.List;\n+\n+public class FuncotatorUtils {\n+\n+    private final static Logger logger = Logger.getLogger(FuncotatorUtils.class);\n+\n+    /**\n+     * PRIVATE CONSTRUCTOR\n+     * DO NOT INSTANTIATE THIS CLASS!\n+     */\n+    private FuncotatorUtils() {}\n+\n+    private static final HashMap<String,AminoAcid> tableByCodon = new HashMap<>(AminoAcid.values().length);\n+    private static final HashMap<String,AminoAcid> tableByCode = new HashMap<>(AminoAcid.values().length);\n+    private static final HashMap<String,AminoAcid> tableByLetter = new HashMap<>(AminoAcid.values().length);\n+\n+    /**\n+     * Initialize our hashmaps of lookup tables:\n+     */\n+    static {\n+        for ( final AminoAcid acid : AminoAcid.values() ) {\n+            tableByCode.put(acid.getCode(),acid);\n+            tableByLetter.put(acid.getLetter(), acid);\n+            for ( final String codon : acid.codons ) {\n+                tableByCodon.put(codon,acid);\n+            }\n+        }\n+    }\n+\n+    /**\n+     * Returns the {@link AminoAcid} corresponding to the given three-letter Eukaryotic {@code codon}\n+     * The codons given are expected to be valid for Eukaryotic DNA.\n+     * @param codon The three-letter codon (each letter one of A,T,G,C) representing a Eukaryotic {@link AminoAcid}\n+     * @return The {@link AminoAcid} corresponding to the given {@code codon}.  Returns {@code null} if the given {@code codon} does not code for a Eucaryotic {@link AminoAcid}.\n+     */\n+    public static AminoAcid getEukaryoticAminoAcidByCodon(final String codon) {\n+        if (codon == null) {\n+            return null;\n+        }\n+        return tableByCodon.get(codon.toUpperCase());\n+    }\n+\n+    /**\n+     * Returns the {@link AminoAcid} corresponding to the given three-letter Mitochondrial {@code codon}.\n+     * The codons given are expected to be valid for Mitochondrial DNA.\n+     * @param codon The three-letter codon (each letter one of A,T,G,C) representing a Mitochondrial {@link AminoAcid}\n+     * @return The {@link AminoAcid} corresponding to the given {@code codon}.  Returns {@code null} if the given {@code codon} does not code for a Mitochondrial {@link AminoAcid}.\n+     */\n+    public static AminoAcid getMitochondrialAminoAcidByCodon(final String codon, final boolean isFirst) {\n+\n+        if (codon == null) {\n+            return null;\n+        }\n+\n+        final String upperCodon = codon.toUpperCase();\n+        if ( isFirst && upperCodon.equals(\"ATT\") || upperCodon.equals(\"ATA\") ) {\n+            return AminoAcid.METHIONINE;\n+        } else if ( upperCodon.equals(\"AGA\") || upperCodon.equals(\"AGG\") ) {\n+            return AminoAcid.STOP_CODON;\n+        } else if ( upperCodon.equals(\"TGA\") ) {\n+            return AminoAcid.TRYPTOPHAN;\n+        } else {\n+            return tableByCodon.get(upperCodon);\n+        }\n+    }\n+\n+    /**\n+     * Returns the {@link AminoAcid} corresponding to the given single-letter abbreviation.\n+     * @param letter The one-letter abbreviation representing an {@link AminoAcid}\n+     * @return The {@link AminoAcid} corresponding to the given {@code letter}.  Returns {@code null} if the given {@code letter} does not code for an {@link AminoAcid}.\n+     */\n+    public static AminoAcid getAminoAcidByLetter(final String letter) {\n+        if ( letter == null ) {\n+            return null;\n+        }\n+\n+        return tableByLetter.get(letter);\n+    }\n+\n+    /**\n+     * Returns the {@link AminoAcid} corresponding to the given single-letter abbreviation.\n+     * @param letter The one-letter abbreviation representing an {@link AminoAcid}\n+     * @return The {@link AminoAcid} corresponding to the given {@code letter}.  Returns {@code null} if the given {@code letter} does not code for an {@link AminoAcid}.\n+     */\n+    public static AminoAcid getAminoAcidByLetter(final char letter) {\n+        return tableByLetter.get(String.valueOf(letter));\n+    }\n+\n+    /**\n+     * @return A {@link String} array of long names for all amino acids in {@link AminoAcid}\n+     */\n+    public static String[] getAminoAcidNames() {\n+        final String[] names = new String[AminoAcid.values().length];\n+        for ( final AminoAcid acid : AminoAcid.values() ) {\n+            names[acid.ordinal()] = acid.getName();\n+        }\n+\n+        return names;\n+    }\n+\n+    /**\n+     * @return A {@link String} array of short names / three-letter abbreviations for all amino acids in {@link AminoAcid}\n+     */\n+    public static String[] getAminoAcidCodes() {\n+        final String[] codes = new String[AminoAcid.values().length];\n+        for ( final AminoAcid acid : AminoAcid.values() ) {\n+            codes[acid.ordinal()] = acid.getCode();\n+        }\n+\n+        return codes;\n+    }\n+\n+    /**\n+     * @param position The position (1-based, inclusive) to check for alignment / in-frameness.\n+     * @return {@code true} if the given {@code position} is in-frame; {@code false} otherwise.\n+     */\n+    public static boolean isPositionInFrame( final int position ) {\n+        return (((position - 1) % 3) == 0);\n+    }\n+\n+    /**\n+     * Determines whether the given reference and alternate alleles constitute a frameshift mutation.\n+     * @param reference The reference {@link Allele}.\n+     * @param alternate The alternate / variant {@link Allele}.\n+     * @return {@code true} if replacing the reference with the alternate results in a frameshift.  {@code false} otherwise.\n+     */\n+    public static boolean isFrameshift(final Allele reference, final Allele alternate) {\n+\n+        Utils.nonNull(reference);\n+        Utils.nonNull(alternate);\n+\n+        // We know it's a frameshift if we have a replacement that is not of a\n+        // length evenly divisible by 3 because that's how many bases are read at once:\n+        return ((Math.abs( reference.length() - alternate.length() ) % 3) != 0);\n+    }\n+\n+    /**\n+     * Determines whether the given reference and alternate alleles constitute a frameshift mutation.\n+     * @param reference The {@link String} representation of the reference allele.\n+     * @param alternate The {@link String} representation of the alternate allele.\n+     * @return {@code true} if replacing the reference with the alternate results in a frameshift.  {@code false} otherwise.\n+     */\n+    public static boolean isFrameshift(final String reference, final String alternate) {\n+\n+        Utils.nonNull(reference);\n+        Utils.nonNull(alternate);\n+\n+        // We know it's a frameshift if we have a replacement that is not of a\n+        // length evenly divisible by 3 because that's how many bases are read at once:\n+        return ((Math.abs( reference.length() - alternate.length() ) % 3) != 0);\n+    }\n+\n+    /**\n+     * Determines whether the given reference and alternate alleles constitute an insertion mutation.\n+     * @param reference The reference {@link Allele}.\n+     * @param alternate The alternate / variant {@link Allele}.\n+     * @return {@code true} if replacing the reference with the alternate results in an insertion.  {@code false} otherwise.\n+     */\n+    public static boolean isInsertion(final Allele reference, final Allele alternate) {\n+\n+        Utils.nonNull(reference);\n+        Utils.nonNull(alternate);\n+\n+        // If we have more bases in the alternate, we have an insertion:\n+        return reference.length() < alternate.length();\n+    }\n+\n+    /**\n+     * Determines whether the given reference and alternate alleles constitute an insertion mutation.\n+     * @param reference A {@link String} representing the reference allele.\n+     * @param alternate A {@link String} representing the alternate / variant allele.\n+     * @return {@code true} if replacing the reference with the alternate results in an insertion.  {@code false} otherwise.\n+     */\n+    public static boolean isInsertion(final String reference, final String alternate) {\n+\n+        Utils.nonNull(reference);\n+        Utils.nonNull(alternate);\n+\n+        // If we have more bases in the alternate, we have an insertion:\n+        return reference.length() < alternate.length();\n+    }\n+\n+    /**\n+     * Determines whether the given reference and alternate alleles constitute a deletion mutation.\n+     * @param reference A {@link String} representing the reference allele.\n+     * @param alternate A {@link String} representing the alternate / variant allele.\n+     * @return {@code true} if replacing the reference with the alternate results in a deletion.  {@code false} otherwise.\n+     */\n+    public static boolean isDeletion(final String reference, final String alternate) {\n+\n+        Utils.nonNull(reference);\n+        Utils.nonNull(alternate);\n+\n+        // If we have fewer bases in the alternate, we have a deletion:\n+        return reference.length() > alternate.length();\n+    }\n+\n+    /**\n+     * Determines whether the given reference and alternate alleles constitute a deletion mutation.\n+     * @param reference The reference {@link Allele}.\n+     * @param alternate The alternate / variant {@link Allele}.\n+     * @return {@code true} if replacing the reference with the alternate results in a deletion.  {@code false} otherwise.\n+     */\n+    public static boolean isDeletion(final Allele reference, final Allele alternate) {\n+\n+        Utils.nonNull(reference);\n+        Utils.nonNull(alternate);\n+\n+        // If we have fewer bases in the alternate, we have a deletion:\n+        return reference.length() > alternate.length();\n+    }\n+\n+    /**\n+     * Determines whether the given reference and alternate alleles constitute an insertion or deletion mutation.\n+     * @param reference A {@link String} representing the reference allele.\n+     * @param alternate A {@link String} representing the alternate / variant allele.\n+     * @return {@code true} if replacing the reference with the alternate results in an insertion or deletion.  {@code false} otherwise.\n+     */\n+    public static boolean isIndel(final String reference, final String alternate) {\n+\n+        Utils.nonNull(reference);\n+        Utils.nonNull(alternate);\n+\n+        // If we do not have the same number of bases in the reference and alternate alleles,\n+        // then we have an indel:\n+        return reference.length() != alternate.length();\n+    }\n+\n+    /**\n+     * Determines whether the given reference and alternate alleles constitute an insertion or deletion mutation.\n+     * @param reference The reference {@link Allele}.\n+     * @param alternate The alternate / variant {@link Allele}.\n+     * @return {@code true} if replacing the reference with the alternate results in an insertion or deletion.  {@code false} otherwise.\n+     */\n+    public static boolean isIndel(final Allele reference, final Allele alternate) {\n+\n+        Utils.nonNull(reference);\n+        Utils.nonNull(alternate);\n+\n+        // If we do not have the same number of bases in the reference and alternate alleles,\n+        // then we have an indel:\n+        return reference.length() != alternate.length();\n+    }\n+\n+    /**\n+     * Determines whether the given reference and alternate alleles constitute an Oligo-Nucleotide Polymorphism (ONP).\n+     * For Funcotator purposes, an ONP is a mutation/variant that is a substitution of one or more consecutive bases.\n+     * @param reference The reference {@link Allele}.\n+     * @param alternate The alternate / variant {@link Allele}.\n+     * @return {@code true} if replacing the reference with the alternate results in an ONP.  {@code false} otherwise.\n+     */\n+    public static boolean isOnp(final Allele reference, final Allele alternate) {\n+\n+        Utils.nonNull(reference);\n+        Utils.nonNull(alternate);\n+\n+        // If we have more bases in the alternate, we have an insertion:\n+        return reference.length() == alternate.length();\n+    }\n+\n+    /**\n+     * Determines whether the given reference and alternate alleles constitute an Oligo-Nucleotide Polymorphism (ONP).\n+     * For Funcotator purposes, an ONP is a mutation/variant that is a substitution of one or more consecutive bases.\n+     * @param reference A {@link String} representing the reference allele.\n+     * @param alternate A {@link String} representing the alternate / variant allele.\n+     * @return {@code true} if replacing the reference with the alternate results in an ONP.  {@code false} otherwise.\n+     */\n+    public static boolean isOnp(final String reference, final String alternate) {\n+\n+        Utils.nonNull(reference);\n+        Utils.nonNull(alternate);\n+\n+        // If we have more bases in the alternate, we have an insertion:\n+        return reference.length() == alternate.length();\n+    }\n+\n+//    /**\n+//     * Get the string of alternate bases that are different from the given reference alleles.\n+//     * Assumes there is one contiguous string of changed bases between the two alleles.\n+//     * Assumes that if there is overlap between the alleles, the overlap occurs at either the front or the back of both.\n+//     * @param refAllele Reference {@link Allele}.\n+//     * @param altAllele Alternate {@link Allele}.\n+//     * @param copyRefBasesWhenAltIsPastEnd Will copy the bases from the given {@code refAllele} when the alternate allele has no more bases to copy over.  Used primarily for handling deletions.\n+//     * @return A string containing the bases from the given {@code altAllele} that are different from the reference (in their correct relative order).\n+//     */\n+//    public static String getNonOverlappingAltAlleleBaseString( final Allele refAllele, final Allele altAllele, final boolean copyRefBasesWhenAltIsPastEnd ) {\n+//\n+//        final StringBuilder sb = new StringBuilder();\n+//\n+//        final char noBase = 'x';\n+//        final int maxAlleleLength = Math.max(refAllele.length(), altAllele.length());\n+//        boolean overlapInBack = false;\n+//        boolean havePassedOverlapAlready = false;\n+//\n+//        // Find out where the overlap is:\n+//        if ( refAllele.getBases()[0] != altAllele.getBases()[0] ) {\n+//            overlapInBack = true;\n+//        }\n+//\n+//        // Go through and construct the changed allele string:\n+//        for ( int i = 0; i < maxAlleleLength; ++i ) {\n+//\n+//            // Get our index for front or back differences:\n+//            final int index;\n+//            if ( overlapInBack ) {\n+//                index = (maxAlleleLength - 1) - i;\n+//            }\n+//            else {\n+//                index = i;\n+//            }\n+//\n+//            // Check for differences between the bases:\n+//            char refBase = noBase;\n+//            char altBase = noBase;\n+//\n+//            if ( index < refAllele.length() ) {\n+//                refBase = refAllele.getBaseString().charAt(index);\n+//            }\n+//            if ( index < altAllele.length() ) {\n+//                altBase = altAllele.getBaseString().charAt(index);\n+//            }\n+//\n+//            // Check to see if we're at the end of the differences between the alleles:\n+//            if ( altBase == noBase ) {\n+//                if ( copyRefBasesWhenAltIsPastEnd ) {\n+//                    if ( overlapInBack ) {\n+//                        sb.append( refAllele.getBaseString().substring(0, index + 1) );\n+//                    }\n+//                    else {\n+//                        sb.append( refAllele.getBaseString().substring(index) );\n+//                    }\n+//                }\n+//                break;\n+//            }\n+//            else if ( havePassedOverlapAlready && (altBase == refBase) ) {\n+//                // We can now safely copy the rest of the alt allele into the string buffer and get out of the loop.\n+//                if ( overlapInBack ) {\n+//                    sb.append( altAllele.getBaseString().substring(0, index + 1) );\n+//                }\n+//                else {\n+//                    sb.append( altAllele.getBaseString().substring(index) );\n+//                }\n+//                break;\n+//            }\n+//            else if ( altBase != refBase ) {\n+//                sb.append(altBase);\n+//                havePassedOverlapAlready = true;\n+//            }\n+//        }\n+//\n+//        // We're done.  Bye bye!\n+//        return sb.toString();\n+//    }\n+\n+    /**\n+     * Get the string of alternate bases that are different from the given reference alleles.\n+     * Assumes there is one contiguous string of changed bases between the two alleles.\n+     * Assumes that if there is overlap between the alleles, the overlap occurs at either the front or the back of both.\n+     * @param refAllele Reference {@link Allele}.\n+     * @param altAllele Alternate {@link Allele}.\n+     * @param copyRefBasesWhenAltIsPastEnd Will copy the bases from the given {@code refAllele} when the alternate allele has no more bases to copy over.  Used primarily for handling deletions.\n+     * @return A string containing the bases from the given {@code altAllele} that are different from the reference (in their correct relative order).\n+     */\n+    public static String getNonOverlappingAltAlleleBaseString( final Allele refAllele, final Allele altAllele, final boolean copyRefBasesWhenAltIsPastEnd ) {\n+\n+        final StringBuilder sb = new StringBuilder();\n+\n+        final char noBase = 'x';\n+        final int maxAlleleLength = Math.max(refAllele.length(), altAllele.length());\n+        boolean havePassedOverlapAlready = false;\n+\n+        // Find out where the overlap is:\n+        if ( refAllele.getBases()[0] != altAllele.getBases()[0] ) {\n+            // overlap in back:\n+            for ( int i = 0; i < maxAlleleLength; ++i ) {\n+                // Check for differences between the bases:\n+                char refBase = noBase;\n+                char altBase = noBase;\n+\n+                if ( (refAllele.length() - 1 - i) >= 0 ) {\n+                    refBase = refAllele.getBaseString().charAt(refAllele.length() - 1 - i);\n+                }\n+                if ( (altAllele.length() - 1 - i) >= 0 ) {\n+                    altBase = altAllele.getBaseString().charAt(altAllele.length() - 1 - i);\n+                }\n+\n+                // Check to see if we're at the end of the differences between the alleles:\n+                if ( altBase == noBase ) {\n+                    if ( copyRefBasesWhenAltIsPastEnd ) {\n+                        sb.append( refAllele.getBaseString().substring(0, refAllele.length() - i) );\n+                    }\n+                    break;\n+                }\n+                else if ( havePassedOverlapAlready && (altBase == refBase) ) {\n+                    // We can now safely copy the rest of the alt allele into the string buffer and get out of the loop.\n+                    sb.append( altAllele.getBaseString().substring(0, altAllele.length() - i) );\n+                    break;\n+                }\n+                else if (altBase != refBase) {\n+                    sb.append(altBase);\n+                    havePassedOverlapAlready = true;\n+                }\n+            }\n+\n+            // Now we rotate the string buffer because we've been iterating through it backwards:\n+            sb.reverse();\n+        }\n+        else {\n+            // overlap in front:\n+            for ( int i = 0; i < maxAlleleLength; ++i ) {\n+\n+                // Check for differences between the bases:\n+                char refBase = noBase;\n+                char altBase = noBase;\n+\n+                if ( i < refAllele.length() ) {\n+                    refBase = refAllele.getBaseString().charAt(i);\n+                }\n+                if ( i < altAllele.length() ) {\n+                    altBase = altAllele.getBaseString().charAt(i);\n+                }\n+\n+                // Check to see if we're at the end of the differences between the alleles:\n+                if ( altBase == noBase ) {\n+                    if ( copyRefBasesWhenAltIsPastEnd ) {\n+                        sb.append( refAllele.getBaseString().substring(i) );\n+                    }\n+                    break;\n+                }\n+                else if ( havePassedOverlapAlready && (altBase == refBase) ) {\n+                    // We can now safely copy the rest of the alt allele into the string buffer and get out of the loop.\n+                    sb.append( altAllele.getBaseString().substring(i) );\n+                    break;\n+                }\n+                else if ( altBase != refBase ) {\n+                    sb.append(altBase);\n+                    havePassedOverlapAlready = true;\n+                }\n+            }\n+        }\n+\n+        // We're done.  Bye bye!\n+        return sb.toString();\n+    }\n+\n+    /**\n+     * Determines whether the given reference and alternate alleles constitute a frameshift mutation.\n+     * @param startPos Genomic start position (1-based, inclusive) of the variant.\n+     * @param refEnd Genomic end position (1-based, inclusive) of the reference allele.\n+     * @param altEnd Genomic end position (1-based, inclusive) of the alternate allele.\n+     * @return {@code true} if replacing the reference with the alternate results in a frameshift.  {@code false} otherwise.\n+     */\n+    public static boolean isFrameshift(final int startPos, final int refEnd, final int altEnd) {\n+\n+        final int refLength = refEnd - startPos + 1;\n+        final int altLength = altEnd - startPos + 1;\n+\n+        // We know it's a frameshift if we have a replacement that is not of a\n+        // length evenly divisible by 3 because that's how many bases are read at once:\n+        return ((Math.abs( refLength - altLength ) % 3) != 0);\n+    }\n+\n+    /**\n+     * Gets the position describing where the given allele and variant lie inside the given transcript using transcript-based coordinates.\n+     * The index will be calculated even if the given variant ends outside the bounds of the given transcript.\n+     * Assumes {@code transcript} is a sorted list (in exon number order).\n+     * @param variant A {@link Locatable} to locate inside the given {@code transcript}.\n+     * @param transcript A sorted {@link List} of {@link Locatable} (in exon number order) that describe the transcript to use for locating the given {@code allele}.\n+     * @param strand The strand on which the transcript is read.\n+     * @return The position (1-based, inclusive) describing where the given {@code allele} lies in the given {@code transcript}.  If the variant is not in the given {@code transcript}, then this returns -1.\n+     */\n+    public static int getStartPositionInTranscript( final Locatable variant,\n+                                                    final List<? extends Locatable> transcript,\n+                                                    final Strand strand) {\n+        Utils.nonNull(variant);\n+        Utils.nonNull(transcript);\n+        assertValidStrand( strand );\n+\n+        int position = 1;\n+\n+        boolean foundPosition = false;\n+\n+        final SimpleInterval variantStartLocus;\n+        if ( strand == Strand.POSITIVE ) {\n+            variantStartLocus = new SimpleInterval(variant.getContig(), variant.getStart(), variant.getStart());\n+        }\n+        else {\n+            variantStartLocus = new SimpleInterval(variant.getContig(), variant.getEnd(), variant.getEnd());\n+        }\n+\n+        for (final Locatable exon : transcript) {\n+            if (!exon.getContig().equals(variantStartLocus.getContig())) {\n+                throw new GATKException(\"Variant and transcript contigs are not equal: \"\n+                        + variantStartLocus.getContig() + \" != \" + exon.getContig());\n+            }\n+\n+            if (new SimpleInterval(exon).contains(variantStartLocus)) {\n+                if ( strand == Strand.POSITIVE ) {\n+                    position += variantStartLocus.getStart() - exon.getStart();\n+                }\n+                else {\n+                    position += exon.getEnd() - variantStartLocus.getStart();\n+                }\n+                foundPosition = true;\n+                break;\n+            } else {\n+                // Add 1 because of inclusive positions / indexing starting at 1\n+                position += exon.getEnd() - exon.getStart() + 1;\n+            }\n+        }\n+\n+        if ( foundPosition ) {\n+            return position;\n+        }\n+\n+        return -1;\n+    }\n+\n+    /**\n+     * Get the sequence-aligned end position for the given allele end position.\n+     * @param alleleEndPosition The genome end position (1-based, inclusive) for an allele.\n+     * @return An aligned end position (1-based, inclusive) for the given allele end position.\n+     */\n+    public static int getAlignedEndPosition(final int alleleEndPosition) {\n+        return (int)(Math.ceil(alleleEndPosition / 3.0) * 3);\n+    }\n+\n+    /**\n+     * Gets the sequence aligned position (1-based, inclusive) for the given coding sequence position.\n+     * This will produce the next lowest position evenly divisible by 3, such that a codon starting at this returned\n+     * position would include the given position.\n+     * @param position A sequence starting coordinate for which to produce an coding-aligned position.\n+     * @return A coding-aligned position (1-based, inclusive) corresponding to the given {@code position}.\n+     */\n+    public static int getAlignedPosition(final int position) {\n+        return position - ((position - 1) % 3);\n+    }\n+\n+    /**\n+     * Calculates whether the given {@code startPosition} (1-based, inclusive) is in frame relative to the end of the region.\n+     * @param startPosition The position (1-based, inclusive) relative to the start of a region to check for frame alignment.\n+     * @param regionLength The length of the region containing {@code startPosition}.\n+     * @return {@code true} if the given {@code startPosition} is in frame relative to the given {@code regionLength} ; {@code false} otherwise.\n+     */\n+    public static boolean isInFrameWithEndOfRegion(final int startPosition, final int regionLength) {\n+        return (((regionLength - startPosition + 1) % 3) == 0);\n+    }\n+\n+    /**\n+     * Creates the string representation of the codon change for the given {@link SequenceComparison}.\n+     * @param seqComp {@link SequenceComparison} representing the alternate and reference alleles for a DNA sequence.\n+     * @return A {@link String} representing the codon change for the given {@link SequenceComparison}.\n+     */\n+    public static String getCodonChangeString(final SequenceComparison seqComp) {\n+\n+        Utils.nonNull(seqComp);\n+        Utils.nonNull(seqComp.getAlignedCodingSequenceAlleleStart());\n+        Utils.nonNull(seqComp.getAlignedReferenceAlleleStop());\n+        Utils.nonNull(seqComp.getAlignedCodingSequenceReferenceAllele());\n+        Utils.nonNull(seqComp.getAlternateAllele());\n+        Utils.nonNull(seqComp.getAlignedCodingSequenceAlternateAllele());\n+        Utils.nonNull(seqComp.getCodingSequenceAlleleStart());\n+\n+        // Used for insertions:\n+        Utils.nonNull(seqComp.getReferenceCodingSequence());\n+        assertValidStrand( seqComp.getStrand() );\n+\n+        // Make some local names so that things are easier to read:\n+        final String alignedRefAllele = seqComp.getAlignedCodingSequenceReferenceAllele();\n+        final String alignedAltAllele = seqComp.getAlignedCodingSequenceAlternateAllele();\n+        \n+        final StringBuilder ref = new StringBuilder();\n+        final StringBuilder alt = new StringBuilder();\n+\n+        // Handle the ONP case:\n+        if ( isOnp(alignedRefAllele, alignedAltAllele) ) {\n+\n+            // Capitalize the right parts of each string if they're of equal length:\n+            for (int i = 0; i < alignedRefAllele.length(); ++i) {\n+                if (alignedRefAllele.charAt(i) != alignedAltAllele.charAt(i)) {\n+                    ref.append(Character.toUpperCase(alignedRefAllele.charAt(i)));\n+                    alt.append(Character.toUpperCase(alignedAltAllele.charAt(i)));\n+                } else {\n+                    final char c = Character.toLowerCase(alignedRefAllele.charAt(i));\n+                    ref.append(c);\n+                    alt.append(c);\n+                }\n+            }\n+\n+            // Construct and return the string:\n+            if (seqComp.getAlignedCodingSequenceAlleleStart().equals(seqComp.getAlignedReferenceAlleleStop())) {\n+                return \"c.(\" + seqComp.getAlignedCodingSequenceAlleleStart() + \")\" +\n+                        ref.toString() + \">\" + alt.toString();\n+            } else {\n+                return \"c.(\" + seqComp.getAlignedCodingSequenceAlleleStart() + \"-\" +\n+                        seqComp.getAlignedReferenceAlleleStop() + \")\" +\n+                        ref.toString() + \">\" + alt.toString();\n+            }\n+        }\n+        // Handle the insertion case:\n+        else if ( isInsertion(alignedRefAllele, alignedAltAllele) ) {\n+\n+            final String nextRefCodon = getNextReferenceCodon(seqComp.getReferenceCodingSequence(), seqComp.getAlignedCodingSequenceAlleleStart(), seqComp.getAlignedReferenceAlleleStop(), seqComp.getStrand());\n+\n+            // Check for frame shift syntax first:\n+            if ( isFrameshift(alignedRefAllele, alignedAltAllele) ) {\n+\n+                // If the variant position is in frame, then we have to use the next codon, because it will be the first\n+                // codon that is affected.\n+                // We add 1 because of the convention that the variant occurs just after the base specified for insertions.\n+                // TODO: This is really bad - we are tying our output to a specific input format.  FIX IT.\n+                if ( isPositionInFrame(seqComp.getCodingSequenceAlleleStart() + 1) ) {\n+                    return \"c.(\" + (seqComp.getAlignedCodingSequenceAlleleStart() + 3) + \"-\" +\n+                            (seqComp.getAlignedReferenceAlleleStop() + 3) + \")\" +\n+                            nextRefCodon.toLowerCase() + \"fs\";\n+                }\n+                else {\n+                    // Out of frame insertions affect the current codon, so the current position should be\n+                    // used.\n+                    return \"c.(\" + seqComp.getAlignedCodingSequenceAlleleStart() + \"-\" +\n+                            seqComp.getAlignedReferenceAlleleStop() + \")\" +\n+                            alignedRefAllele.toLowerCase() + \"fs\";\n+                }\n+            }\n+            else {\n+\n+                // If the variant position is in frame, then we have to use the next codon, because it will be the first\n+                // codon that is affected.\n+                // We add 1 because of the convention that the variant occurs just after the base specified for insertions.\n+                // TODO: This is really bad - we are tying our output to a specific input format.  FIX IT.\n+                if (isPositionInFrame(seqComp.getCodingSequenceAlleleStart() + 1)) {\n+\n+                    // For insertions we need to grab the codon just following the end of the insertion reference and place\n+                    // it on the end of our reference before we render it.  We must also ignore the first codon because of\n+                    // the leading extra base in the VCF file.\n+                    // TODO: This is really bad - we are tying our output to a specific input format.  FIX IT.\n+\n+                    // Create a new reference allele by removing the first codon\n+                    // (because of the added leading base for insertions)\n+                    // and appending the next codon to it:\n+                    final String newAlignedRefAllele = alignedRefAllele.substring(3) + nextRefCodon;\n+\n+                    // Create a new alternate allele by removing the first codon\n+                    // (because of the added leading base for insertions):\n+                    final String newAlignedAltAllele = alignedAltAllele.substring(3);\n+\n+                    // Create a new start and stop position because of the added leading base:\n+                    final int newStartPosition = seqComp.getAlignedCodingSequenceAlleleStart() + 3;\n+                    final int newEndPosition = seqComp.getAlignedReferenceAlleleStop() + 3;\n+\n+                    // Capitalize for insertion:\n+\n+                    // Insertions alternate alleles have ref first, then the extra bases,\n+                    // so we capitalize only the extra bases.\n+\n+                    // The next codon is really our new ref allele.\n+                    // And the ref will always be all lower case:\n+                    ref.append(nextRefCodon.toLowerCase());\n+\n+                    // Add alleles to our stringstreams:\n+                    // Alt allele chars will be upper case:\n+                    alt.append(newAlignedAltAllele.toUpperCase());\n+\n+                    // Ref allele will be lower case:\n+                    alt.append(newAlignedRefAllele.toLowerCase());\n+\n+                    // Here we add 3 to the start and stop positions because of the\n+                    return \"c.(\" + newStartPosition + \"-\" + newEndPosition + \")\" +\n+                            ref.toString() + \">\" + alt.toString();\n+                }\n+                else {\n+                    // For positions that are not in frame, we can just keep the ref and alt alleles since those will\n+                    // correctly reflect the change:\n+\n+                    // Capitalize the insertion correctly:\n+                    int i = 0;\n+                    int j = 0;\n+                    while ( alt.length() != alignedAltAllele.length() ) {\n+                        if ( i == alignedRefAllele.length() ) {\n+                            alt.append( alignedRefAllele.substring(i).toLowerCase() );\n+                        }\n+                        else {\n+                            if ( alignedRefAllele.charAt(i) != alignedAltAllele.charAt(j) ) {\n+                                // Once we get 1 difference, we append the rest of the characters here:\n+\n+                                // Get the rest of the characters from the alternate allele into the buffer:\n+                                for ( int k = 0 ; k < seqComp.getAlternateAllele().length() - 1 ; ++k){\n+                                    alt.append(Character.toUpperCase(alignedAltAllele.charAt(j++)));\n+                                }\n+                            }\n+                            else {\n+                                alt.append( Character.toLowerCase(alignedAltAllele.charAt(j)) );\n+                                ++i;\n+                                ++j;\n+                            }\n+                        }\n+                    }\n+\n+                    return \"c.(\" + seqComp.getAlignedCodingSequenceAlleleStart() + \"-\" + seqComp.getAlignedReferenceAlleleStop() + \")\" +\n+                            alignedRefAllele.toLowerCase() + \">\" + alt.toString();\n+                }\n+\n+            }\n+        }\n+        // Handle the deletion case:\n+        else {\n+            // Check for frame shift syntax and return our string.\n+            // NOTE: We know that because of the way deletions are created\n+            // (i.e. a base is added to the beginning of the string), we can ignore the first codon (3 bases) of the\n+            // reference:\n+            String decorator = \"del\";\n+            if ( isFrameshift(alignedRefAllele, alignedAltAllele) ) {\n+                decorator = \"fs\";\n+            }\n+\n+            return \"c.(\" + (seqComp.getAlignedCodingSequenceAlleleStart() + 3) + \"-\" +\n+                    seqComp.getAlignedReferenceAlleleStop() + \")\" +\n+                    alignedRefAllele.substring(3).toLowerCase() + decorator;\n+        }\n+    }\n+\n+    /**\n+     * Gets the next complete in-frame codon from the given {@link ReferenceSequence} according to the current codon position and strand.\n+     * @param referenceSequence The {@link ReferenceSequence} for the current codon.\n+     * @param currentAlignedCodingSequenceAlleleStart The starting position (1-based, inclusive) of the current codon.\n+     * @param currentAlignedCodingSequenceAlleleStop The ending position (1-based, inclusive) of the current codon.\n+     * @param strand The {@link Strand} on which the current codon resides.\n+     * @return The next codon in frame with the current codon as specified by the given current codon positions.\n+     */\n+    private static String getNextReferenceCodon(final ReferenceSequence referenceSequence,\n+                                                final int currentAlignedCodingSequenceAlleleStart,\n+                                                final int currentAlignedCodingSequenceAlleleStop,\n+                                                final Strand strand) {\n+\n+        Utils.nonNull( referenceSequence );\n+        assertValidStrand(strand);\n+\n+        final String nextRefCodon;\n+        if ( strand == Strand.POSITIVE ) {\n+            nextRefCodon = referenceSequence.getBaseString().substring(currentAlignedCodingSequenceAlleleStop, currentAlignedCodingSequenceAlleleStop + 3 );\n+        }\n+        else {\n+            nextRefCodon = ReadUtils.getBasesReverseComplement(\n+                    referenceSequence.getBaseString().substring(currentAlignedCodingSequenceAlleleStart - 3, currentAlignedCodingSequenceAlleleStart ).getBytes()\n+            );\n+        }\n+        return nextRefCodon;\n+    }\n+\n+    /**\n+     * Gets a codon change string for a splice site.\n+     * Assumes the variant and exon referenced in the params are on the same contig.\n+     * @param variantStart Start position (1-based, inclusive) of the variant.\n+     * @param exonNumber Number of the exon in the transcript.\n+     * @param exonStart Start position (1-based, inclusive) of the exon.\n+     * @param exonEnd End position (1-based, inclusive) of the exon.\n+     * @param strand The {@link Strand} on which the variant and exon are read.\n+     * @return A {@link String} representing the codon change for the splice site represented by the given parameters.\n+     */\n+    public static String createSpliceSiteCodonChange(final int variantStart,\n+                                                     final int exonNumber,\n+                                                     final int exonStart,\n+                                                     final int exonEnd,\n+                                                     final Strand strand) {\n+        return createSpliceSiteCodonChange(variantStart, exonNumber, exonStart, exonEnd, strand, 0);\n+    }\n+\n+    /**\n+     * Gets a codon change string for a splice site.\n+     * Assumes the variant and exon referenced in the params are on the same contig.\n+     * @param variantStart Start position (1-based, inclusive) of the variant.\n+     * @param exonNumber Number of the exon in the transcript.\n+     * @param exonStart Start position (1-based, inclusive) of the exon.\n+     * @param exonEnd End position (1-based, inclusive) of the exon.\n+     * @param strand The {@link Strand} on which the variant and exon are read.\n+     * @param offsetIndelAdjustment An adjustment added to account for bases lost / gained in an Indel event.\n+     * @return A {@link String} representing the codon change for the splice site represented by the given parameters.\n+     */\n+    public static String createSpliceSiteCodonChange(final int variantStart,\n+                                                     final int exonNumber,\n+                                                     final int exonStart,\n+                                                     final int exonEnd,\n+                                                     final Strand strand,\n+                                                     final int offsetIndelAdjustment) {\n+        assertValidStrand( strand );\n+\n+        char sign = '-';\n+        int offset = exonStart - variantStart;\n+        if ( Math.abs(offset) > Math.abs(variantStart - exonEnd)) {\n+            offset = variantStart - exonEnd;\n+            sign = '+';\n+        }\n+        offset = Math.abs(offset);\n+\n+        if (strand == Strand.NEGATIVE) {\n+            if ( sign == '+' ) {\n+                sign = '-';\n+            }\n+            else {\n+                sign = '+';\n+            }\n+        }\n+\n+        // Add our indel adjustment here:\n+        if ( sign == '+' ) {\n+            offset += offsetIndelAdjustment;\n+        }\n+        else {\n+            offset -= offsetIndelAdjustment;\n+        }\n+\n+        // Make sure we correctly adjust for the zero crossing:\n+        if ( offset < 0 ) {\n+            offset *= -1;\n+            if ( sign == '+') {\n+                sign = '-';\n+            }\n+            else {\n+                sign = '+';\n+            }\n+        }\n+\n+        return \"c.e\" + exonNumber + sign + offset;\n+    }\n+\n+    /**\n+     * Creates the string representation of the codon change for the given {@link SequenceComparison}.\n+     * @param seqComp {@link SequenceComparison} representing the alternate and reference alleles for a DNA sequence.\n+     * @return A {@link String} representing the codon change for the given {@link SequenceComparison}.\n+     */\n+    public static String getProteinChangeString(final SequenceComparison seqComp) {\n+\n+        Utils.nonNull(seqComp);\n+        Utils.nonNull(seqComp.getReferenceAminoAcidSequence());\n+        Utils.nonNull(seqComp.getProteinChangeStartPosition());\n+        Utils.nonNull(seqComp.getProteinChangeEndPosition());\n+        Utils.nonNull(seqComp.getAlternateAminoAcidSequence());\n+        Utils.nonNull(seqComp.getReferenceAllele());\n+        Utils.nonNull(seqComp.getAlternateAllele());\n+\n+        if ( seqComp.getReferenceAllele().length() == 0 ) {\n+            throw new UserException(\"Reference allele cannot be empty.\");\n+        }\n+        if ( seqComp.getAlternateAllele().length() == 0 ) {\n+            throw new UserException(\"Alternate allele cannot be empty.\");\n+        }\n+\n+        String refAaSeq = seqComp.getReferenceAminoAcidSequence();\n+        String altAaSeq = seqComp.getAlternateAminoAcidSequence();\n+        Integer protChangeStartPos = seqComp.getProteinChangeStartPosition();\n+        Integer protChangeEndPos = seqComp.getProteinChangeEndPosition();\n+\n+        // Check for the ONP case:\n+        if ( isOnp(seqComp.getReferenceAllele(), seqComp.getAlternateAllele()) ) {\n+\n+            // We should go through our strings and make sure we only render the parts of the protein that have actually\n+            // changed.  This means that we keep track of the `same` and `different` parts of the sequences.\n+            // `Same` parts at the front & back of the string are ignored.\n+            // We keep them in the middle.\n+            // Then we recompute the position in which the protein has changed.\n+\n+            boolean foundStartDiff = false;\n+            boolean foundEndDiff = false;\n+\n+            int startingDifference = 0;\n+            int endingDifference = 0;\n+\n+            for ( int i = 0 ; i < refAaSeq.length() ; ++i ) {\n+                final int rIndx = refAaSeq.length() - 1 - i;\n+                if ( (!foundStartDiff) && (refAaSeq.charAt(i) != altAaSeq.charAt(i)) ) {\n+                    startingDifference = i;\n+                    foundStartDiff = true;\n+                }\n+                if ( (!foundEndDiff) && (refAaSeq.charAt(rIndx) != altAaSeq.charAt(rIndx)) ) {\n+                    endingDifference = i;\n+                    foundEndDiff = true;\n+                }\n+            }\n+\n+            // Set the new start / stop positions:\n+            protChangeStartPos += startingDifference;\n+            protChangeEndPos -= endingDifference;\n+\n+            // Set the new ref and alt amino acid sequences:\n+            refAaSeq = refAaSeq.substring(startingDifference, refAaSeq.length() - endingDifference);\n+            altAaSeq = altAaSeq.substring(startingDifference, altAaSeq.length() - endingDifference);\n+\n+            if (protChangeStartPos.equals(protChangeEndPos)) {\n+                return \"p.\" + refAaSeq + protChangeStartPos +\n+                        altAaSeq;\n+            } else {\n+                return \"p.\" + protChangeStartPos\n+                        + \"_\" + protChangeEndPos + refAaSeq + '>' + altAaSeq;\n+            }\n+        }\n+        // Check for the Insertion case:\n+        else if ( isInsertion(seqComp.getReferenceAllele(), seqComp.getAlternateAllele()) ) {\n+\n+            Utils.nonNull(seqComp.getCodingSequenceAlleleStart());\n+            Utils.nonNull(seqComp.getReferenceCodingSequence());\n+            assertValidStrand(seqComp.getStrand());\n+\n+            // Because we have to deal with the codon after the insertion, we need to know what that next codon is:\n+            final String nextRefCodon = getNextReferenceCodon(seqComp.getReferenceCodingSequence(), seqComp.getAlignedCodingSequenceAlleleStart(), seqComp.getAlignedReferenceAlleleStop(), seqComp.getStrand());\n+\n+            // We must also know the Amino Acid sequence for it:\n+            final String nextRefAaSeq = createAminoAcidSequence(nextRefCodon);\n+\n+            if ( isFrameshift(seqComp.getReferenceAllele(), seqComp.getAlternateAllele()) ) {\n+                // If the variant position is in frame, then we have to use the next amino acid, because it will be the first\n+                // amino acid that is affected.\n+                // We add 1 because of the convention that the variant occurs just after the base specified for insertions.\n+                // TODO: This is really bad - we are tying our output to a specific input format.  FIX IT.\n+                if ( isPositionInFrame(seqComp.getCodingSequenceAlleleStart() + 1) ) {\n+                    return \"p.\" + nextRefAaSeq + (protChangeStartPos + 1) + \"fs\";\n+                }\n+                else {\n+                    // Out of frame insertions affect the current protein position, so the current position should be\n+                    // used.\n+                    return \"p.\" + refAaSeq + protChangeStartPos + \"fs\";\n+                }\n+            }\n+            else {\n+\n+                // If the variant position is in frame, then we have to use the next amino acid, because it will be the first\n+                // amino acid that is affected.\n+                // We add 1 because of the convention that the variant occurs just after the base specified for insertions.\n+                // TODO: This is really bad - we are tying our output to a specific input format.  FIX IT.\n+                if ( isPositionInFrame(seqComp.getCodingSequenceAlleleStart() + 1) ) {\n+                    // NOTE: We know that because of the way insertions are created\n+                    // (i.e. a base is added to the beginning of the string), we can ignore the first amino acid (3 bases) of the\n+                    // amino acid sequence:\n+                    return \"p.\" + protChangeStartPos + \"_\" + (protChangeStartPos+1) + \"ins\" + altAaSeq.substring(1);\n+                }\n+                else {\n+\n+                    // For this case we know that protChangeStartPos is the position of the current amino acid in which\n+                    // the insertion took place.\n+                    // We also know that refAaSeq is the amino acid at protChangeStartPos.\n+\n+\n+                    // To get the protein change itself, we need to iterate through the ref and alt amino acid sequences\n+                    // and determine which are overlaps (starting from the back).  Any overlaps are discarded until\n+                    // differences are found.\n+                    // Then the rest of the sequence is said to be new.\n+                    final StringBuilder altAminoAcidBuilder = new StringBuilder();\n+                    int i = refAaSeq.length()-1;\n+                    int j = altAaSeq.length()-1;\n+                    int skipped = 0;\n+                    final int expectedLength = ((seqComp.getAlternateAllele().length()-1) / 3);\n+                    while ( altAminoAcidBuilder.length() < expectedLength ) {\n+\n+                        if ( (i < 0) || (refAaSeq.charAt(i) != altAaSeq.charAt(j)) ) {\n+                            // Get all remaining amino acids into altAminoAcidBuilder:\n+                            while ((j >= 0) && (altAminoAcidBuilder.length() != expectedLength)) {\n+                                altAminoAcidBuilder.append(altAaSeq.charAt(j--));\n+                            }\n+                        } else {\n+                            --i;\n+                            --j;\n+                            ++skipped;\n+                        }\n+                    }\n+                    altAminoAcidBuilder.reverse();\n+\n+                    // NOTE: We know that because of the way insertions are created\n+                    // (i.e. a base is added to the beginning of the string), we can ignore the first amino acid (3 bases) of the\n+                    // amino acid sequence:\n+                    return \"p.\" + (protChangeStartPos - skipped) + \"_\" + (protChangeStartPos - skipped + 1) + \"ins\" + altAminoAcidBuilder.toString();\n+                }\n+            }\n+        }\n+        // Must be a deletion:\n+        else {\n+\n+            // NOTE: We know that because of the way deletions are created\n+            // (i.e. a base is added to the beginning of the string), we can ignore the first amino acid (3 bases) of the\n+            // reference:\n+            String decorator = \"del\";\n+            if ( isFrameshift(seqComp.getReferenceAllele(), seqComp.getAlternateAllele()) ) {\n+                decorator = \"fs\";\n+            }\n+            return \"p.\" + refAaSeq.substring(1) + (protChangeStartPos + 1) + decorator;\n+        }\n+    }\n+\n+    /**\n+     * Get the coding sequence change string from the given {@link SequenceComparison}\n+     * This method is assumed to be called only when the variant occurs in a coding region of the genome.\n+     * @param seqComp {@link SequenceComparison} from which to construct the coding sequence change string.\n+     * @return A {@link String} representing the coding sequence change between the ref and alt alleles in {@code seqComp}.\n+     */\n+    public static String getCodingSequenceChangeString( final SequenceComparison seqComp ) {\n+\n+        Utils.nonNull(seqComp);\n+        Utils.nonNull(seqComp.getCodingSequenceAlleleStart());\n+        Utils.nonNull(seqComp.getReferenceAllele());\n+        Utils.nonNull(seqComp.getAlternateAllele());\n+\n+        // Check for ONP:\n+        if ( isOnp(seqComp.getReferenceAllele(), seqComp.getAlternateAllele()) ) {\n+            if (seqComp.getAlternateAllele().length() > 1) {\n+                return \"c.\" + seqComp.getCodingSequenceAlleleStart() + \"_\" + (seqComp.getCodingSequenceAlleleStart() + seqComp.getReferenceAllele().length() - 1) +\n+                        seqComp.getReferenceAllele() + \">\" + seqComp.getAlternateAllele();\n+            } else {\n+                return \"c.\" + seqComp.getCodingSequenceAlleleStart() +\n+                        seqComp.getReferenceAllele() + \">\" + seqComp.getAlternateAllele();\n+            }\n+        }\n+        // Check for Insertion:\n+        else if ( isInsertion(seqComp.getReferenceAllele(), seqComp.getAlternateAllele()) ) {\n+            return \"c.\" + seqComp.getCodingSequenceAlleleStart() + \"_\" + (seqComp.getCodingSequenceAlleleStart() + 1) +\n+                    \"ins\" + seqComp.getAlternateAllele().substring(seqComp.getReferenceAllele().length()).toUpperCase();\n+        }\n+        // Must be a Deletion:\n+        else {\n+\n+            int start = seqComp.getCodingSequenceAlleleStart() + seqComp.getAlternateAllele().length();\n+            int end = seqComp.getCodingSequenceAlleleStart() + seqComp.getReferenceAllele().length() - 1;\n+\n+            // If we have exon information, and we SHOULD, we use it to trim the start/stop coordinates\n+            // of the cDNA string to the extants of the coding region:\n+            if ( (seqComp.getExonStartPosition() != null) && (seqComp.getExonEndPosition() != null) ) {\n+                final int cdsExonStart = seqComp.getCodingSequenceAlleleStart() - (seqComp.getAlleleStart() - seqComp.getExonStartPosition());\n+                final int cdsExonEnd   = cdsExonStart + (seqComp.getExonEndPosition() - seqComp.getExonStartPosition());\n+\n+                if ( start < cdsExonStart ) {\n+                    start = cdsExonStart;\n+                }\n+                if ( end > cdsExonEnd ) {\n+                    end = cdsExonEnd;\n+                }\n+            }\n+\n+            return \"c.\" + start + \"_\" + end + \"del\" +\n+                    seqComp.getReferenceAllele().substring(seqComp.getAlternateAllele().length()).toUpperCase();\n+        }\n+    }\n+\n+    /**\n+     * Get the coding sequence change string from the given {@link SequenceComparison}\n+     * @param transcriptPosition The position in the transcript of the given splice site variant.\n+     * @return A {@link String} representing the coding sequence change between the ref and alt alleles in {@code seqComp}.\n+     */\n+    public static String getCodingSequenceChangeStringForExonSpliceSite( final int transcriptPosition ) {\n+\n+        if ( transcriptPosition < 1 ) {\n+            throw new GATKException(\"Encountered transcript position less than 1 (transcript positions are 1-based): \" + transcriptPosition + \" < \" + 1);\n+        }\n+\n+        return \"c.\" + transcriptPosition + \"_splice\";\n+    }\n+\n+    /**\n+     * Creates an amino acid sequence from a given coding sequence.\n+     * If the coding sequence is not evenly divisible by 3, the remainder bases will not be included in the coding sequence.\n+     * @param codingSequence The coding sequence from which to create an amino acid sequence.\n+     * @return A {@link String} containing a sequence of single-letter amino acids.\n+     */\n+    public static String createAminoAcidSequence(final String codingSequence) {\n+\n+        Utils.nonNull(codingSequence);\n+\n+        final StringBuilder sb = new StringBuilder();\n+\n+        // Ensure that we don't have remainder bases:\n+        int maxIndex = codingSequence.length();\n+        if ( maxIndex % 3 != 0 ) {\n+            maxIndex = (int)Math.floor(maxIndex / 3) * 3;\n+            logger.warn(\"createAminoAcidSequence given a coding sequence of length not divisible by 3.  Dropping bases from the end: \" + (codingSequence.length() % 3));\n+        }\n+\n+        for ( int i = 0; i < maxIndex; i += 3 ) {\n+            final AminoAcid aa = getEukaryoticAminoAcidByCodon(codingSequence.substring(i, i+3));\n+            if ( aa == null ) {\n+                sb.append(AminoAcid.NONSENSE.getLetter());\n+            }\n+            else {\n+                sb.append(aa.getLetter());\n+            }\n+        }\n+        return sb.toString();\n+    }\n+\n+    /**\n+     * Get the coding sequence-aligned allele based on stop and start position.\n+     * @param codingSequence Coding sequence from which the allele should be derived.\n+     * @param alignedAlleleStart Start position of the allele (1-indexed, inclusive).\n+     * @param alignedAlleleStop Stop position of the allele (1-indexed, inclusive).\n+     * @param strand {@link Strand} on which the allele is coded.\n+     * @return The {@link String} representation of the allele.\n+     */\n+    private static String getAlignedAlleleSequence(final String codingSequence,\n+                                                   final Integer alignedAlleleStart,","path":"src/main/java/org/broadinstitute/hellbender/tools/funcotator/FuncotatorUtils.java","position":1161,"original_position":1161,"commit_id":"b7be62a08a937a0104fa970f2f86df39670785f6","original_commit_id":"b7be62a08a937a0104fa970f2f86df39670785f6","user":{"login":"jonn-smith","id":11667487,"avatar_url":"https://avatars1.githubusercontent.com/u/11667487?v=4","gravatar_id":"","url":"https://api.github.com/users/jonn-smith","html_url":"https://github.com/jonn-smith","followers_url":"https://api.github.com/users/jonn-smith/followers","following_url":"https://api.github.com/users/jonn-smith/following{/other_user}","gists_url":"https://api.github.com/users/jonn-smith/gists{/gist_id}","starred_url":"https://api.github.com/users/jonn-smith/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonn-smith/subscriptions","organizations_url":"https://api.github.com/users/jonn-smith/orgs","repos_url":"https://api.github.com/users/jonn-smith/repos","events_url":"https://api.github.com/users/jonn-smith/events{/privacy}","received_events_url":"https://api.github.com/users/jonn-smith/received_events","type":"User","site_admin":false},"body":"It's a hold-over from the definitions in `SequenceComparison` - I wanted a uniform way to check that something was already assigned.  Using the class wrappers for primitive types and assigning to null made it straight-forward to do so.","created_at":"2017-11-06T21:17:40Z","updated_at":"2017-11-06T21:17:40Z","html_url":"https://github.com/broadinstitute/gatk/pull/3779#discussion_r149205937","pull_request_url":"https://api.github.com/repos/broadinstitute/gatk/pulls/3779","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/broadinstitute/gatk/pulls/comments/149205937"},"html":{"href":"https://github.com/broadinstitute/gatk/pull/3779#discussion_r149205937"},"pull_request":{"href":"https://api.github.com/repos/broadinstitute/gatk/pulls/3779"}},"in_reply_to_id":148696189},"pull_request":{"url":"https://api.github.com/repos/broadinstitute/gatk/pulls/3779","id":150367980,"html_url":"https://github.com/broadinstitute/gatk/pull/3779","diff_url":"https://github.com/broadinstitute/gatk/pull/3779.diff","patch_url":"https://github.com/broadinstitute/gatk/pull/3779.patch","issue_url":"https://api.github.com/repos/broadinstitute/gatk/issues/3779","number":3779,"state":"open","locked":false,"title":"First version of Funcotator, a GATK Oncotator analog.","user":{"login":"jonn-smith","id":11667487,"avatar_url":"https://avatars1.githubusercontent.com/u/11667487?v=4","gravatar_id":"","url":"https://api.github.com/users/jonn-smith","html_url":"https://github.com/jonn-smith","followers_url":"https://api.github.com/users/jonn-smith/followers","following_url":"https://api.github.com/users/jonn-smith/following{/other_user}","gists_url":"https://api.github.com/users/jonn-smith/gists{/gist_id}","starred_url":"https://api.github.com/users/jonn-smith/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonn-smith/subscriptions","organizations_url":"https://api.github.com/users/jonn-smith/orgs","repos_url":"https://api.github.com/users/jonn-smith/repos","events_url":"https://api.github.com/users/jonn-smith/events{/privacy}","received_events_url":"https://api.github.com/users/jonn-smith/received_events","type":"User","site_admin":false},"body":"\r\nFirst version of Funcotator, a GATK Oncotator analog. \r\nFixes #3283\r\n\r\nIncludes functionality to create annotations from GENCODE for HG19 and\r\nHG38 for MNPs and INDELs in all regions of the genome.\r\n\r\nNOTE: There are still some INDEL issues, and some INDEL tests are still\r\ncommented out.\r\n\r\nThis is very much a work in progress and should still be considered a\r\nBETA tool.\r\n\r\nAdded required test files for Funcotator unit and integration tests to\r\ngit lfs.\r\n\r\nRebased on master, now tests are GATKBaseTests.","created_at":"2017-11-02T18:20:12Z","updated_at":"2017-11-06T21:17:40Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2b3bab075eb335f7224028555e7dc233be713610","assignee":{"login":"droazen","id":798637,"avatar_url":"https://avatars0.githubusercontent.com/u/798637?v=4","gravatar_id":"","url":"https://api.github.com/users/droazen","html_url":"https://github.com/droazen","followers_url":"https://api.github.com/users/droazen/followers","following_url":"https://api.github.com/users/droazen/following{/other_user}","gists_url":"https://api.github.com/users/droazen/gists{/gist_id}","starred_url":"https://api.github.com/users/droazen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/droazen/subscriptions","organizations_url":"https://api.github.com/users/droazen/orgs","repos_url":"https://api.github.com/users/droazen/repos","events_url":"https://api.github.com/users/droazen/events{/privacy}","received_events_url":"https://api.github.com/users/droazen/received_events","type":"User","site_admin":false},"assignees":[{"login":"droazen","id":798637,"avatar_url":"https://avatars0.githubusercontent.com/u/798637?v=4","gravatar_id":"","url":"https://api.github.com/users/droazen","html_url":"https://github.com/droazen","followers_url":"https://api.github.com/users/droazen/followers","following_url":"https://api.github.com/users/droazen/following{/other_user}","gists_url":"https://api.github.com/users/droazen/gists{/gist_id}","starred_url":"https://api.github.com/users/droazen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/droazen/subscriptions","organizations_url":"https://api.github.com/users/droazen/orgs","repos_url":"https://api.github.com/users/droazen/repos","events_url":"https://api.github.com/users/droazen/events{/privacy}","received_events_url":"https://api.github.com/users/droazen/received_events","type":"User","site_admin":false},{"login":"LeeTL1220","id":2152339,"avatar_url":"https://avatars0.githubusercontent.com/u/2152339?v=4","gravatar_id":"","url":"https://api.github.com/users/LeeTL1220","html_url":"https://github.com/LeeTL1220","followers_url":"https://api.github.com/users/LeeTL1220/followers","following_url":"https://api.github.com/users/LeeTL1220/following{/other_user}","gists_url":"https://api.github.com/users/LeeTL1220/gists{/gist_id}","starred_url":"https://api.github.com/users/LeeTL1220/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LeeTL1220/subscriptions","organizations_url":"https://api.github.com/users/LeeTL1220/orgs","repos_url":"https://api.github.com/users/LeeTL1220/repos","events_url":"https://api.github.com/users/LeeTL1220/events{/privacy}","received_events_url":"https://api.github.com/users/LeeTL1220/received_events","type":"User","site_admin":false},{"login":"lbergelson","id":4700332,"avatar_url":"https://avatars3.githubusercontent.com/u/4700332?v=4","gravatar_id":"","url":"https://api.github.com/users/lbergelson","html_url":"https://github.com/lbergelson","followers_url":"https://api.github.com/users/lbergelson/followers","following_url":"https://api.github.com/users/lbergelson/following{/other_user}","gists_url":"https://api.github.com/users/lbergelson/gists{/gist_id}","starred_url":"https://api.github.com/users/lbergelson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lbergelson/subscriptions","organizations_url":"https://api.github.com/users/lbergelson/orgs","repos_url":"https://api.github.com/users/lbergelson/repos","events_url":"https://api.github.com/users/lbergelson/events{/privacy}","received_events_url":"https://api.github.com/users/lbergelson/received_events","type":"User","site_admin":false}],"requested_reviewers":[{"login":"droazen","id":798637,"avatar_url":"https://avatars0.githubusercontent.com/u/798637?v=4","gravatar_id":"","url":"https://api.github.com/users/droazen","html_url":"https://github.com/droazen","followers_url":"https://api.github.com/users/droazen/followers","following_url":"https://api.github.com/users/droazen/following{/other_user}","gists_url":"https://api.github.com/users/droazen/gists{/gist_id}","starred_url":"https://api.github.com/users/droazen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/droazen/subscriptions","organizations_url":"https://api.github.com/users/droazen/orgs","repos_url":"https://api.github.com/users/droazen/repos","events_url":"https://api.github.com/users/droazen/events{/privacy}","received_events_url":"https://api.github.com/users/droazen/received_events","type":"User","site_admin":false},{"login":"lbergelson","id":4700332,"avatar_url":"https://avatars3.githubusercontent.com/u/4700332?v=4","gravatar_id":"","url":"https://api.github.com/users/lbergelson","html_url":"https://github.com/lbergelson","followers_url":"https://api.github.com/users/lbergelson/followers","following_url":"https://api.github.com/users/lbergelson/following{/other_user}","gists_url":"https://api.github.com/users/lbergelson/gists{/gist_id}","starred_url":"https://api.github.com/users/lbergelson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lbergelson/subscriptions","organizations_url":"https://api.github.com/users/lbergelson/orgs","repos_url":"https://api.github.com/users/lbergelson/repos","events_url":"https://api.github.com/users/lbergelson/events{/privacy}","received_events_url":"https://api.github.com/users/lbergelson/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/broadinstitute/gatk/milestones/12","html_url":"https://github.com/broadinstitute/gatk/milestone/12","labels_url":"https://api.github.com/repos/broadinstitute/gatk/milestones/12/labels","id":2397977,"number":12,"title":"Engine-4.0","description":"","creator":{"login":"droazen","id":798637,"avatar_url":"https://avatars0.githubusercontent.com/u/798637?v=4","gravatar_id":"","url":"https://api.github.com/users/droazen","html_url":"https://github.com/droazen","followers_url":"https://api.github.com/users/droazen/followers","following_url":"https://api.github.com/users/droazen/following{/other_user}","gists_url":"https://api.github.com/users/droazen/gists{/gist_id}","starred_url":"https://api.github.com/users/droazen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/droazen/subscriptions","organizations_url":"https://api.github.com/users/droazen/orgs","repos_url":"https://api.github.com/users/droazen/repos","events_url":"https://api.github.com/users/droazen/events{/privacy}","received_events_url":"https://api.github.com/users/droazen/received_events","type":"User","site_admin":false},"open_issues":133,"closed_issues":105,"state":"open","created_at":"2017-03-20T14:24:57Z","updated_at":"2017-11-06T21:16:58Z","due_on":"2018-01-09T08:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/broadinstitute/gatk/pulls/3779/commits","review_comments_url":"https://api.github.com/repos/broadinstitute/gatk/pulls/3779/comments","review_comment_url":"https://api.github.com/repos/broadinstitute/gatk/pulls/comments{/number}","comments_url":"https://api.github.com/repos/broadinstitute/gatk/issues/3779/comments","statuses_url":"https://api.github.com/repos/broadinstitute/gatk/statuses/b7be62a08a937a0104fa970f2f86df39670785f6","head":{"label":"broadinstitute:jts_funcotator_3283","ref":"jts_funcotator_3283","sha":"b7be62a08a937a0104fa970f2f86df39670785f6","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":"2017-11-06T09:02:27Z","pushed_at":"2017-11-06T21:17:01Z","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":149310,"stargazers_count":258,"watchers_count":258,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":99,"mirror_url":null,"archived":false,"open_issues_count":782,"forks":99,"open_issues":782,"watchers":258,"default_branch":"master"}},"base":{"label":"broadinstitute:master","ref":"master","sha":"118923b42fe917821564d9dc7a515fd3315b0731","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":"2017-11-06T09:02:27Z","pushed_at":"2017-11-06T21:17:01Z","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":149310,"stargazers_count":258,"watchers_count":258,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":99,"mirror_url":null,"archived":false,"open_issues_count":782,"forks":99,"open_issues":782,"watchers":258,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/broadinstitute/gatk/pulls/3779"},"html":{"href":"https://github.com/broadinstitute/gatk/pull/3779"},"issue":{"href":"https://api.github.com/repos/broadinstitute/gatk/issues/3779"},"comments":{"href":"https://api.github.com/repos/broadinstitute/gatk/issues/3779/comments"},"review_comments":{"href":"https://api.github.com/repos/broadinstitute/gatk/pulls/3779/comments"},"review_comment":{"href":"https://api.github.com/repos/broadinstitute/gatk/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/broadinstitute/gatk/pulls/3779/commits"},"statuses":{"href":"https://api.github.com/repos/broadinstitute/gatk/statuses/b7be62a08a937a0104fa970f2f86df39670785f6"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"jonn-smith"}}