{"action":"created","comment":{"url":"https://api.github.com/repos/broadinstitute/hellbender/pulls/comments/34915936","id":34915936,"diff_hunk":"@@ -0,0 +1,389 @@\n+package org.broadinstitute.hellbender.tools.walkers.filters;\n+\n+import com.google.common.collect.Sets;\n+import htsjdk.tribble.Feature;\n+import htsjdk.variant.variantcontext.*;\n+import htsjdk.variant.variantcontext.VariantContextUtils.JexlVCMatchExp;\n+import htsjdk.variant.variantcontext.writer.Options;\n+import htsjdk.variant.variantcontext.writer.VariantContextWriter;\n+import htsjdk.variant.variantcontext.writer.VariantContextWriterBuilder;\n+import htsjdk.variant.vcf.*;\n+import org.broadinstitute.hellbender.cmdline.Argument;\n+import org.broadinstitute.hellbender.cmdline.CommandLineProgramProperties;\n+import org.broadinstitute.hellbender.cmdline.StandardArgumentDefinitions;\n+import org.broadinstitute.hellbender.cmdline.programgroups.VariantProgramGroup;\n+import org.broadinstitute.hellbender.engine.*;\n+import org.broadinstitute.hellbender.exceptions.UserException;\n+import org.broadinstitute.hellbender.utils.IntervalUtils;\n+import org.broadinstitute.hellbender.utils.Utils;\n+\n+import java.util.*;\n+\n+import static java.util.Collections.singleton;\n+\n+\n+/**\n+ * Filter variant calls based on INFO and FORMAT annotations\n+ *\n+ * <p>\n+ * This tool is designed for hard-filtering variant calls based on certain criteria.\n+ * Records are hard-filtered by changing the value in the FILTER field to something other than PASS. Filtered records\n+ * will be preserved in the output unless their removal is requested in the command line. </p>\n+ *\n+ * <h3>Input</h3>\n+ * <p>\n+ * A variant set to filter.\n+ * </p>\n+ *\n+ * <h3>Output</h3>\n+ * <p>\n+ * A filtered VCF.\n+ * </p>\n+ *\n+ * <h3>Usage example</h3>\n+ * <pre>\n+ * java -jar GenomeAnalysisTK.jar \\\n+ *   -T VariantFiltration \\\n+ *   -R reference.fasta \\\n+ *   -o output.vcf \\\n+ *   --variant input.vcf \\\n+ *   --filterExpression \"AB < 0.2 || MQ0 > 50\" \\\n+ *   --filterName \"Nov09filters\" \\\n+ *   --mask mask.vcf \\\n+ *   --maskName InDel\n+ * </pre>\n+ *\n+ */\n+@CommandLineProgramProperties(\n+        usage = \"Filter variant calls based on INFO and FORMAT annotations.\",\n+        usageShort = \"Filter variants VCF\",\n+        programGroup = VariantProgramGroup.class\n+)\n+public final class VariantFiltration extends VariantWalker {\n+\n+    /**\n+     * Any variant which overlaps entries from the provided mask rod will be filtered. If the user wants logic to be reversed,\n+     * i.e. filter variants that do not overlap with provided mask, then argument -filterNotInMask can be used.\n+     * Note that it is up to the user to adapt the name of the mask to make it clear that the reverse logic was used\n+     * (e.g. if masking against Hapmap, use -maskName=hapmap for the normal masking and -maskName=not_hapmap for the reverse masking).\n+     */\n+    @Argument(fullName=\"mask\", shortName=\"mask\", doc=\"Input ROD mask\", optional=true)\n+    public FeatureInput<Feature> mask;\n+\n+    @Argument(doc=\"File to which variants should be written\", fullName = StandardArgumentDefinitions.OUTPUT_LONG_NAME, shortName = StandardArgumentDefinitions.OUTPUT_SHORT_NAME, optional = false)\n+    public String out = null;\n+\n+    /**\n+     * VariantFiltration accepts any number of JEXL expressions (so you can have two named filters by using\n+     * --filterName One --filterExpression \"X < 1\" --filterName Two --filterExpression \"X > 2\").\n+     */\n+    @Argument(fullName=\"filterExpression\", shortName=\"filter\", doc=\"One or more expression used with INFO fields to filter\", optional=true)\n+    public ArrayList<String> filterExpressions = new ArrayList<>(); //XXX htsjdk's API is bogus and wants an ArrayList\n+\n+    /**\n+     * This name is put in the FILTER field for variants that get filtered.  Note that there must be a 1-to-1 mapping between filter expressions and filter names.\n+     */\n+    @Argument(fullName=\"filterName\", shortName=\"filterName\", doc=\"Names to use for the list of filters\", optional=true)\n+    public ArrayList<String> filterNames = new ArrayList<>(); //XXX htsjdk's API is bogus and wants an ArrayList\n+\n+    /**\n+     * Similar to the INFO field based expressions, but used on the FORMAT (genotype) fields instead.\n+     * VariantFiltration will add the sample-level FT tag to the FORMAT field of filtered samples (this does not affect the record's FILTER tag).\n+     * One can filter normally based on most fields (e.g. \"GQ < 5.0\"), but the GT (genotype) field is an exception. We have put in convenience\n+     * methods so that one can now filter out hets (\"isHet == 1\"), refs (\"isHomRef == 1\"), or homs (\"isHomVar == 1\"). Also available are\n+     * expressions isCalled, isNoCall, isMixed, and isAvailable, in accordance with the methods of the Genotype object.\n+     */\n+    @Argument(fullName=\"genotypeFilterExpression\", shortName=\"G_filter\", doc=\"One or more expression used with FORMAT (sample/genotype-level) fields to filter (see documentation guide for more info)\", optional=true)\n+    public ArrayList<String> genotypeFilterExpressions = new ArrayList<>();  //XXX htsjdk's API is bogus and wants an ArrayList\n+\n+    /**\n+     * Similar to the INFO field based expressions, but used on the FORMAT (genotype) fields instead.\n+     */\n+    @Argument(fullName=\"genotypeFilterName\", shortName=\"G_filterName\", doc=\"Names to use for the list of sample/genotype filters (must be a 1-to-1 mapping); this name is put in the FILTER field for variants that get filtered\", optional=true)\n+    public ArrayList<String> genotypeFilterNames = new ArrayList<>();   //XXX htsjdk's API is bogus and wants an ArrayList\n+\n+    /**\n+     * Works together with the --clusterWindowSize argument.\n+     */\n+    @Argument(fullName=\"clusterSize\", shortName=\"cluster\", doc=\"The number of SNPs which make up a cluster\", optional=true)\n+    public Integer clusterSize = 3;\n+\n+    /**\n+     * Works together with the --clusterSize argument.  To disable the clustered SNP filter, set this value to less than 1.\n+     */\n+    @Argument(fullName=\"clusterWindowSize\", shortName=\"window\", doc=\"The window size (in bases) in which to evaluate clustered SNPs\", optional=true)\n+    public Integer clusterWindow = 0;\n+\n+    @Argument(fullName=\"maskExtension\", shortName=\"maskExtend\", doc=\"How many bases beyond records from a provided 'mask' rod should variants be filtered\", optional=true)\n+    public Integer maskExtension = 0;\n+\n+    /**\n+     * When using the -mask argument, the maskName will be annotated in the variant record.\n+     * Note that when using the -filterNotInMask argument to reverse the masking logic,\n+     * it is up to the user to adapt the name of the mask to make it clear that the reverse logic was used\n+     * (e.g. if masking against Hapmap, use -maskName=hapmap for the normal masking and -maskName=not_hapmap for the reverse masking).\n+     */\n+    @Argument(fullName=\"maskName\", shortName=\"maskName\", doc=\"The text to put in the FILTER field if a 'mask' rod is provided and overlaps with a variant call\", optional=true)\n+    public String maskName = \"Mask\";\n+\n+    /**\n+     * By default, if the -mask argument is used, any variant falling in a mask will be filtered.\n+     * If this argument is used, logic is reversed, and variants falling outside a given mask will be filtered.\n+     * Use case is, for example, if we have an interval list or BED file with \"good\" sites.\n+     * Note that it is up to the user to adapt the name of the mask to make it clear that the reverse logic was used\n+     * (e.g. if masking against Hapmap, use -maskName=hapmap for the normal masking and -maskName=not_hapmap for the reverse masking).\n+     */\n+    @Argument(fullName=\"filterNotInMask\", shortName=\"filterNotInMask\", doc=\"Filter records NOT in given input mask.\", optional=true)\n+    public boolean filterRecordsNotInMask = false;\n+\n+    /**\n+     * By default, if JEXL cannot evaluate your expression for a particular record because one of the annotations is not present, the whole expression evaluates as PASSing.\n+     * Use this argument to have it evaluate as failing filters instead for these cases.\n+     */\n+    @Argument(fullName=\"missingValuesInExpressionsShouldEvaluateAsFailing\", doc=\"When evaluating the JEXL expressions, missing values should be considered failing the expression\", optional=true)\n+    public Boolean failMissingValues = false;\n+\n+    /**\n+     * Invalidate previous filters applied to the VariantContext, applying only the filters here\n+     */\n+    @Argument(fullName=\"invalidatePreviousFilters\",doc=\"Remove previous filters applied to the VCF\",optional=true)\n+    boolean invalidatePreviousFilters = false;\n+\n+    /**\n+     * Invert the selection criteria for --filterExpression\n+     */\n+    @Argument(fullName=\"invertFilterExpression\", shortName=\"invfilter\", doc=\"Invert the selection criteria for --filterExpression\", optional=true)\n+    public boolean invertFilterExpression = false;\n+\n+    /**\n+     * Invert the selection criteria for --genotypeFilterExpression\n+     */\n+    @Argument(fullName=\"invertGenotypeFilterExpression\", shortName=\"invG_filter\", doc=\"Invert the selection criteria for --genotypeFilterExpression\", optional=true)\n+    public boolean invertGenotypeFilterExpression = false;\n+\n+    /**\n+     * If this argument is provided, set filtered genotypes to no-call (./.).\n+     */\n+    @Argument(fullName=\"setFilteredGtToNocall\", optional=true, doc=\"Set filtered genotypes to no-call\")\n+    private boolean setFilteredGenotypesToNocall = false;\n+\n+    // JEXL expressions for the filters\n+    private List<JexlVCMatchExp> filterExps;\n+    private List<JexlVCMatchExp> genotypeFilterExps;\n+\n+    public static final String CLUSTERED_SNP_FILTER_NAME = \"SnpCluster\";\n+\n+    private VariantContextWriter writer;\n+\n+    private final List<Allele> diploidNoCallAlleles = Arrays.asList(Allele.NO_CALL, Allele.NO_CALL);\n+\n+    /**\n+     * Prepend inverse phrase to description if --invertFilterExpression\n+     *\n+     * @param description the description\n+     * @return the description with inverse prepended if --invert_filter_expression\n+     */\n+    private String possiblyInvertFilterExpression( final String description ){\n+        return invertFilterExpression ? \"Inverse of: \" + description : description;\n+    }\n+\n+    private void initializeVcfWriter() {\n+\n+        //XXX hardwired to output VCFs\n+        //XXX unset indexing on the fly\n+        writer = new VariantContextWriterBuilder().setOutputFile(out).setOutputFileType(VariantContextWriterBuilder.OutputType.VCF).unsetOption(Options.INDEX_ON_THE_FLY).build();\n+\n+        // setup the header fields\n+        final Set<VCFHeaderLine> hInfo = new HashSet<>();\n+        hInfo.addAll(getHeaderForVariants().getMetaDataInSortedOrder());\n+\n+        if ( clusterWindow > 0 ) {\n+            hInfo.add(new VCFFilterHeaderLine(CLUSTERED_SNP_FILTER_NAME, \"SNPs found in clusters\"));\n+        }\n+\n+        if ( !genotypeFilterExps.isEmpty() ) {\n+            hInfo.add(VCFStandardHeaderLines.getFormatLine(VCFConstants.GENOTYPE_FILTER_KEY));\n+        }\n+\n+        try {\n+            for ( final JexlVCMatchExp exp : filterExps ) {\n+                hInfo.add(new VCFFilterHeaderLine(exp.name, possiblyInvertFilterExpression(exp.exp.toString())));\n+            }\n+            for ( final JexlVCMatchExp exp : genotypeFilterExps ) {\n+                hInfo.add(new VCFFilterHeaderLine(exp.name, possiblyInvertFilterExpression(exp.exp.toString())));\n+            }\n+\n+            if ( mask != null ) {\n+                if (filterRecordsNotInMask) {\n+                    hInfo.add(new VCFFilterHeaderLine(maskName, \"Doesn't overlap a user-input mask\"));\n+                } else {\n+                    hInfo.add(new VCFFilterHeaderLine(maskName, \"Overlaps a user-input mask\"));\n+                }\n+            }\n+        } catch (final IllegalArgumentException e) {\n+            throw new UserException.BadInput(e.getMessage());\n+        }\n+\n+        writer.writeHeader(new VCFHeader(hInfo, getHeaderForVariants().getGenotypeSamples()));\n+    }\n+\n+    @Override\n+    public void onTraversalStart() {\n+        if ( maskExtension < 0 ) {\n+            throw new UserException.BadArgumentValue(\"maskExtension\", \"negative values are not allowed\");\n+        }\n+\n+        if (filterRecordsNotInMask && mask == null) {\n+            throw new UserException.BadArgumentValue(\"filterNotInMask\", \"argument not allowed if mask argument is not provided\");\n+        }\n+        filterExps = VariantContextUtils.initializeMatchExps(filterNames, filterExpressions);\n+        genotypeFilterExps = VariantContextUtils.initializeMatchExps(genotypeFilterNames, genotypeFilterExpressions);\n+\n+        VariantContextUtils.engine.get().setSilent(true);\n+\n+        initializeVcfWriter();\n+    }\n+\n+    @Override\n+    public void apply(final VariantContext variant, final ReadsContext readsContext, final ReferenceContext ref, final FeatureContext featureContext) {\n+\n+        final VariantContext vc1 = invalidatePreviousFilters ? (new VariantContextBuilder(variant)).filters(Collections.emptySet()).make() : variant;\n+        final VariantContext vc = filterPresent(vc1) ? vc1: addMaskIfCoversVariant(vc1, featureContext);\n+\n+        filter(vc, featureContext);\n+    }\n+\n+    /**\n+     * Add mask to variant context filters if it covers the it's location\n+     * @return VariantContext with the mask added if the VariantContext is within the extended mask area\n+     */\n+    private VariantContext addMaskIfCoversVariant(final VariantContext vc, final FeatureContext featureContext) {\n+        final List<Feature> maskSnps = featureContext.getValues(mask, maskExtension, maskExtension);\n+\n+        final boolean snpsMasked = maskSnps.isEmpty() == filterRecordsNotInMask;\n+        if (snpsMasked) {\n+            final Set<String> oldFiltersPlusNewOne = Sets.union(vc.getFilters(), singleton(maskName));\n+            return new VariantContextBuilder(vc).filters(oldFiltersPlusNewOne).make();\n+        } else {\n+            return vc;\n+        }\n+    }\n+\n+    private boolean filterPresent(final VariantContext vc) {\n+        return vc.getFilters() != null && vc.getFilters().contains(maskName);\n+    }\n+\n+    private void filter(final VariantContext vc, final FeatureContext featureContext) {\n+        final VariantContextBuilder builder = new VariantContextBuilder(vc);\n+\n+        // make new Genotypes based on filters\n+        if ( !genotypeFilterExps.isEmpty() || setFilteredGenotypesToNocall ) {\n+            final GenotypesContext genotypes = GenotypesContext.create(vc.getGenotypes().size());\n+\n+            // for each genotype, check filters then create a new object\n+            for ( final Genotype g : vc.getGenotypes() ) {\n+                if ( g.isCalled() ) {\n+                    final List<String> filters = new ArrayList<>();\n+                    if ( g.isFiltered() ) {\n+                        filters.add(g.getFilters());\n+                    }\n+\n+                    // Add if expression filters the variant context\n+                    for ( final JexlVCMatchExp exp : genotypeFilterExps ) {\n+                        if ( Utils.invertLogic(VariantContextUtils.match(vc, g, exp), invertGenotypeFilterExpression) ) {\n+                            filters.add(exp.name);\n+                        }\n+                    }\n+\n+                    // if sample is filtered and --setFilteredGtToNocall, set genotype to non-call\n+                    if ( !filters.isEmpty() && setFilteredGenotypesToNocall ) {\n+                        genotypes.add(new GenotypeBuilder(g).filters(filters).alleles(diploidNoCallAlleles).make());\n+                    } else {\n+                        genotypes.add(new GenotypeBuilder(g).filters(filters).make());\n+                    }\n+                } else {\n+                    genotypes.add(g);\n+                }\n+            }\n+\n+            builder.genotypes(genotypes);\n+        }\n+\n+        // make a new variant context based on filters\n+        final Set<String> filters = new LinkedHashSet<>(vc.getFilters());\n+\n+        // test for clustered SNPs if requested\n+        if (areClusteredVariants(featureContext, vc)){\n+            filters.add(CLUSTERED_SNP_FILTER_NAME);\n+        }\n+\n+        for ( final JexlVCMatchExp exp : filterExps ) {\n+            try {\n+                if ( Utils.invertLogic(VariantContextUtils.match(vc, exp), invertFilterExpression) ) {\n+                    filters.add(exp.name);\n+                }\n+            } catch (final Exception e) {\n+                // do nothing unless specifically asked to; it just means that the expression isn't defined for this context\n+                if ( failMissingValues  ) {\n+                    filters.add(exp.name);\n+                }\n+            }\n+        }\n+\n+        if ( filters.isEmpty() ) {\n+            builder.passFilters();\n+        } else {\n+            builder.filters(filters);\n+        }\n+\n+        writer.add(builder.make());\n+    }\n+\n+    /**\n+     * Return true if there is a window of size {@link clusterWindow} that contains as least {@link clusterSize} variants.\n+     */\n+    private boolean areClusteredVariants(final FeatureContext featureContext, final VariantContext current) {\n+        if (clusterWindow < 1){ //as per argument doc, values < 1 imply no clustering\n+            return false;\n+        }\n+        //Need to fetch variants from left and right of the current variant.\n+        final List<? extends Feature> values = featureContext.getValues(getDrivingVariantFeatureInput(), clusterWindow, clusterWindow);\n+        values.sort(IntervalUtils.LEXICOGRAPHICAL_ORDER_COMPARATOR); //Note: by construction, they will be from the same contig.\n+        if (values.size() < clusterSize){  //not enough variants - will never be a cluster no matter what.\n+            return false;\n+        }\n+\n+        //Scan the list of variants and check if any stretch of clusterSize variants\n+        //that contains the 'current variant' has is more clustered than clusterWindow.\n+        final int currentStartPos = current.getStart();\n+        int firstIndexIndex = 0;\n+\n+        //start with the lowest pos\n+        int firstPos = values.get(firstIndexIndex).getStart();//there is at least 1 element so it's ok\n+        final int n = clusterSize - 1;\n+        while(firstPos <= currentStartPos && firstIndexIndex + n < values.size()) {\n+            final int firstPlusNPos = values.get(firstIndexIndex + n).getStart();\n+\n+            if (firstPlusNPos - firstPos < clusterWindow){\n+                return true;\n+            }\n+\n+            firstIndexIndex++;\n+            firstPos = values.get(firstIndexIndex).getStart();//there is at least 1 element so it's ok\n+        }\n+        return false;\n+    }\n+\n+    /**\n+     * Tell the user the number of loci processed and close out the new variants file.","path":"src/main/java/org/broadinstitute/hellbender/tools/walkers/filters/VariantFiltration.java","position":378,"original_position":378,"commit_id":"e8c266ec99b02010852b860be6dbe080d5bfad4a","original_commit_id":"e8c266ec99b02010852b860be6dbe080d5bfad4a","user":{"login":"droazen","id":798637,"avatar_url":"https://avatars.githubusercontent.com/u/798637?v=3","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},"body":"Comment is inaccurate -- the tool does not return the number of loci processed. Should it?","created_at":"2015-07-17T18:10:32Z","updated_at":"2015-07-17T18:10:32Z","html_url":"https://github.com/broadinstitute/hellbender/pull/614#discussion_r34915936","pull_request_url":"https://api.github.com/repos/broadinstitute/hellbender/pulls/614","_links":{"self":{"href":"https://api.github.com/repos/broadinstitute/hellbender/pulls/comments/34915936"},"html":{"href":"https://github.com/broadinstitute/hellbender/pull/614#discussion_r34915936"},"pull_request":{"href":"https://api.github.com/repos/broadinstitute/hellbender/pulls/614"}}},"pull_request":{"url":"https://api.github.com/repos/broadinstitute/hellbender/pulls/614","id":39312400,"html_url":"https://github.com/broadinstitute/hellbender/pull/614","diff_url":"https://github.com/broadinstitute/hellbender/pull/614.diff","patch_url":"https://github.com/broadinstitute/hellbender/pull/614.patch","issue_url":"https://api.github.com/repos/broadinstitute/hellbender/issues/614","number":614,"state":"open","locked":false,"title":"VariantFiltration - port and a ~half-rewrite for GATK4. ","user":{"login":"akiezun","id":1993519,"avatar_url":"https://avatars.githubusercontent.com/u/1993519?v=3","gravatar_id":"","url":"https://api.github.com/users/akiezun","html_url":"https://github.com/akiezun","followers_url":"https://api.github.com/users/akiezun/followers","following_url":"https://api.github.com/users/akiezun/following{/other_user}","gists_url":"https://api.github.com/users/akiezun/gists{/gist_id}","starred_url":"https://api.github.com/users/akiezun/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akiezun/subscriptions","organizations_url":"https://api.github.com/users/akiezun/orgs","repos_url":"https://api.github.com/users/akiezun/repos","events_url":"https://api.github.com/users/akiezun/events{/privacy}","received_events_url":"https://api.github.com/users/akiezun/received_events","type":"User","site_admin":false},"body":"It is now site-by-site independent (unlike GATK3).\r\n\r\nAll integration tests were ported as is (after ditching the MD5s). The algorithm was changed so that it works on a site-by-site independent basis. Some changes to the engine classes were required to allow queries over intervals in feature data sources.\r\n\r\nFixes https://github.com/broadinstitute/hellbender/issues/38","created_at":"2015-07-06T21:24:06Z","updated_at":"2015-07-17T18:10:32Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e998afdf6658cfdbdc4ab65b73b90bc5f2dcd062","assignee":{"login":"droazen","id":798637,"avatar_url":"https://avatars.githubusercontent.com/u/798637?v=3","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},"milestone":null,"commits_url":"https://api.github.com/repos/broadinstitute/hellbender/pulls/614/commits","review_comments_url":"https://api.github.com/repos/broadinstitute/hellbender/pulls/614/comments","review_comment_url":"https://api.github.com/repos/broadinstitute/hellbender/pulls/comments{/number}","comments_url":"https://api.github.com/repos/broadinstitute/hellbender/issues/614/comments","statuses_url":"https://api.github.com/repos/broadinstitute/hellbender/statuses/e8c266ec99b02010852b860be6dbe080d5bfad4a","head":{"label":"broadinstitute:ak_variant_filtration","ref":"ak_variant_filtration","sha":"e8c266ec99b02010852b860be6dbe080d5bfad4a","user":{"login":"broadinstitute","id":393552,"avatar_url":"https://avatars.githubusercontent.com/u/393552?v=3","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":"hellbender","full_name":"broadinstitute/hellbender","owner":{"login":"broadinstitute","id":393552,"avatar_url":"https://avatars.githubusercontent.com/u/393552?v=3","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/hellbender","description":"GATK4 development","fork":false,"url":"https://api.github.com/repos/broadinstitute/hellbender","forks_url":"https://api.github.com/repos/broadinstitute/hellbender/forks","keys_url":"https://api.github.com/repos/broadinstitute/hellbender/keys{/key_id}","collaborators_url":"https://api.github.com/repos/broadinstitute/hellbender/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/broadinstitute/hellbender/teams","hooks_url":"https://api.github.com/repos/broadinstitute/hellbender/hooks","issue_events_url":"https://api.github.com/repos/broadinstitute/hellbender/issues/events{/number}","events_url":"https://api.github.com/repos/broadinstitute/hellbender/events","assignees_url":"https://api.github.com/repos/broadinstitute/hellbender/assignees{/user}","branches_url":"https://api.github.com/repos/broadinstitute/hellbender/branches{/branch}","tags_url":"https://api.github.com/repos/broadinstitute/hellbender/tags","blobs_url":"https://api.github.com/repos/broadinstitute/hellbender/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/broadinstitute/hellbender/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/broadinstitute/hellbender/git/refs{/sha}","trees_url":"https://api.github.com/repos/broadinstitute/hellbender/git/trees{/sha}","statuses_url":"https://api.github.com/repos/broadinstitute/hellbender/statuses/{sha}","languages_url":"https://api.github.com/repos/broadinstitute/hellbender/languages","stargazers_url":"https://api.github.com/repos/broadinstitute/hellbender/stargazers","contributors_url":"https://api.github.com/repos/broadinstitute/hellbender/contributors","subscribers_url":"https://api.github.com/repos/broadinstitute/hellbender/subscribers","subscription_url":"https://api.github.com/repos/broadinstitute/hellbender/subscription","commits_url":"https://api.github.com/repos/broadinstitute/hellbender/commits{/sha}","git_commits_url":"https://api.github.com/repos/broadinstitute/hellbender/git/commits{/sha}","comments_url":"https://api.github.com/repos/broadinstitute/hellbender/comments{/number}","issue_comment_url":"https://api.github.com/repos/broadinstitute/hellbender/issues/comments{/number}","contents_url":"https://api.github.com/repos/broadinstitute/hellbender/contents/{+path}","compare_url":"https://api.github.com/repos/broadinstitute/hellbender/compare/{base}...{head}","merges_url":"https://api.github.com/repos/broadinstitute/hellbender/merges","archive_url":"https://api.github.com/repos/broadinstitute/hellbender/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/broadinstitute/hellbender/downloads","issues_url":"https://api.github.com/repos/broadinstitute/hellbender/issues{/number}","pulls_url":"https://api.github.com/repos/broadinstitute/hellbender/pulls{/number}","milestones_url":"https://api.github.com/repos/broadinstitute/hellbender/milestones{/number}","notifications_url":"https://api.github.com/repos/broadinstitute/hellbender/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/broadinstitute/hellbender/labels{/name}","releases_url":"https://api.github.com/repos/broadinstitute/hellbender/releases{/id}","created_at":"2014-12-02T20:50:36Z","updated_at":"2015-07-05T14:31:29Z","pushed_at":"2015-07-17T18:08:22Z","git_url":"git://github.com/broadinstitute/hellbender.git","ssh_url":"git@github.com:broadinstitute/hellbender.git","clone_url":"https://github.com/broadinstitute/hellbender.git","svn_url":"https://github.com/broadinstitute/hellbender","homepage":"","size":32857,"stargazers_count":26,"watchers_count":26,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":6,"mirror_url":null,"open_issues_count":208,"forks":6,"open_issues":208,"watchers":26,"default_branch":"master"}},"base":{"label":"broadinstitute:master","ref":"master","sha":"9a3044247b8a18bdb6df8dfa1f76e0ce27fe8c2f","user":{"login":"broadinstitute","id":393552,"avatar_url":"https://avatars.githubusercontent.com/u/393552?v=3","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":"hellbender","full_name":"broadinstitute/hellbender","owner":{"login":"broadinstitute","id":393552,"avatar_url":"https://avatars.githubusercontent.com/u/393552?v=3","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/hellbender","description":"GATK4 development","fork":false,"url":"https://api.github.com/repos/broadinstitute/hellbender","forks_url":"https://api.github.com/repos/broadinstitute/hellbender/forks","keys_url":"https://api.github.com/repos/broadinstitute/hellbender/keys{/key_id}","collaborators_url":"https://api.github.com/repos/broadinstitute/hellbender/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/broadinstitute/hellbender/teams","hooks_url":"https://api.github.com/repos/broadinstitute/hellbender/hooks","issue_events_url":"https://api.github.com/repos/broadinstitute/hellbender/issues/events{/number}","events_url":"https://api.github.com/repos/broadinstitute/hellbender/events","assignees_url":"https://api.github.com/repos/broadinstitute/hellbender/assignees{/user}","branches_url":"https://api.github.com/repos/broadinstitute/hellbender/branches{/branch}","tags_url":"https://api.github.com/repos/broadinstitute/hellbender/tags","blobs_url":"https://api.github.com/repos/broadinstitute/hellbender/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/broadinstitute/hellbender/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/broadinstitute/hellbender/git/refs{/sha}","trees_url":"https://api.github.com/repos/broadinstitute/hellbender/git/trees{/sha}","statuses_url":"https://api.github.com/repos/broadinstitute/hellbender/statuses/{sha}","languages_url":"https://api.github.com/repos/broadinstitute/hellbender/languages","stargazers_url":"https://api.github.com/repos/broadinstitute/hellbender/stargazers","contributors_url":"https://api.github.com/repos/broadinstitute/hellbender/contributors","subscribers_url":"https://api.github.com/repos/broadinstitute/hellbender/subscribers","subscription_url":"https://api.github.com/repos/broadinstitute/hellbender/subscription","commits_url":"https://api.github.com/repos/broadinstitute/hellbender/commits{/sha}","git_commits_url":"https://api.github.com/repos/broadinstitute/hellbender/git/commits{/sha}","comments_url":"https://api.github.com/repos/broadinstitute/hellbender/comments{/number}","issue_comment_url":"https://api.github.com/repos/broadinstitute/hellbender/issues/comments{/number}","contents_url":"https://api.github.com/repos/broadinstitute/hellbender/contents/{+path}","compare_url":"https://api.github.com/repos/broadinstitute/hellbender/compare/{base}...{head}","merges_url":"https://api.github.com/repos/broadinstitute/hellbender/merges","archive_url":"https://api.github.com/repos/broadinstitute/hellbender/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/broadinstitute/hellbender/downloads","issues_url":"https://api.github.com/repos/broadinstitute/hellbender/issues{/number}","pulls_url":"https://api.github.com/repos/broadinstitute/hellbender/pulls{/number}","milestones_url":"https://api.github.com/repos/broadinstitute/hellbender/milestones{/number}","notifications_url":"https://api.github.com/repos/broadinstitute/hellbender/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/broadinstitute/hellbender/labels{/name}","releases_url":"https://api.github.com/repos/broadinstitute/hellbender/releases{/id}","created_at":"2014-12-02T20:50:36Z","updated_at":"2015-07-05T14:31:29Z","pushed_at":"2015-07-17T18:08:22Z","git_url":"git://github.com/broadinstitute/hellbender.git","ssh_url":"git@github.com:broadinstitute/hellbender.git","clone_url":"https://github.com/broadinstitute/hellbender.git","svn_url":"https://github.com/broadinstitute/hellbender","homepage":"","size":32857,"stargazers_count":26,"watchers_count":26,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":6,"mirror_url":null,"open_issues_count":208,"forks":6,"open_issues":208,"watchers":26,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/broadinstitute/hellbender/pulls/614"},"html":{"href":"https://github.com/broadinstitute/hellbender/pull/614"},"issue":{"href":"https://api.github.com/repos/broadinstitute/hellbender/issues/614"},"comments":{"href":"https://api.github.com/repos/broadinstitute/hellbender/issues/614/comments"},"review_comments":{"href":"https://api.github.com/repos/broadinstitute/hellbender/pulls/614/comments"},"review_comment":{"href":"https://api.github.com/repos/broadinstitute/hellbender/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/broadinstitute/hellbender/pulls/614/commits"},"statuses":{"href":"https://api.github.com/repos/broadinstitute/hellbender/statuses/e8c266ec99b02010852b860be6dbe080d5bfad4a"}}}}