{"action":"created","comment":{"url":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls/comments/25655138","id":25655138,"diff_hunk":"@@ -129,157 +169,211 @@ def parser_tabfile_rename(parser=argparse.ArgumentParser()):\n     return parser\n __commands__.append(('tabfile_rename', parser_tabfile_rename))\n \n-#  ==============================================\n-\n \n-def pos_to_number(row):\n-    row['pos'] = int(float(row['pos']))\n-    return row\n-def reposition_vphaser_deletions(row):\n-    if row['var'].startswith('D'):\n-        for k in ('ct_1','ct_2','ct_3','ct_4','extra1','extra2'):\n-            assert row.get(k,'D')[0] in ('D','i')\n-        row['pos'] = row['pos']-1\n-    return row\n+#  ========== merge_to_vcf ===========================\n \n-def vphaser_to_vcf(inFile, refFasta, multiAlignment, outVcf):\n+def merge_to_vcf(refFasta, outVcf, samples, isnvs, assemblies):\n     ''' Convert vPhaser2 parsed filtered output text file into VCF format.\n-        We require the consensus assemblies for all these samples in a multi-alignment\n-        FASTA format as well, in order to resolve the ambiguity in vPhaser's output.\n-        All sample names and coordinates must be identical between inFile, inRef, and\n-        multiAlign.  We also require the reference genome FASTA (inRef) to determine\n-        reference alleles.  Requires a single-chromosome genome.\n     '''\n-\n-    # read in multiple alignments of consensus sequences\n-    with open(multiAlignment, 'rt') as inf:\n-        aln = Bio.AlignIO.read(inf, 'fasta')\n-\n-    # open reference genome and set ref as a BioPython SeqRecord\n-    with open(refFasta, 'rt') as inf:\n-        ref = list(Bio.SeqIO.parse(inf, 'fasta'))\n-        assert len(ref)==1\n-        ref = ref[0]\n-\n-    # prepare sample list\n-    samples = list(util.misc.unique(row['patient'] for row in util.file.read_tabfile_dict(inFile)))\n-    samples_assembled = [(i, seq.id.split('.')[0], seq.id) for i,seq in enumerate(aln)]\n-    sample_idx_map = {}\n-    for s in samples:\n-        idx = [i for i,s_root,s_full in samples_assembled if s_root==s.split('.')[0]]\n-        assert len(idx)==1, \"unable to uniquely find %s in %s\" % (s, multiAlignment)\n-        sample_idx_map[s] = idx[0]\n-\n-    # write output VCF file\n-    with open(outVcf, 'wt') as outf:\n+    \n+    # setup\n+    if not (len(samples) == len(isnvs) == len(assemblies)):\n+        raise LookupError(\"samples, isnvs, and assemblies must have the same number of elements\")\n+    samp_to_fasta = dict(zip(samples, assemblies))\n+    samp_to_isnv = dict(zip(samples, isnvs))\n+    samp_to_cmap = dict((s, CoordMapper(genome, refFasta))\n+        for s, genome in samp_to_fasta.items())\n+    with open(refFasta, 'rU') as inf:\n+        ref_chrlens = list((seq.id, len(seq)) for seq in Bio.SeqIO.parse(inf, 'fasta'))\n+    \n+    if outVcf.endswith('.vcf.gz'):\n+        tmpVcf = util.file.mkstempfname('.vcf')\n+    elif outVcf.endswith('.vcf'):\n+        tmpVcf = outVcf\n+    else:\n+        raise ValueError(\"outVcf must end in .vcf or .vcf.gz\")\n+    \n+    with open(tmpVcf, 'wt') as outf:\n+    \n+        # write header\n         outf.write('##fileformat=VCFv4.1\\n')\n         outf.write('##FORMAT=<ID=GT,Number=1,Type=String,Description=\"Genotype\">\\n')\n         outf.write('##FORMAT=<ID=AF,Number=A,Type=Float,Description=\"Allele Frequency\">\\n')\n-        outf.write('##contig=<ID=%s,length=%d>\\n' % (ref.id, len(ref)))\n+        for c, clen in ref_chrlens:\n+            outf.write('##contig=<ID=%s,length=%d>\\n' % (c, clen))\n         outf.write('##reference=file://%s\\n' % refFasta)\n         header = ['CHROM','POS','ID','REF','ALT','QUAL','FILTER','INFO','FORMAT'] + samples\n         outf.write('#'+'\\t'.join(header)+'\\n')\n \n-        # read in iSNVs and group rows based on unique position\n-\n-        data = sorted(map(reposition_vphaser_deletions, map(pos_to_number, util.file.read_tabfile_dict(inFile))), key=lambda row: row['pos'])\n-        for pos, rows in itertools.groupby(data, lambda row: row['pos']):\n-            # get the set of alleles seen per patient\n-            rows = [(row['patient'], [row[h].split(':') for h in ('ct_1','ct_2','ct_3','ct_4','extra1','extra2') if row.get(h)]) for row in rows]\n-            # convert (allele, forward count, reverse count) tuples from strings to ints\n-            rows = [(s,[(a,int(f),int(r)) for a,f,r in counts]) for s,counts in rows]\n-\n-            # filter based on same criteria used earlier (actually remove these calls)\n-            rows = [(s, list([(a,f,r) for a,f,r in counts if f>=5 and r>=5 and 10>=(float(f)/r)>=0.1]))\n-                for s,counts in rows]\n-\n-            # remove patients where no internal variation exists anymore\n-            # remove (skip) positions where no patients exist anymore\n-            dropped = set(s for s,counts in rows if len(counts)<=1)\n-            rows = [(s,counts) for s,counts in rows if s not in dropped]\n-            if not rows:\n-                log.warn(\"dropping position %d due to loss of all samples\" % pos)\n-                continue\n-            if dropped:\n-                log.warn(\"dropping samples %s at position %d due to filtered variation\" % (dropped, pos))\n-\n-            # combine fwd+rev counts and sort (allele,count) tuples in descending count order\n-            rows = [(s,list(sorted([(a,f+r) for a,f,r in counts], key=lambda a,n:n, reverse=True))) for s,counts in rows]\n-\n-            # define the length of this variation based on the largest deletion\n-            end = pos\n-            for s,counts in rows:\n-                for a,n in counts:\n-                    if a.startswith('D'):\n-                        end = max(end, pos+int(a[1:]))\n-\n-            # find reference allele and consensus alleles\n-            refAllele = str(ref[pos-1:end].seq)\n-            consAlleles = dict((s, str(aln[sample_idx_map[s]][pos-1:end].seq)) for s in samples)\n-            for s,allele in consAlleles.items():\n-                if [a for a in allele if a not in set(('A','C','T','G'))]:\n-                    log.warn(\"dropping unclean consensus for %s at %s-%s: %s\" % (s, pos, end, allele))\n-                    del consAlleles[s]\n-\n-            # define genotypes and fractions\n-            iSNVs = {}\n-            rows = dict(rows)\n-            for s in samples:\n-                if s in rows:\n-                    consAllele = consAlleles[s]\n-                    # we have iSNV data on this sample\n-                    tot_n = sum(n for a,n in rows[s])\n-                    iSNVs[s] = {}\n-                    for a,n in rows[s]:\n-                        f = float(n)/tot_n\n-                        if a.startswith('I'):\n-                            # insertion allele is first ref base, plus inserted bases, plus subsequent ref bases\n-                            a = consAllele[0] + a[1:] + consAllele[1:]\n-                        elif a.startswith('D'):\n-                            # deletion is the first ref base, plus remaining ref seq with the first few positions dropped off\n-                            a = consAllele[0] + consAllele[1+int(a[1:]):]\n-                        elif a in ('i','d'):\n-                            # this is vphaser's way of saying the \"reference\" (majority/consensus) allele, in the face of other indel variants\n-                            a = consAllele\n+        # one reference chrom at a time\n+        with open(refFasta, 'rU') as inf:\n+            for ref_sequence in Bio.SeqIO.parse(inf, 'fasta'):\n+\n+                # read in all iSNVs for this chrom and map to reference coords\n+                data = []\n+                for s in samples:\n+                    for row in util.file.read_tabfile(samp_to_isnv[s]):\n+                        s_chrom = samp_to_cmap[s].mapBtoA(ref_sequence.id)\n+                        if row[0] == s_chrom:\n+                            row = {'sample':s, 'CHROM':ref_sequence.id,\n+                                's_chrom':s_chrom, 's_pos':int(row[1]),\n+                                's_alt':row[2], 's_ref': row[3],\n+                                'n_libs':row[7], 'lib_bias': row[8],\n+                                'alleles':list(x.split(':') for x in row[9:] if x)}\n+                            # make a sorted allele list\n+                            row['allele_counts'] = list(sorted(\n+                                [(a,int(f)+int(r)) for a,f,r in row['alleles']],\n+                                key=(lambda x:x[1]), reverse=True))\n+                            # reposition vphaser deletions minus one to be consistent with\n+                            # VCF conventions\n+                            if row['s_alt'].startswith('D'):\n+                                for a,n in row['allele_counts']:\n+                                    assert a[0] in ('D','i')\n+                                row['s_pos'] = row['s_pos']-1\n+                            # map position back to reference coordinates\n+                            row['POS'] = samp_to_cmap[s].mapAtoB(s_chrom, row['s_pos'], side = -1)[1]\n+                            row['END'] = samp_to_cmap[s].mapAtoB(s_chrom, row['s_pos'], side = 1)[1]\n+                            data.append(row)\n+            \n+                # sort all iSNVs (across all samples) and group by position\n+                data = sorted(data, key=(lambda row: row['POS']))\n+                data = itertools.groupby(data, lambda row: row['POS'])\n+            \n+                # process one reference position at a time\n+                for pos, rows in data:","path":"intrahost.py","position":263,"original_position":263,"commit_id":"1fbae4d33fc4422b6fc8fe0eed4847ffbc93eaa7","original_commit_id":"1fbae4d33fc4422b6fc8fe0eed4847ffbc93eaa7","user":{"login":"dpark01","id":8513746,"avatar_url":"https://avatars.githubusercontent.com/u/8513746?v=3","gravatar_id":"","url":"https://api.github.com/users/dpark01","html_url":"https://github.com/dpark01","followers_url":"https://api.github.com/users/dpark01/followers","following_url":"https://api.github.com/users/dpark01/following{/other_user}","gists_url":"https://api.github.com/users/dpark01/gists{/gist_id}","starred_url":"https://api.github.com/users/dpark01/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dpark01/subscriptions","organizations_url":"https://api.github.com/users/dpark01/orgs","repos_url":"https://api.github.com/users/dpark01/repos","events_url":"https://api.github.com/users/dpark01/events{/privacy}","received_events_url":"https://api.github.com/users/dpark01/received_events","type":"User","site_admin":false},"body":"So, in practice, very few, if any, callers will correctly handle this, and also, the GATK IndelRealigner (which we call prior to V-Phaser) should try to minimize the real-life scenarios in which we might encounter something like this.  Currently, this code does not attempt to do anything with this, and they are reported on independently.\r\n\r\nHowever, one could conceivably replace the itertools.groupby line with something that does some sort of overlapping intervals function on the POS-END interval (perhaps using an R-Tree for optimal implementation). That would solve everything actually, the rest of the downstream code should merge everything smartly.\r\n\r\nI'm not sure how much to worry about this scenario though. It wouldn't be hard to detect the scenario and push a log.warn if it happens.  After the groupby, everything is already sorted on POS.  After the code block that determines \"end\" based on the longest variant, we could save it in some variable that persists outside of the for loop and then at the top of the loop, if max_previous_end >= pos: log.warn(\"overlapping variants in VCF!\").","created_at":"2015-03-03T01:02:59Z","updated_at":"2015-03-03T01:02:59Z","html_url":"https://github.com/broadinstitute/viral-ngs/pull/104#discussion_r25655138","pull_request_url":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls/104","_links":{"self":{"href":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls/comments/25655138"},"html":{"href":"https://github.com/broadinstitute/viral-ngs/pull/104#discussion_r25655138"},"pull_request":{"href":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls/104"}}},"pull_request":{"url":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls/104","id":30235273,"html_url":"https://github.com/broadinstitute/viral-ngs/pull/104","diff_url":"https://github.com/broadinstitute/viral-ngs/pull/104.diff","patch_url":"https://github.com/broadinstitute/viral-ngs/pull/104.patch","issue_url":"https://api.github.com/repos/broadinstitute/viral-ngs/issues/104","number":104,"state":"open","locked":false,"title":"implement iSNV step 2 (merge to VCF)","user":{"login":"dpark01","id":8513746,"avatar_url":"https://avatars.githubusercontent.com/u/8513746?v=3","gravatar_id":"","url":"https://api.github.com/users/dpark01","html_url":"https://github.com/dpark01","followers_url":"https://api.github.com/users/dpark01/followers","following_url":"https://api.github.com/users/dpark01/following{/other_user}","gists_url":"https://api.github.com/users/dpark01/gists{/gist_id}","starred_url":"https://api.github.com/users/dpark01/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dpark01/subscriptions","organizations_url":"https://api.github.com/users/dpark01/orgs","repos_url":"https://api.github.com/users/dpark01/repos","events_url":"https://api.github.com/users/dpark01/events{/privacy}","received_events_url":"https://api.github.com/users/dpark01/received_events","type":"User","site_admin":false},"body":"closes #89 ","created_at":"2015-03-01T02:11:27Z","updated_at":"2015-03-03T01:02:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"986c68eb5ec9ad5ef696ea8326da2cb909c3c673","assignee":{"login":"iljungr","id":1295313,"avatar_url":"https://avatars.githubusercontent.com/u/1295313?v=3","gravatar_id":"","url":"https://api.github.com/users/iljungr","html_url":"https://github.com/iljungr","followers_url":"https://api.github.com/users/iljungr/followers","following_url":"https://api.github.com/users/iljungr/following{/other_user}","gists_url":"https://api.github.com/users/iljungr/gists{/gist_id}","starred_url":"https://api.github.com/users/iljungr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iljungr/subscriptions","organizations_url":"https://api.github.com/users/iljungr/orgs","repos_url":"https://api.github.com/users/iljungr/repos","events_url":"https://api.github.com/users/iljungr/events{/privacy}","received_events_url":"https://api.github.com/users/iljungr/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls/104/commits","review_comments_url":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls/104/comments","review_comment_url":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/broadinstitute/viral-ngs/issues/104/comments","statuses_url":"https://api.github.com/repos/broadinstitute/viral-ngs/statuses/1fbae4d33fc4422b6fc8fe0eed4847ffbc93eaa7","head":{"label":"broadinstitute:dp-89-isnv-merge","ref":"dp-89-isnv-merge","sha":"1fbae4d33fc4422b6fc8fe0eed4847ffbc93eaa7","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":24471201,"name":"viral-ngs","full_name":"broadinstitute/viral-ngs","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/viral-ngs","description":"Viral genomics analysis pipelines","fork":false,"url":"https://api.github.com/repos/broadinstitute/viral-ngs","forks_url":"https://api.github.com/repos/broadinstitute/viral-ngs/forks","keys_url":"https://api.github.com/repos/broadinstitute/viral-ngs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/broadinstitute/viral-ngs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/broadinstitute/viral-ngs/teams","hooks_url":"https://api.github.com/repos/broadinstitute/viral-ngs/hooks","issue_events_url":"https://api.github.com/repos/broadinstitute/viral-ngs/issues/events{/number}","events_url":"https://api.github.com/repos/broadinstitute/viral-ngs/events","assignees_url":"https://api.github.com/repos/broadinstitute/viral-ngs/assignees{/user}","branches_url":"https://api.github.com/repos/broadinstitute/viral-ngs/branches{/branch}","tags_url":"https://api.github.com/repos/broadinstitute/viral-ngs/tags","blobs_url":"https://api.github.com/repos/broadinstitute/viral-ngs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/broadinstitute/viral-ngs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/broadinstitute/viral-ngs/git/refs{/sha}","trees_url":"https://api.github.com/repos/broadinstitute/viral-ngs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/broadinstitute/viral-ngs/statuses/{sha}","languages_url":"https://api.github.com/repos/broadinstitute/viral-ngs/languages","stargazers_url":"https://api.github.com/repos/broadinstitute/viral-ngs/stargazers","contributors_url":"https://api.github.com/repos/broadinstitute/viral-ngs/contributors","subscribers_url":"https://api.github.com/repos/broadinstitute/viral-ngs/subscribers","subscription_url":"https://api.github.com/repos/broadinstitute/viral-ngs/subscription","commits_url":"https://api.github.com/repos/broadinstitute/viral-ngs/commits{/sha}","git_commits_url":"https://api.github.com/repos/broadinstitute/viral-ngs/git/commits{/sha}","comments_url":"https://api.github.com/repos/broadinstitute/viral-ngs/comments{/number}","issue_comment_url":"https://api.github.com/repos/broadinstitute/viral-ngs/issues/comments{/number}","contents_url":"https://api.github.com/repos/broadinstitute/viral-ngs/contents/{+path}","compare_url":"https://api.github.com/repos/broadinstitute/viral-ngs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/broadinstitute/viral-ngs/merges","archive_url":"https://api.github.com/repos/broadinstitute/viral-ngs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/broadinstitute/viral-ngs/downloads","issues_url":"https://api.github.com/repos/broadinstitute/viral-ngs/issues{/number}","pulls_url":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls{/number}","milestones_url":"https://api.github.com/repos/broadinstitute/viral-ngs/milestones{/number}","notifications_url":"https://api.github.com/repos/broadinstitute/viral-ngs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/broadinstitute/viral-ngs/labels{/name}","releases_url":"https://api.github.com/repos/broadinstitute/viral-ngs/releases{/id}","created_at":"2014-09-25T19:00:24Z","updated_at":"2015-02-28T19:34:39Z","pushed_at":"2015-03-02T15:26:12Z","git_url":"git://github.com/broadinstitute/viral-ngs.git","ssh_url":"git@github.com:broadinstitute/viral-ngs.git","clone_url":"https://github.com/broadinstitute/viral-ngs.git","svn_url":"https://github.com/broadinstitute/viral-ngs","homepage":"","size":16650,"stargazers_count":5,"watchers_count":5,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":3,"mirror_url":null,"open_issues_count":9,"forks":3,"open_issues":9,"watchers":5,"default_branch":"master"}},"base":{"label":"broadinstitute:master","ref":"master","sha":"6d3ca8182d5ba773f74e5f547e7ae292701e4b56","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":24471201,"name":"viral-ngs","full_name":"broadinstitute/viral-ngs","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/viral-ngs","description":"Viral genomics analysis pipelines","fork":false,"url":"https://api.github.com/repos/broadinstitute/viral-ngs","forks_url":"https://api.github.com/repos/broadinstitute/viral-ngs/forks","keys_url":"https://api.github.com/repos/broadinstitute/viral-ngs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/broadinstitute/viral-ngs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/broadinstitute/viral-ngs/teams","hooks_url":"https://api.github.com/repos/broadinstitute/viral-ngs/hooks","issue_events_url":"https://api.github.com/repos/broadinstitute/viral-ngs/issues/events{/number}","events_url":"https://api.github.com/repos/broadinstitute/viral-ngs/events","assignees_url":"https://api.github.com/repos/broadinstitute/viral-ngs/assignees{/user}","branches_url":"https://api.github.com/repos/broadinstitute/viral-ngs/branches{/branch}","tags_url":"https://api.github.com/repos/broadinstitute/viral-ngs/tags","blobs_url":"https://api.github.com/repos/broadinstitute/viral-ngs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/broadinstitute/viral-ngs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/broadinstitute/viral-ngs/git/refs{/sha}","trees_url":"https://api.github.com/repos/broadinstitute/viral-ngs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/broadinstitute/viral-ngs/statuses/{sha}","languages_url":"https://api.github.com/repos/broadinstitute/viral-ngs/languages","stargazers_url":"https://api.github.com/repos/broadinstitute/viral-ngs/stargazers","contributors_url":"https://api.github.com/repos/broadinstitute/viral-ngs/contributors","subscribers_url":"https://api.github.com/repos/broadinstitute/viral-ngs/subscribers","subscription_url":"https://api.github.com/repos/broadinstitute/viral-ngs/subscription","commits_url":"https://api.github.com/repos/broadinstitute/viral-ngs/commits{/sha}","git_commits_url":"https://api.github.com/repos/broadinstitute/viral-ngs/git/commits{/sha}","comments_url":"https://api.github.com/repos/broadinstitute/viral-ngs/comments{/number}","issue_comment_url":"https://api.github.com/repos/broadinstitute/viral-ngs/issues/comments{/number}","contents_url":"https://api.github.com/repos/broadinstitute/viral-ngs/contents/{+path}","compare_url":"https://api.github.com/repos/broadinstitute/viral-ngs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/broadinstitute/viral-ngs/merges","archive_url":"https://api.github.com/repos/broadinstitute/viral-ngs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/broadinstitute/viral-ngs/downloads","issues_url":"https://api.github.com/repos/broadinstitute/viral-ngs/issues{/number}","pulls_url":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls{/number}","milestones_url":"https://api.github.com/repos/broadinstitute/viral-ngs/milestones{/number}","notifications_url":"https://api.github.com/repos/broadinstitute/viral-ngs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/broadinstitute/viral-ngs/labels{/name}","releases_url":"https://api.github.com/repos/broadinstitute/viral-ngs/releases{/id}","created_at":"2014-09-25T19:00:24Z","updated_at":"2015-02-28T19:34:39Z","pushed_at":"2015-03-02T15:26:12Z","git_url":"git://github.com/broadinstitute/viral-ngs.git","ssh_url":"git@github.com:broadinstitute/viral-ngs.git","clone_url":"https://github.com/broadinstitute/viral-ngs.git","svn_url":"https://github.com/broadinstitute/viral-ngs","homepage":"","size":16650,"stargazers_count":5,"watchers_count":5,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":3,"mirror_url":null,"open_issues_count":9,"forks":3,"open_issues":9,"watchers":5,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls/104"},"html":{"href":"https://github.com/broadinstitute/viral-ngs/pull/104"},"issue":{"href":"https://api.github.com/repos/broadinstitute/viral-ngs/issues/104"},"comments":{"href":"https://api.github.com/repos/broadinstitute/viral-ngs/issues/104/comments"},"review_comments":{"href":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls/104/comments"},"review_comment":{"href":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/broadinstitute/viral-ngs/pulls/104/commits"},"statuses":{"href":"https://api.github.com/repos/broadinstitute/viral-ngs/statuses/1fbae4d33fc4422b6fc8fe0eed4847ffbc93eaa7"}}}}