Repository 'jbrowse2'
hg clone https://toolshed.g2.bx.psu.edu/repos/fubar/jbrowse2

Changeset 0:d78175596286 (2024-01-08)
Next changeset 1:129adb5d10d3 (2024-01-08)
Commit message:
planemo upload for repository https://github.com/galaxyproject/tools-iuc/tree/master/tools/jbrowse2 commit cd77dffaad652cfb75b98bde5231beaa6d63cd5b-dirty
added:
Galaxy-History-jbrowse2samples.tar.gz
blastxml_to_gapped_gff3.py
convertMAF.sh
galaxyaushum.png
gff3_rebase.py
jbrowse2.py
jbrowse2.xml
macros.xml
maf2bed.pl
readme.rst
servejb2.py
static/images/bam.png
static/images/bigwig.png
static/images/blast.png
static/images/opacity.png
static/images/sections.png
static/images/styling.png
static/merlintracksamples.png
test-data/all_fasta.loc
test-data/bam/merlin-sample.bam
test-data/bam/merlin-sample.bam.bai
test-data/bam/merlin-sample.bam.gz
test-data/bed/test-3.bed
test-data/bed/test-6.bed
test-data/bw/merlin.bw
test-data/gff3/1.gff
test-data/gff3/2.gff
test-data/gff3/A.gff
test-data/gff3/B.gff
test-data/gff3/C.gff
test-data/gff3/D.gff
test-data/gff3/interpro.gff
test-data/gff3/merlin.gff3
test-data/index.html
test-data/maf/merlin.maf
test-data/merlin.fa
test-data/vcf/merlin.vcf
tstar.sh
b
diff -r 000000000000 -r d78175596286 Galaxy-History-jbrowse2samples.tar.gz
b
Binary file Galaxy-History-jbrowse2samples.tar.gz has changed
b
diff -r 000000000000 -r d78175596286 blastxml_to_gapped_gff3.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/blastxml_to_gapped_gff3.py Mon Jan 08 09:20:33 2024 +0000
[
b'@@ -0,0 +1,300 @@\n+#!/usr/bin/env python\n+import argparse\n+import copy\n+import logging\n+import re\n+import sys\n+\n+from BCBio import GFF\n+\n+logging.basicConfig(level=logging.INFO)\n+log = logging.getLogger(name="blastxml2gff3")\n+\n+__doc__ = """\n+BlastXML files, when transformed to GFF3, do not normally show gaps in the\n+blast hits. This tool aims to fill that "gap".\n+"""\n+\n+\n+def blastxml2gff3(blastxml, min_gap=3, trim=False, trim_end=False, include_seq=False):\n+    from Bio.Blast import NCBIXML\n+    from Bio.Seq import Seq\n+    from Bio.SeqRecord import SeqRecord\n+    from Bio.SeqFeature import SeqFeature, SimpleLocation\n+\n+    blast_records = NCBIXML.parse(blastxml)\n+    for idx_record, record in enumerate(blast_records):\n+        # http://www.sequenceontology.org/browser/release_2.4/term/SO:0000343\n+        match_type = {  # Currently we can only handle BLASTN, BLASTP\n+            "BLASTN": "nucleotide_match",\n+            "BLASTP": "protein_match",\n+        }.get(record.application, "match")\n+\n+        recid = record.query\n+        if " " in recid:\n+            recid = recid[0: recid.index(" ")]\n+\n+        rec = SeqRecord(Seq("ACTG"), id=recid)\n+        for idx_hit, hit in enumerate(record.alignments):\n+            for idx_hsp, hsp in enumerate(hit.hsps):\n+                qualifiers = {\n+                    "ID": "b2g.%s.%s.%s" % (idx_record, idx_hit, idx_hsp),\n+                    "source": "blast",\n+                    "score": hsp.expect,\n+                    "accession": hit.accession,\n+                    "hit_id": hit.hit_id,\n+                    "length": hit.length,\n+                    "hit_titles": hit.title.split(" >"),\n+                }\n+                if include_seq:\n+                    qualifiers.update(\n+                        {\n+                            "blast_qseq": hsp.query,\n+                            "blast_sseq": hsp.sbjct,\n+                            "blast_mseq": hsp.match,\n+                        }\n+                    )\n+\n+                for prop in (\n+                    "score",\n+                    "bits",\n+                    "identities",\n+                    "positives",\n+                    "gaps",\n+                    "align_length",\n+                    "strand",\n+                    "frame",\n+                    "query_start",\n+                    "query_end",\n+                    "sbjct_start",\n+                    "sbjct_end",\n+                ):\n+                    qualifiers["blast_" + prop] = getattr(hsp, prop, None)\n+\n+                desc = hit.title.split(" >")[0]\n+                qualifiers["description"] = desc[desc.index(" "):]\n+\n+                # This required a fair bit of sketching out/match to figure out\n+                # the first time.\n+                #\n+                # the match_start location must account for queries and\n+                # subjecst that start at locations other than 1\n+                parent_match_start = hsp.query_start - hsp.sbjct_start\n+                # The end is the start + hit.length because the match itself\n+                # may be longer than the parent feature, so we use the supplied\n+                # subject/hit length to calculate the real ending of the target\n+                # protein.\n+                parent_match_end = hsp.query_start + hit.length + hsp.query.count("-")\n+\n+                # If we trim the left end, we need to trim without losing information.\n+                used_parent_match_start = parent_match_start\n+                if trim:\n+                    if parent_match_start < 1:\n+                        used_parent_match_start = 0\n+\n+                if trim or trim_end:\n+                    if parent_match_end > hsp.query_end:\n+                        parent_match_end = hsp.query_end + 1\n+\n+                # The ``match`` feature will hold one or more ``match_part``s\n+                top_feature = SeqFeature(\n+                    SimpleLocation(used_parent_match_start, parent_match_end, strand=0),\n+        '..b'sition.start()]\n+        fm += match[prev: position.start()]\n+        fs += subject[prev: position.start()]\n+        prev = position.start() + 1\n+    fq += query[prev:]\n+    fm += match[prev:]\n+    fs += subject[prev:]\n+\n+    return (fq, fm, fs)\n+\n+\n+def generate_parts(query, match, subject, ignore_under=3):\n+    region_q = []\n+    region_m = []\n+    region_s = []\n+\n+    (query, match, subject) = __remove_query_gaps(query, match, subject)\n+\n+    region_start = -1\n+    region_end = -1\n+    mismatch_count = 0\n+    for i, (q, m, s) in enumerate(zip(query, match, subject)):\n+\n+        # If we have a match\n+        if m != " " or m == "+":\n+            if region_start == -1:\n+                region_start = i\n+                # It\'s a new region, we need to reset or it\'s pre-seeded with\n+                # spaces\n+                region_q = []\n+                region_m = []\n+                region_s = []\n+            region_end = i\n+            mismatch_count = 0\n+        else:\n+            mismatch_count += 1\n+\n+        region_q.append(q)\n+        region_m.append(m)\n+        region_s.append(s)\n+\n+        if mismatch_count >= ignore_under and region_start != -1 and region_end != -1:\n+            region_q = region_q[0:-ignore_under]\n+            region_m = region_m[0:-ignore_under]\n+            region_s = region_s[0:-ignore_under]\n+            yield region_start, region_end + 1, cigar_from_string(\n+                region_q, region_m, region_s, strict_m=True\n+            )\n+            region_q = []\n+            region_m = []\n+            region_s = []\n+\n+            region_start = -1\n+            region_end = -1\n+            mismatch_count = 0\n+\n+    yield region_start, region_end + 1, cigar_from_string(\n+        region_q, region_m, region_s, strict_m=True\n+    )\n+\n+\n+def _qms_to_matches(query, match, subject, strict_m=True):\n+    matchline = []\n+\n+    for (q, m, s) in zip(query, match, subject):\n+        ret = ""\n+\n+        if m != " " or m == "+":\n+            ret = "="\n+        elif m == " ":\n+            if q == "-":\n+                ret = "D"\n+            elif s == "-":\n+                ret = "I"\n+            else:\n+                ret = "X"\n+        else:\n+            log.warn("Bad data: \\n\\t%s\\n\\t%s\\n\\t%s\\n" % (query, match, subject))\n+\n+        if strict_m:\n+            if ret == "=" or ret == "X":\n+                ret = "M"\n+\n+        matchline.append(ret)\n+    return matchline\n+\n+\n+def _matchline_to_cigar(matchline):\n+    cigar_line = []\n+    last_char = matchline[0]\n+    count = 0\n+    for char in matchline:\n+        if char == last_char:\n+            count += 1\n+        else:\n+            cigar_line.append("%s%s" % (last_char, count))\n+            count = 1\n+        last_char = char\n+    cigar_line.append("%s%s" % (last_char, count))\n+    return " ".join(cigar_line)\n+\n+\n+def cigar_from_string(query, match, subject, strict_m=True):\n+    matchline = _qms_to_matches(query, match, subject, strict_m=strict_m)\n+    if len(matchline) > 0:\n+        return _matchline_to_cigar(matchline)\n+    else:\n+        return ""\n+\n+\n+if __name__ == "__main__":\n+    parser = argparse.ArgumentParser(\n+        description="Convert Blast XML to gapped GFF3", epilog=""\n+    )\n+    parser.add_argument(\n+        "blastxml", type=argparse.FileType("r"), help="Blast XML Output"\n+    )\n+    parser.add_argument(\n+        "--min_gap",\n+        type=int,\n+        help="Maximum gap size before generating a new match_part",\n+        default=3,\n+    )\n+    parser.add_argument(\n+        "--trim",\n+        action="store_true",\n+        help="Trim blast hits to be only as long as the parent feature",\n+    )\n+    parser.add_argument(\n+        "--trim_end", action="store_true", help="Cut blast results off at end of gene"\n+    )\n+    parser.add_argument("--include_seq", action="store_true", help="Include sequence")\n+    args = parser.parse_args()\n+\n+    for rec in blastxml2gff3(**vars(args)):\n+        if len(rec.features):\n+            GFF.write([rec], sys.stdout)\n'
b
diff -r 000000000000 -r d78175596286 convertMAF.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/convertMAF.sh Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+# https://github.com/cmdcolin/jbrowse-plugin-mafviewer/blob/master/bin/convert.sh
+#  MAF file must contain the species name and chromosome name
+#  e.g. hg38.chr1 in the sequence identifiers.
+perl $3/maf2bed.pl $2 < $1 | sort -k1,1 -k2,2n > $4.sorted.bed
+bgzip $4.sorted.bed
+tabix -p bed $4.sorted.bed.gz
b
diff -r 000000000000 -r d78175596286 galaxyaushum.png
b
Binary file galaxyaushum.png has changed
b
diff -r 000000000000 -r d78175596286 gff3_rebase.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gff3_rebase.py Mon Jan 08 09:20:33 2024 +0000
[
b'@@ -0,0 +1,209 @@\n+#!/usr/bin/env python\n+import argparse\n+import copy\n+import logging\n+import sys\n+\n+from BCBio import GFF\n+from Bio.SeqFeature import FeatureLocation\n+\n+logging.basicConfig(level=logging.INFO)\n+log = logging.getLogger(__name__)\n+\n+__author__ = "Eric Rasche"\n+__version__ = "0.4.0"\n+__maintainer__ = "Eric Rasche"\n+__email__ = "esr@tamu.edu"\n+\n+\n+def feature_lambda(feature_list, test, test_kwargs, subfeatures=True):\n+    """Recursively search through features, testing each with a test function, yielding matches.\n+\n+    GFF3 is a hierachical data structure, so we need to be able to recursively\n+    search through features. E.g. if you\'re looking for a feature with\n+    ID=\'bob.42\', you can\'t just do a simple list comprehension with a test\n+    case. You don\'t know how deeply burried bob.42 will be in the feature tree. This is where feature_lambda steps in.\n+\n+    :type feature_list: list\n+    :param feature_list: an iterable of features\n+\n+    :type test: function reference\n+    :param test: a closure with the method signature (feature, **kwargs) where\n+                 the kwargs are those passed in the next argument. This\n+                 function should return True or False, True if the feature is\n+                 to be yielded as part of the main feature_lambda function, or\n+                 False if it is to be ignored. This function CAN mutate the\n+                 features passed to it (think "apply").\n+\n+    :type test_kwargs: dictionary\n+    :param test_kwargs: kwargs to pass to your closure when it is called.\n+\n+    :type subfeatures: boolean\n+    :param subfeatures: when a feature is matched, should just that feature be\n+                        yielded to the caller, or should the entire sub_feature\n+                        tree for that feature be included? subfeatures=True is\n+                        useful in cases such as searching for a gene feature,\n+                        and wanting to know what RBS/Shine_Dalgarno_sequences\n+                        are in the sub_feature tree (which can be accomplished\n+                        with two feature_lambda calls). subfeatures=False is\n+                        useful in cases when you want to process (and possibly\n+                        return) the entire feature tree, such as applying a\n+                        qualifier to every single feature.\n+\n+    :rtype: yielded list\n+    :return: Yields a list of matching features.\n+    """\n+    # Either the top level set of [features] or the subfeature attribute\n+    for feature in feature_list:\n+        if test(feature, **test_kwargs):\n+            if not subfeatures:\n+                feature_copy = copy.deepcopy(feature)\n+                feature_copy.sub_features = []\n+                yield feature_copy\n+            else:\n+                yield feature\n+\n+        if hasattr(feature, "sub_features"):\n+            for x in feature_lambda(\n+                feature.sub_features, test, test_kwargs, subfeatures=subfeatures\n+            ):\n+                yield x\n+\n+\n+def feature_test_qual_value(feature, **kwargs):\n+    """Test qualifier values.\n+\n+    For every feature, check that at least one value in\n+    feature.quailfiers(kwargs[\'qualifier\']) is in kwargs[\'attribute_list\']\n+    """\n+    for attribute_value in feature.qualifiers.get(kwargs["qualifier"], []):\n+        if attribute_value in kwargs["attribute_list"]:\n+            return True\n+    return False\n+\n+\n+def __get_features(child, interpro=False):\n+    child_features = {}\n+    for rec in GFF.parse(child):\n+        # Only top level\n+        for feature in rec.features:\n+            # Get the record id as parent_feature_id (since this is how it will be during remapping)\n+            parent_feature_id = rec.id\n+            # If it\'s an interpro specific gff3 file\n+            if interpro:\n+                # Then we ignore polypeptide features as they\'re useless\n+                if feature.type == "polypeptide":\n+                    continue\n+        '..b'ale for this, removing.\n+                # if \'_\' in parent_feature_id:\n+                # parent_feature_id = parent_feature_id[parent_feature_id.index(\'_\') + 1:]\n+\n+            try:\n+                child_features[parent_feature_id].append(feature)\n+            except KeyError:\n+                child_features[parent_feature_id] = [feature]\n+            # Keep a list of feature objects keyed by parent record id\n+    return child_features\n+\n+\n+def __update_feature_location(feature, parent, protein2dna):\n+    start = feature.location.start\n+    end = feature.location.end\n+    if protein2dna:\n+        start *= 3\n+        end *= 3\n+\n+    if parent.location.strand >= 0:\n+        ns = parent.location.start + start\n+        ne = parent.location.start + end\n+        st = +1\n+    else:\n+        ns = parent.location.end - end\n+        ne = parent.location.end - start\n+        st = -1\n+\n+    # Don\'t let start/stops be less than zero. It\'s technically valid for them\n+    # to be (at least in the model I\'m working with) but it causes numerous\n+    # issues.\n+    #\n+    # Instead, we\'ll replace with %3 to try and keep it in the same reading\n+    # frame that it should be in.\n+    if ns < 0:\n+        ns %= 3\n+    if ne < 0:\n+        ne %= 3\n+\n+    feature.location = FeatureLocation(ns, ne, strand=st)\n+\n+    if hasattr(feature, "sub_features"):\n+        for subfeature in feature.sub_features:\n+            __update_feature_location(subfeature, parent, protein2dna)\n+\n+\n+def rebase(parent, child, interpro=False, protein2dna=False, map_by="ID"):\n+    # get all of the features we will be re-mapping in a dictionary, keyed by parent feature ID\n+    child_features = __get_features(child, interpro=interpro)\n+\n+    for rec in GFF.parse(parent):\n+        replacement_features = []\n+        for feature in feature_lambda(\n+            rec.features,\n+            # Filter features in the parent genome by those that are\n+            # "interesting", i.e. have results in child_features array.\n+            # Probably an unnecessary optimisation.\n+            feature_test_qual_value,\n+            {\n+                "qualifier": map_by,\n+                "attribute_list": child_features.keys(),\n+            },\n+            subfeatures=False,\n+        ):\n+\n+            # Features which will be re-mapped\n+            to_remap = child_features[feature.id]\n+            # TODO: update starts\n+            fixed_features = []\n+            for x in to_remap:\n+                # Then update the location of the actual feature\n+                __update_feature_location(x, feature, protein2dna)\n+\n+                if interpro:\n+                    for y in ("status", "Target"):\n+                        try:\n+                            del x.qualifiers[y]\n+                        except Exception:\n+                            pass\n+\n+                fixed_features.append(x)\n+            replacement_features.extend(fixed_features)\n+        # We do this so we don\'t include the original set of features that we\n+        # were rebasing against in our result.\n+        rec.features = replacement_features\n+        rec.annotations = {}\n+        GFF.write([rec], sys.stdout)\n+\n+\n+if __name__ == "__main__":\n+    parser = argparse.ArgumentParser(\n+        description="rebase gff3 features against parent locations", epilog=""\n+    )\n+    parser.add_argument(\n+        "parent", type=argparse.FileType("r"), help="Parent GFF3 annotations"\n+    )\n+    parser.add_argument(\n+        "child",\n+        type=argparse.FileType("r"),\n+        help="Child GFF3 annotations to rebase against parent",\n+    )\n+    parser.add_argument(\n+        "--interpro", action="store_true", help="Interpro specific modifications"\n+    )\n+    parser.add_argument(\n+        "--protein2dna",\n+        action="store_true",\n+        help="Map protein translated results to original DNA data",\n+    )\n+    parser.add_argument("--map_by", help="Map by key", default="ID")\n+    args = parser.parse_args()\n+    rebase(**vars(args))\n'
b
diff -r 000000000000 -r d78175596286 jbrowse2.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jbrowse2.py Mon Jan 08 09:20:33 2024 +0000
[
b'@@ -0,0 +1,1445 @@\n+#!/usr/bin/env python\n+# change to accumulating all configuration for config.json based on the default from the clone\n+import argparse\n+import binascii\n+import datetime\n+import hashlib\n+import json\n+import logging\n+import os\n+import re\n+import shutil\n+import struct\n+import subprocess\n+import tempfile\n+import xml.etree.ElementTree as ET\n+from collections import defaultdict\n+\n+logging.basicConfig(level=logging.INFO)\n+log = logging.getLogger("jbrowse")\n+TODAY = datetime.datetime.now().strftime("%Y-%m-%d")\n+GALAXY_INFRASTRUCTURE_URL = None\n+mapped_chars = {\n+    ">": "__gt__",\n+    "<": "__lt__",\n+    "\'": "__sq__",\n+    \'"\': "__dq__",\n+    "[": "__ob__",\n+    "]": "__cb__",\n+    "{": "__oc__",\n+    "}": "__cc__",\n+    "@": "__at__",\n+    "#": "__pd__",\n+    "": "__cn__",\n+}\n+\n+\n+class ColorScaling(object):\n+\n+    COLOR_FUNCTION_TEMPLATE = """\n+    function(feature, variableName, glyphObject, track) {{\n+        var score = {score};\n+        {opacity}\n+        return \'rgba({red}, {green}, {blue}, \' + opacity + \')\';\n+    }}\n+    """\n+\n+    COLOR_FUNCTION_TEMPLATE_QUAL = r"""\n+    function(feature, variableName, glyphObject, track) {{\n+        var search_up = function self(sf, attr){{\n+            if(sf.get(attr) !== undefined){{\n+                return sf.get(attr);\n+            }}\n+            if(sf.parent() === undefined) {{\n+                return;\n+            }}else{{\n+                return self(sf.parent(), attr);\n+            }}\n+        }};\n+\n+        var search_down = function self(sf, attr){{\n+            if(sf.get(attr) !== undefined){{\n+                return sf.get(attr);\n+            }}\n+            if(sf.children() === undefined) {{\n+                return;\n+            }}else{{\n+                var kids = sf.children();\n+                for(var child_idx in kids){{\n+                    var x = self(kids[child_idx], attr);\n+                    if(x !== undefined){{\n+                        return x;\n+                    }}\n+                }}\n+                return;\n+            }}\n+        }};\n+\n+        var color = ({user_spec_color} || search_up(feature, \'color\') || search_down(feature, \'color\') || {auto_gen_color});\n+        var score = (search_up(feature, \'score\') || search_down(feature, \'score\'));\n+        {opacity}\n+        if(score === undefined){{ opacity = 1; }}\n+        var result = /^#?([a-f\\d]{{2}})([a-f\\d]{{2}})([a-f\\d]{{2}})$/i.exec(color);\n+        var red = parseInt(result[1], 16);\n+        var green = parseInt(result[2], 16);\n+        var blue = parseInt(result[3], 16);\n+        if(isNaN(opacity) || opacity < 0){{ opacity = 0; }}\n+        return \'rgba(\' + red + \',\' + green + \',\' + blue + \',\' + opacity + \')\';\n+    }}\n+    """\n+\n+    OPACITY_MATH = {\n+        "linear": """\n+            var opacity = (score - ({min})) / (({max}) - ({min}));\n+        """,\n+        "logarithmic": """\n+            var opacity = Math.log10(score - ({min})) / Math.log10(({max}) - ({min}));\n+        """,\n+        "blast": """\n+            var opacity = 0;\n+            if(score == 0.0) {{\n+                opacity = 1;\n+            }} else {{\n+                opacity = (20 - Math.log10(score)) / 180;\n+            }}\n+        """,\n+    }\n+\n+    BREWER_COLOUR_IDX = 0\n+    BREWER_COLOUR_SCHEMES = [\n+        (166, 206, 227),\n+        (31, 120, 180),\n+        (178, 223, 138),\n+        (51, 160, 44),\n+        (251, 154, 153),\n+        (227, 26, 28),\n+        (253, 191, 111),\n+        (255, 127, 0),\n+        (202, 178, 214),\n+        (106, 61, 154),\n+        (255, 255, 153),\n+        (177, 89, 40),\n+        (228, 26, 28),\n+        (55, 126, 184),\n+        (77, 175, 74),\n+        (152, 78, 163),\n+        (255, 127, 0),\n+    ]\n+\n+    BREWER_DIVERGING_PALLETES = {\n+        "BrBg": ("#543005", "#003c30"),\n+        "PiYg": ("#8e0152", "#276419"),\n+        "PRGn": ("#40004b", "#00441b"),\n+        "PuOr": ("#7f3b08", "#2d004b"),\n+        "RdBu": ("#67001f", "#053061"),\n+        "RdGy": ("#67001f", "#1a1a1a"),\n+        '..b'= metadata["dataset_id"]\n+                        track_conf["trackfiles"].append(\n+                            (\n+                                os.path.realpath(x.attrib["path"]),\n+                                x.attrib["ext"],\n+                                x.attrib["label"],\n+                                metadata,\n+                            )\n+                        )\n+        else:\n+            # For tracks without files (rest, sparql)\n+            track_conf["trackfiles"].append(\n+                (\n+                    "",  # N/A, no path for rest or sparql\n+                    track.attrib["format"],\n+                    track.find("options/label").text,\n+                    {},\n+                )\n+            )\n+\n+        if is_multi_bigwig:\n+            metadata = metadata_from_node(x.find("metadata"))\n+\n+            track_conf["trackfiles"].append(\n+                (\n+                    multi_bigwig_paths,  # Passing an array of paths to represent as one track\n+                    "bigwig_multiple",\n+                    "MultiBigWig",  # Giving an hardcoded name for now\n+                    {},  # No metadata for multiple bigwig\n+                )\n+            )\n+\n+        track_conf["category"] = track.attrib["cat"]\n+        track_conf["format"] = track.attrib["format"]\n+        track_conf["style"] = {\n+            item.tag: parse_style_conf(item) for item in track.find("options/style")\n+        }\n+\n+        track_conf["style"] = {\n+            item.tag: parse_style_conf(item) for item in track.find("options/style")\n+        }\n+\n+        track_conf["style_labels"] = {\n+            item.tag: parse_style_conf(item)\n+            for item in track.find("options/style_labels")\n+        }\n+\n+        track_conf["conf"] = etree_to_dict(track.find("options"))\n+        keys = jc.process_annotations(track_conf)\n+\n+        if keys:\n+            for key in keys:\n+                default_session_data["visibility"][\n+                    track.attrib.get("visibility", "default_off")\n+                ].append(key)\n+                default_session_data["style"][key] = track_conf[\n+                    "style"\n+                ]  # TODO do we need this anymore?\n+                default_session_data["style_labels"][key] = track_conf["style_labels"]\n+\n+        default_session_data["defaultLocation"] = root.find(\n+            "metadata/general/defaultLocation"\n+        ).text\n+        default_session_data["session_name"] = root.find(\n+            "metadata/general/session_name"\n+        ).text\n+\n+        general_data = {\n+            "analytics": root.find("metadata/general/analytics").text,\n+            "primary_color": root.find("metadata/general/primary_color").text,\n+            "secondary_color": root.find("metadata/general/secondary_color").text,\n+            "tertiary_color": root.find("metadata/general/tertiary_color").text,\n+            "quaternary_color": root.find("metadata/general/quaternary_color").text,\n+            "font_size": root.find("metadata/general/font_size").text,\n+        }\n+        track_conf["category"] = track.attrib["cat"]\n+        track_conf["format"] = track.attrib["format"]\n+        try:\n+            # Only pertains to gff3 + blastxml. TODO?\n+            track_conf["style"] = {t.tag: t.text for t in track.find("options/style")}\n+        except TypeError:\n+            track_conf["style"] = {}\n+            pass\n+        track_conf["conf"] = etree_to_dict(track.find("options"))\n+        jc.add_general_configuration(general_data)\n+        print("## processed", str(track_conf), "trackIdlist", jc.trackIdlist)\n+    x = open(args.xml, "r").read()\n+    log.info(\n+        "###done processing xml=%s; trackIdlist=%s, config=%s"\n+        % (x, jc.trackIdlist, str(jc.config_json))\n+    )\n+    jc.config_json["tracks"] = jc.tracksToAdd\n+    if jc.usejson:\n+        jc.write_config()\n+    # jc.add_default_view()\n+    jc.add_default_session(default_session_data)\n+\n+    # jc.text_index() not sure what broke here.\n'
b
diff -r 000000000000 -r d78175596286 jbrowse2.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jbrowse2.xml Mon Jan 08 09:20:33 2024 +0000
[
b'@@ -0,0 +1,1062 @@\n+ <tool id="jbrowse2" name="jbrowse2" version="@TOOL_VERSION@+@WRAPPER_VERSION@" profile="22.05">\n+    <description>genome browser</description>\n+    <macros>\n+        <import>macros.xml</import>\n+    </macros>\n+    <expand macro="edamInc"/>\n+    <xrefs>\n+        <xref type="bio.tools">jbrowse2</xref>\n+    </xrefs>\n+    <expand macro="requirements"/>\n+    <version_command>python \'${__tool_directory__}/jbrowse2.py\' --version</version_command>\n+    <command detect_errors="aggressive"><![CDATA[\n+mkdir -p \'$output.files_path\' &&\n+## Copy the XML file into the directory, mostly for debugging\n+## but nice if users want to reproduce locally\n+cp \'$trackxml\' \'$output.files_path/galaxy.xml\' &&\n+python \'$__tool_directory__/jbrowse2.py\'\n+--outdir \'$output.files_path\'\n+--xml \'$trackxml\' &&\n+\n+cp \'$output.files_path/index.html\' \'$output\'\n+\n+## Ugly testing hack since I cannot get <extra_files> to test the files I want to test. Hmph.\n+#if str($uglyTestingHack) == "enabled":\n+ &&   cp \'$trackxml\' \'$output\'\n+#end if\n+  ]]></command>\n+<configfiles>\n+        <configfile name="trackxml"><![CDATA[<?xml version="1.0"?>\n+<root>\n+    <metadata>\n+        <genomes>\n+            #if str($reference_genome.genome_type_select) == "indexed":\n+              <genome path="${reference_genome.genomes.fields.path}" label="${reference_genome.genomes.fields.name}">\n+                  <metadata />\n+              </genome>s\n+            #else\n+              <genome path="$reference_genome.genome" label="${reference_genome.genome.element_identifier}">\n+                <metadata>\n+                  <dataset id="${__app__.security.encode_id($reference_genome.genome.id)}" hid="${reference_genome.genome.hid}"\n+                      size="${reference_genome.genome.get_size(nice_size=True)}"\n+                      edam_format="${reference_genome.genome.datatype.edam_format}"\n+                      file_ext="${reference_genome.genome.ext}"\n+                      dname = "${reference_genome.genome.element_identifier}" />\n+                  <history id="${__app__.security.encode_id($reference_genome.genome.history_id)}"\n+                      #if $reference_genome.genome.history.user:\n+                      user_email="${reference_genome.genome.history.user.email}"\n+                      user_id="${reference_genome.genome.history.user_id}"\n+                      display_name="${reference_genome.genome.history.get_display_name()}"/>\n+                      #else\n+                      user_email="anonymous"\n+                      user_id="-1"\n+                      display_name="Unnamed History"/>\n+                      #end if\n+                  <metadata\n+                      #for (key, value) in $reference_genome.genome.get_metadata().items():\n+                      #if "_types" not in $key:\n+                        #if isinstance($value, list):\n+                          #set value_str = "[%s]" % \',\'.join([str(val) for val in value])\n+                          ${key}="$value_str"\n+                        #else\n+                          ${key}="${value}"\n+                        #end if\n+                      #end if\n+                      #end for\n+                      />\n+                  <tool\n+                      tool_id="${reference_genome.genome.creating_job.tool_id}"\n+                      tool_version="${reference_genome.genome.creating_job.tool_version}"\n+                      />\n+                </metadata>\n+              </genome>\n+            #end if\n+        </genomes>\n+        <general>\n+            <defaultLocation>${jbgen.defaultLocation}</defaultLocation>\n+            <analytics>${jbgen.enableAnalytics}</analytics>\n+            <primary_color>${jbgen.primary_color}</primary_color>\n+            <secondary_color>${jbgen.secondary_color}</secondary_color>\n+            <tertiary_color>${jbgen.tertiary_color}</tertiary_color>\n+            <quaternary_color>${jbgen.quaternary_color}</quaternary_color>\n+            <font_size>${jbgen.font_'..b'dons for unusual genomes,\n+and detailed track styling is not yet implemented. Send code.\n+JBrowse1 development has now ceased in favour of JBrowse2.\n+\n+Use and local viewing\n+=====================\n+\n+A JBrowse2 history item can be opened by viewing it (the "eye" icon).\n+They can also be downloaded as archives ("floppy disk" icon) to share and for local viewing.\n+One extra step is required before they can be viewed. A local python web server must be started using a script included in each archive.\n+Unzip the archive (*unzip [filename].zip*) and change to the first level directory. It contains a file named "servejb2.py"\n+\n+Assuming you have python3 installed, running:\n+\n+*python3 servjb2.py*\n+\n+will serve the unarchived JBrowse2 configuration, so it can be browsed by pointing a web browser to localhost:8080\n+\n+Overview\n+--------\n+\n+JBrowse is a fast, embeddable genome browser built completely with\n+JavaScript and HTML5.\n+\n+The JBrowse-in-Galaxy (JiG) tool was written to help build complex\n+JBrowse installations straight from Galaxy, taking advantage of the\n+latest Galaxy features such as dataset collections, sections, and colour\n+pickers. It allows you to build up a JBrowse instance without worrying\n+about how to run the command line tools to format your data, and which\n+options need to be supplied and where. Additionally it comes with many\n+javascript functions to handle colouring of features which would be\n+nearly impossible to write without the assistance of this tool.\n+\n+The JBrowse-in-Galaxy tool is maintained by `the Galaxy IUC\n+<https://github.com/galaxyproject/tools-iuc/issues>`__, who you can help you\n+with missing features or bugs in the tool.\n+\n+Options\n+-------\n+\n+The first option you encounter is the **Fasta Sequence(s)**. This option\n+now accepts multiple fasta files, allowing you to build JBrowse\n+instances that contain data for multiple genomes or chrosomomes\n+(generally known as "landmark features" in gff3 terminology.)\n+\n+**Track Groups** represent a set of tracks in a single category. These\n+can be used to let your users understand relationships between large\n+groups of tracks.\n+\n+.. image:: sections.png\n+\n+Annotation Tracks\n+-----------------\n+\n+There are a few different types of tracks supported, each with their own\n+set of options:\n+\n+GFF3/BED\n+~~~~~~~~\n+\n+These are standard feature tracks. They usually highlight genes,\n+mRNAs and other features of interest along a genomic region.\n+\n+BAM Pileups\n+~~~~~~~~~~~\n+\n+We support BAM files and can automatically generate SNP tracks based on\n+that bam data.\n+\n+\n+BlastXML\n+~~~~~~~~\n+\n+.. image:: blast.png\n+\n+JiG now supports both blastn and blastp datasets. JiG internally uses a\n+blastXML to gapped GFF3 tool to convert your blastxml datasets into a\n+format amenable to visualization in JBrowse. This tool is also\n+available separately from the IUC on the toolshed.\n+\n+**Minimum Gap Size** reflects how long a gap must be before it becomes a\n+real gap in the processed gff3 file. In the picture above, various sizes\n+of gaps can be seen. If the minimum gap size was set much higher, say\n+100nt, many of the smaller gaps would disappear, and the features on\n+both sides would be merged into one, longer feature. This setting is\n+inversely proportional to runtime and output file size. *Do not set this\n+to a low value for large datasets*. By setting this number lower, you\n+will have extremely large outputs and extremely long runtimes. The\n+default was configured based off of the author\'s experience, but the\n+author only works on small viruses. It is *strongly* recommended that\n+you filter your blast results before display, e.g. picking out the top\n+10 hits or so.\n+\n+**Protein blast search** option merely informs underlying tools that\n+they should adjust feature locations by 3x.\n+\n+Bigwig XY\n+~~~~~~~~~\n+\n+.. image:: bigwig.png\n+\n+\n+\n+VCFs/SNPs\n+~~~~~~~~~\n+\n+These tracks do not support any special configuration.\n+\n+@ATTRIBUTION@\n+]]></help>\n+    <expand macro="citations"/>\n+</tool>\n'
b
diff -r 000000000000 -r d78175596286 macros.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/macros.xml Mon Jan 08 09:20:33 2024 +0000
[
b'@@ -0,0 +1,509 @@\n+<?xml version="1.0"?>\n+<macros>\n+    <token name="@TOOL_VERSION@">2.10.0</token>\n+    <xml name = "edamInc">\n+        <edam_topics>\n+            <edam_topic>topic_3307</edam_topic>\n+            <edam_topic>topic_0092</edam_topic>\n+        </edam_topics>\n+        <edam_operations>\n+            <edam_operation>operation_0573</edam_operation>\n+            <edam_operation>operation_0564</edam_operation>\n+        </edam_operations>\n+    </xml>\n+    <xml name="requirements">\n+        <requirements>\n+            <requirement type="package" version="@TOOL_VERSION@">jbrowse2</requirement>\n+            <requirement type="package" version="1.82">biopython</requirement>\n+            <requirement type="package" version="0.7.0">bcbio-gff</requirement>\n+            <requirement type="package" version="1.19">samtools</requirement>\n+            <requirement type="package" version="6.0.1">pyyaml</requirement>\n+            <requirement type="package" version="1.11">tabix</requirement>\n+            <requirement type="package" version="4.6.0">findutils</requirement>\n+            <yield/>\n+        </requirements>\n+    </xml>\n+    <token name="@DATA_DIR@">\\$GALAXY_JBROWSE_SHARED_DIR</token>\n+    <token name="@WRAPPER_VERSION@">galaxy0</token>\n+    <token name="@ATTRIBUTION@"><![CDATA[\n+**Attribution**\n+This Galaxy tool relies on the JBrowse, maintained by the GMOD Community. The Galaxy wrapper is developed by the IUC\n+This xml currently fails silently when profile=22.05 is set.\n+]]>\n+    </token>\n+    <xml name="genome_selector"\n+        token_help=""\n+        token_label="Fasta sequences"\n+        token_optional="False" >\n+        <conditional name="reference_genome">\n+            <param help="Built-in references" label="Reference genome to display" name="genome_type_select" type="select">\n+                <option selected="True" value="indexed">Use a built-in genome</option>\n+                <option value="history">Use a genome from history</option>\n+            </param>\n+            <when value="indexed">\n+                <param\n+                help="@HELP@"\n+                label="@LABEL@"\n+                name="genomes"\n+                type="select"\n+                optional="@OPTIONAL@"\n+                >\n+                    <options from_data_table="all_fasta">\n+                        <filter column="2" type="sort_by" />\n+                        <validator message="No genomes are available for the selected input dataset" type="no_options" />\n+                    </options>\n+                </param>\n+            </when>\n+            <when value="history">\n+                <param\n+                format="fasta"\n+                label="@LABEL@"\n+                help="@HELP@"\n+                name="genomes"\n+                type="data"\n+                optional="@OPTIONAL@"\n+                multiple="True" />\n+            </when>\n+        </conditional>\n+    </xml>\n+\n+    <xml name="auto_manual_tk"\n+        token_cond_label="Color"\n+        token_cond_name="color"\n+        token_select_label="Color Specification"\n+        token_select_name="color_select"\n+        token_automatic_label="Automatically selected"\n+        token_manual_label="Manual Color Selection">\n+        <conditional name="@COND_NAME@" label="@COND_LABEL@">\n+            <param type="select" label="@SELECT_LABEL@" name="@SELECT_NAME@">\n+                <option value="automatic" selected="true">@AUTOMATIC_LABEL@</option>\n+                <option value="manual">@MANUAL_LABEL@</option>\n+            </param>\n+            <when value="automatic">\n+            </when>\n+            <when value="manual">\n+                <yield />\n+            </when>\n+        </conditional>\n+    </xml>\n+\n+    <xml name="jb_color"\n+        token_label="JBrowse style.color"\n+        token_name="style_color"\n+        token_value="goldenrod"\n+        token_help="Basic color of features. Most glyphs interpret this as the fill color of the rectangle they draw. Color syntax is the same a'..b'"text"\n+                        name="menu_title"\n+                        help="Will be displayed in the popup title bar if displayed ({id}, {type}, {start}, {end}, {strand} variables will be interpreted)">\n+                    <expand macro="menu_sanitize" />\n+                </param>\n+                <param label="Menu url"\n+                        type="text"\n+                        name="menu_url"\n+                        help="Destination URL ({name}, {id}, {type}, {start}, {end}, {strand} variables will be interpreted)">\n+                    <expand macro="menu_sanitize" />\n+                </param>\n+                <param label="Menu icon"\n+                        type="select"\n+                        name="menu_icon"\n+                        help="Icon to display next to menu label">\n+                    <option value="dijitIconBookmark" selected="true">Bookmark</option>\n+                    <option value="dijitIconSave">Save</option>\n+                    <option value="dijitIconPrint">Print</option>\n+                    <option value="dijitIconCut">Cut</option>\n+                    <option value="dijitIconCopy">Copy</option>\n+                    <option value="dijitIconClear">Clear</option>\n+                    <option value="dijitIconDelete">Delete</option>\n+                    <option value="dijitIconUndo">Undo</option>\n+                    <option value="dijitIconEdit">Edit</option>\n+                    <option value="dijitIconNewTask">New Task</option>\n+                    <option value="dijitIconEditTask">Edit Task</option>\n+                    <option value="dijitIconEditProperty">Edit Property</option>\n+                    <option value="dijitIconTask">Task</option>\n+                    <option value="dijitIconFilter">Filter</option>\n+                    <option value="dijitIconConfigure">Configure</option>\n+                    <option value="dijitIconSearch">Search</option>\n+                    <option value="dijitIconApplication">Application</option>\n+                    <option value="dijitIconChart">Chart</option>\n+                    <option value="dijitIconConnector">Connector</option>\n+                    <option value="dijitIconDatabase">Database</option>\n+                    <option value="dijitIconDocuments">Documents</option>\n+                    <option value="dijitIconMail">Mail</option>\n+                    <option value="dijitLeaf">Leaf</option>\n+                    <option value="dijitIconFile">File</option>\n+                    <option value="dijitIconFunction">Function</option>\n+                    <option value="dijitIconKey">Key</option>\n+                    <option value="dijitIconPackage">Package</option>\n+                    <option value="dijitIconSample">Sample</option>\n+                    <option value="dijitIconTable">Table</option>\n+                    <option value="dijitIconUsers">Users</option>\n+                    <option value="dijitIconFolderClosed">Folder Closed</option>\n+                    <option value="dijitIconFolderOpen">Folder Open</option>\n+                    <option value="dijitIconError">Error</option>\n+                </param>\n+            </repeat>\n+        </section>\n+    </xml>\n+\n+    <xml name="menu_sanitize">\n+        <sanitizer>\n+            <valid>\n+                <add value="{"/>\n+                <add value="}"/>\n+                <add value="!"/>\n+                <add value="?"/>\n+                <add value="&amp;"/>\n+                <add value="+"/>\n+                <add value="="/>\n+                <add value="\'"/>\n+                <add value=\'"\'/>\n+            </valid>\n+        </sanitizer>\n+    </xml>\n+\n+\n+    <xml name="input_conditional" token_label="Track Data" token_format="data">\n+        <param label="@LABEL@" format="@FORMAT@" name="annotation" type="data" multiple="True"/>\n+    </xml>\n+    <xml name="citations">\n+        <citations>\n+        <citation type="doi">10.1101/gr.094607.109</citation>\n+        </citations>\n+    </xml>\n+</macros>\n'
b
diff -r 000000000000 -r d78175596286 maf2bed.pl
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/maf2bed.pl Mon Jan 08 09:20:33 2024 +0000
[
@@ -0,0 +1,46 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+
+$, = ' ';
+$\ = "\n";
+$, = "\t";
+
+my $id = 0;
+my $buffer = '';
+my $start = 0;
+my $end = 0;
+my $score = 0;
+my $chrom = '';
+
+while (<STDIN>) {
+    chomp;
+    next if /^$/;
+    my @line = split('\s+');
+    if (/^s\s+$ARGV[0]/) {
+        $chrom = $line[1];
+        $chrom =~ s/$ARGV[0]\.//;
+        $start = $line[2];
+        $end = $line[2] + $line[3];
+        s/^s //;
+        s/ +/:/g;
+        my $temp = $_;
+        $buffer = $buffer eq '' ? $temp : "$buffer,$temp";
+    }
+    elsif (/^a/) {
+        $score = +(s/^a score=//);
+        if($id > 0) {
+            print $chrom, $start, $end, "$ARGV[0]_$id", $score, $buffer;
+        }
+        $id += 1;
+        $buffer = '';
+    }
+
+    elsif (/^s/) {
+        s/^s //;
+        s/ +/:/g;
+        my $temp = $_;
+        $buffer = $buffer eq '' ? $temp : "$buffer,$temp";
+    }
+}
+print $chrom, $start, $end, "$ARGV[0]_$id", $score, $buffer;
b
diff -r 000000000000 -r d78175596286 readme.rst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/readme.rst Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,117 @@
+JBrowse2 in Galaxy
+==================
+
+    JBrowse2 is a fast, embeddable genome browser built completely with
+    JavaScript and HTML5
+
+Thus, it makes an ideal fit with Galaxy, especially for use as a
+workflow summary. E.g. annotate a genome, then visualise all of the
+associated datasets as an interactive HTML page. This tool MUST be whitelisted
+(or ``sanitize_all_html=False`` in galaxy.ini) to function correctly.
+gunicorn does not support byte range requests, so this tool must be served by nginx
+or other web server, correctly configured to support range requests.
+
+Installation
+============
+
+It is recommended to install this wrapper via the Galaxy Tool Shed.
+
+Running Locally
+===============
+
+The Galaxy tool interface writes out a xml file which is then used to generate
+the visualizations. An example used during development/testing can be seen in
+`test-data/*/test.xml`. The format is in no way rigorously defined and is
+likely to change at any time! Beware. ;)
+
+History
+=======
+
+- 2.10.0+galaxy2
+
+    - UPDATED to JBrowse 2.10.0
+    - REMOVED most colour and track control from XML and script.
+    - seems to work well with defaults.
+    - need to document and implement track settings by running the browser locally.
+    - works well enough to be useful in workflows such as TreeValGal.
+    - JB2 seems to set defaults wisely.
+    - not yet ideal for users who need fine grained track control.
+
+- 1.16.11+galaxy0
+
+    - UPDATED to JBrowse 1.16.11
+
+- 1.16.10+galaxy0
+
+    - UPDATED to JBrowse 1.16.10
+    - ADDED GALAXY_JBROWSE_SYMLINKS environment variable: if set, the tool will make symlinks to bam/bigwig files instead of copying them
+
+- 1.16.9+galaxy0
+
+    - UPDATED to JBrowse 1.16.9
+
+- 1.16.8+galaxy0
+
+    - UPDATED to JBrowse 1.16.8
+
+- 1.16.5+galaxy0
+
+    - UPDATED to JBrowse 1.16.5
+
+- 1.16.4+galaxy0
+
+    - UPDATED to JBrowse 1.16.4
+    - ADDED filter too big metadata
+    - CHANGED default value for topLevelFeatures (gene subfeatures are now inferred) and style.className (feature style was fixed)
+
+- 1.16.2+galaxy0
+
+    - UPDATED to JBrowse 1.16.2
+    - ADDED support for NeatHTMLFeatures and NeatCanvasFeatures track types
+
+- 1.16.1+galaxy0
+
+    - UPDATED to JBrowse 1.16.1
+    - ADDED support for MultiBigWig plugin
+    - ADDED support for tabix indexing of fasta and gff
+    - ADDED support for REST and SPARQL endpoints
+    - ADDED option to change chunk size for BAM tracks
+    - FIXED loading of VCF files. They were gzipped and the URLs were incorrect
+    - FIXED metadata on tracks types other than GFF+HTML
+    - FIXED infrastructure URL parsing (and embedding in links) for some tracks
+    - REMOVED support for selecting multiple genomes as input due to tracking of track metadata
+    - REMOVED support for themes as JBrowse no longer allow runtime loading of plugins
+
+- 0.7 Support for plugins (currently GC Content, Bookmarks, ComboTrackSelector),
+  track metadata
+- 0.5.2 Support for CanvasFeatures options.
+- 0.5.1 Support for contextual menus. Conda tests.
+- 0.5 Update existing instances on disk. Index names. Support HTML tracks
+  instead of Canvas. Support default tracks. General JBrowse optinos
+- 0.4 Support for dataset collections and customisation of tracks including
+  labelling, colours, styling. Added support for genetic code selection.
+  Fixed package installation recipe issues.
+- 0.3 Added support for BigWig, etc.
+- 0.2 Added support for BAM, Blast, VCF.
+- 0.1 Initial public release.
+
+Wrapper License (MIT/BSD Style)
+===============================
+
+Permission to use, copy, modify, and distribute this software and its
+documentation with or without modifications and for any purpose and
+without fee is hereby granted, provided that any copyright notices
+appear in all copies and that both those copyright notices and this
+permission notice appear in supporting documentation, and that the names
+of the contributors or copyright holders not be used in advertising or
+publicity pertaining to distribution of the software without specific
+prior permission.
+
+THE CONTRIBUTORS AND COPYRIGHT HOLDERS OF THIS SOFTWARE DISCLAIM ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
b
diff -r 000000000000 -r d78175596286 servejb2.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servejb2.py Mon Jan 08 09:20:33 2024 +0000
[
@@ -0,0 +1,159 @@
+#!/usr/bin/env python3
+
+# spec: simplest python web server with range support and multithreading that takes root path,
+# port and bind address as command line arguments; by default uses the current dir as webroot,
+# port 8000 and bind address of 0.0.0.0
+# borrowed from https://github.com/danvk/RangeHTTPServer
+# and reborrowed from https://gist.github.com/glowinthedark/b99900abe935e4ab4857314d647a9068
+
+
+import argparse
+import functools
+import os
+import re
+import socketserver
+import webbrowser
+from http.server import SimpleHTTPRequestHandler
+
+
+DEFAULT_PORT = 8080
+
+
+def copy_byte_range(infile, outfile, start=None, stop=None, bufsize=16 * 1024):
+    """Like shutil.copyfileobj, but only copy a range of the streams.
+
+    Both start and stop are inclusive.
+    """
+    if start is not None:
+        infile.seek(start)
+    while 1:
+        to_read = min(bufsize, stop + 1 - infile.tell() if stop else bufsize)
+        buf = infile.read(to_read)
+        if not buf:
+            break
+        outfile.write(buf)
+
+
+BYTE_RANGE_RE = re.compile(r"bytes=(\d+)-(\d+)?$")
+
+
+def parse_byte_range(byte_range):
+    """Returns the two numbers in 'bytes=123-456' or throws ValueError.
+
+    The last number or both numbers may be None.
+    """
+    if byte_range.strip() == "":
+        return None, None
+
+    m = BYTE_RANGE_RE.match(byte_range)
+    if not m:
+        raise ValueError("Invalid byte range %s" % byte_range)
+
+    first, last = [x and int(x) for x in m.groups()]
+    if last and last < first:
+        raise ValueError("Invalid byte range %s" % byte_range)
+    return first, last
+
+
+class RangeRequestHandler(SimpleHTTPRequestHandler):
+    """Adds support for HTTP 'Range' requests to SimpleHTTPRequestHandler
+
+    The approach is to:
+    - Override send_head to look for 'Range' and respond appropriately.
+    - Override copyfile to only transmit a range when requested.
+    """
+
+    def handle(self):
+        try:
+            SimpleHTTPRequestHandler.handle(self)
+        except Exception:
+            # ignored, thrown whenever the client aborts streaming (broken pipe)
+            pass
+
+    def send_head(self):
+        if "Range" not in self.headers:
+            self.range = None
+            return SimpleHTTPRequestHandler.send_head(self)
+        try:
+            self.range = parse_byte_range(self.headers["Range"])
+        except ValueError:
+            self.send_error(400, "Invalid byte range")
+            return None
+        first, last = self.range
+
+        # Mirroring SimpleHTTPServer.py here
+        path = self.translate_path(self.path)
+        f = None
+        ctype = self.guess_type(path)
+        try:
+            f = open(path, "rb")
+        except IOError:
+            self.send_error(404, "File not found")
+            return None
+
+        fs = os.fstat(f.fileno())
+        file_len = fs[6]
+        if first >= file_len:
+            self.send_error(416, "Requested Range Not Satisfiable")
+            return None
+
+        self.send_response(206)
+        self.send_header("Content-type", ctype)
+
+        if last is None or last >= file_len:
+            last = file_len - 1
+        response_length = last - first + 1
+
+        self.send_header("Content-Range", "bytes %s-%s/%s" % (first, last, file_len))
+        self.send_header("Content-Length", str(response_length))
+        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
+        self.end_headers()
+        return f
+
+    def end_headers(self):
+        self.send_header("Accept-Ranges", "bytes")
+        return SimpleHTTPRequestHandler.end_headers(self)
+
+    def copyfile(self, source, outputfile):
+        if not self.range:
+            return SimpleHTTPRequestHandler.copyfile(self, source, outputfile)
+
+        # SimpleHTTPRequestHandler uses shutil.copyfileobj, which doesn't let
+        # you stop the copying before the end of the file.
+        start, stop = self.range  # set in send_head()
+        copy_byte_range(source, outputfile, start, stop)
+
+
+class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
+    allow_reuse_address = True
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(
+        description="Simple Python Web Server with Range Support"
+    )
+    parser.add_argument(
+        "--root",
+        default=os.getcwd(),
+        help="Root path to serve files from (default: current working directory)",
+    )
+    parser.add_argument(
+        "--port",
+        type=int,
+        default=DEFAULT_PORT,
+        help=f"Port to listen on (default: {DEFAULT_PORT})",
+    )
+    parser.add_argument(
+        "--bind", default="0.0.0.0", help="IP address to bind to (default: 0.0.0.0)"
+    )
+    args = parser.parse_args()
+
+    handler = functools.partial(RangeRequestHandler, directory=args.root)
+
+    webbrowser.open(f"http://{args.bind}:{args.port}")
+
+    with ThreadedTCPServer((args.bind, args.port), handler) as httpd:
+        print(
+            f"Serving HTTP on {args.bind} port {args.port} (http://{args.bind}:{args.port}/)"
+        )
+        httpd.serve_forever()
b
diff -r 000000000000 -r d78175596286 static/images/bam.png
b
Binary file static/images/bam.png has changed
b
diff -r 000000000000 -r d78175596286 static/images/bigwig.png
b
Binary file static/images/bigwig.png has changed
b
diff -r 000000000000 -r d78175596286 static/images/blast.png
b
Binary file static/images/blast.png has changed
b
diff -r 000000000000 -r d78175596286 static/images/opacity.png
b
Binary file static/images/opacity.png has changed
b
diff -r 000000000000 -r d78175596286 static/images/sections.png
b
Binary file static/images/sections.png has changed
b
diff -r 000000000000 -r d78175596286 static/images/styling.png
b
Binary file static/images/styling.png has changed
b
diff -r 000000000000 -r d78175596286 static/merlintracksamples.png
b
Binary file static/merlintracksamples.png has changed
b
diff -r 000000000000 -r d78175596286 test-data/all_fasta.loc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/all_fasta.loc Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,18 @@
+#This file lists the locations and dbkeys of all the fasta files
+#under the "genome" directory (a directory that contains a directory
+#for each build). The script extract_fasta.py will generate the file
+#all_fasta.loc. This file has the format (white space characters are
+#TAB characters):
+#
+#<unique_build_id>  <dbkey> <display_name>  <file_path>
+#
+#So, all_fasta.loc could look something like this:
+#
+#apiMel3    apiMel3 Honeybee (Apis mellifera): apiMel3  /path/to/genome/apiMel3/apiMel3.fa
+#hg19canon  hg19    Human (Homo sapiens): hg19 Canonical    /path/to/genome/hg19/hg19canon.fa
+#hg19full   hg19    Human (Homo sapiens): hg19 Full /path/to/genome/hg19/hg19full.fa
+#
+#Your all_fasta.loc file should contain an entry for each individual
+#fasta file. So there will be multiple fasta files for each build,
+#such as with hg19 above.
+#
b
diff -r 000000000000 -r d78175596286 test-data/bam/merlin-sample.bam
b
Binary file test-data/bam/merlin-sample.bam has changed
b
diff -r 000000000000 -r d78175596286 test-data/bam/merlin-sample.bam.bai
b
Binary file test-data/bam/merlin-sample.bam.bai has changed
b
diff -r 000000000000 -r d78175596286 test-data/bam/merlin-sample.bam.gz
b
Binary file test-data/bam/merlin-sample.bam.gz has changed
b
diff -r 000000000000 -r d78175596286 test-data/bed/test-3.bed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/bed/test-3.bed Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,3 @@
+Merlin 49 1452
+Merlin 1457 2557
+Merlin 2557 3630
b
diff -r 000000000000 -r d78175596286 test-data/bed/test-6.bed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/bed/test-6.bed Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,3 @@
+Merlin 49 1452 chromosomal_replication_initiator_protein_DnaA 0 +
+Merlin 1457 2557 DNA_polymerase_III_subunit_beta 0 +
+Merlin 2557 3630 DNA_replication_and_repair_protein_RecF 0 +
b
diff -r 000000000000 -r d78175596286 test-data/bw/merlin.bw
b
Binary file test-data/bw/merlin.bw has changed
b
diff -r 000000000000 -r d78175596286 test-data/gff3/1.gff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/gff3/1.gff Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,46 @@
+##gff-version 3
+##sequence-region Merlin 1 172788
+Merlin GeneMark.hmm gene 10 30 . + . ID=Merlin_1;seqid=Merlin
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_1_mRNA;Parent=Merlin_1
+Merlin GeneMark.hmm CDS 14 20 1000 + 0 ID=Merlin_1_CDS ;Parent=Merlin_1_mRNA
+Merlin GeneMark.hmm CDS 24 30 500 + 0 ID=Merlin_1_CDS ;Parent=Merlin_1_mRNA
+
+Merlin GeneMark.hmm gene 14 30 . + . ID=Merlin_2;seqid=Merlin;color=#00ff00
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_2_mRNA;seqid=Merlin;color=#00ff00;Parent=Merlin_2
+Merlin GeneMark.hmm CDS 14 20 500 + 0 ID=Merlin_2_CDS ;Parent=Merlin_2_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 24 30 750 + 0 ID=Merlin_2_CDS ;Parent=Merlin_2_mRNA;color=#00ff00
+
+Merlin GeneMark.hmm gene 10 30 . + . ID=Merlin_3;seqid=Merlin
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_3A_mRNA;Parent=Merlin_3;color=#0000ff
+Merlin GeneMark.hmm CDS 14 18 1000 + 0 ID=Merlin_3A_CDS ;Parent=Merlin_3A_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 20 30 800 + 0 ID=Merlin_3A_CDS ;Parent=Merlin_3A_mRNA;color=#0000ff
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_3B_mRNA;Parent=Merlin_3;color=#0000ff
+Merlin GeneMark.hmm CDS 14 22 400 + 0 ID=Merlin_3B_CDS ;Parent=Merlin_3B_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 24 30 1000 + 0 ID=Merlin_3B_CDS ;Parent=Merlin_3B_mRNA;color=#0000ff
+
+
+
+Merlin exonerate gene 1740 2300 . + . Name=Apple3;Note=Gene with two splicing models;ID=1
+Merlin exonerate mRNA 1740 2300 . + . Name=Apple3-a;Note=mRNA A with both CDSs and UTRs;ID=1A;Parent=1;
+Merlin exonerate UTR 1740 1799 . + . Parent=1A
+Merlin exonerate CDS 1900 2080 . + 0 Parent=1A
+Merlin exonerate CDS 2100 2120 . + 2 Parent=1A
+Merlin exonerate UTR 2120 2300 . + . Parent=1A
+Merlin exonerate mRNA 1740 2300 . + . Name=Apple3-b;Note=mRNA B with both CDSs and UTRs;ID=1B;Parent=1;
+Merlin exonerate UTR 1740 1799 . + . Parent=1B
+Merlin exonerate CDS 1800 1880 . + 0 Parent=1B
+Merlin exonerate CDS 1900 1950 . + 1 Parent=1B
+Merlin exonerate CDS 2100 2120 . + 2 Parent=1B
+Merlin exonerate UTR 2120 2300 . + . Parent=1B
+
+
+
+#    {
+#    "baseUrl": "http://localhost:8000/out/data/"
+#    "compress": 0,
+#    "label": "Transcript",
+#    "storeClass": "JBrowse/Store/SeqFeature/NCList",
+#    "trackType": "JBrowse/View/Track/CanvasFeatures",
+#    "type": "JBrowse/View/Track/CanvasFeatures",
+#    "urlTemplate": "tracks/42ff9cb16c0509f0abb4a76ce14077bc_0/{refseq}/trackData.json",
+#    }
b
diff -r 000000000000 -r d78175596286 test-data/gff3/2.gff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/gff3/2.gff Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,6 @@
+##gff-version 3
+##sequence-region Merlin 1 172788
+
+Merlin . cDNA_match 1200 9000 . . . ID=cDNA00001
+Merlin . match_part 1200 3200 2.2e-30 + . ID=match00002;Parent=cDNA00001;Target=Merlin 5 506;Gap=M301 D1499 M201
+Merlin . match_part 7000 9000 7.4e-32 - . ID=match00003;Parent=cDNA00001;Target=Merlin 1 502;Gap=M101 D1499 M401
b
diff -r 000000000000 -r d78175596286 test-data/gff3/A.gff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/gff3/A.gff Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,46 @@
+##gff-version 3
+##sequence-region Merlin 1 172788
+Merlin GeneMark.hmm gene 10 30 . + . ID=Merlin_1;seqid=Merlin
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_1_mRNA;Parent=Merlin_1
+Merlin GeneMark.hmm CDS 14 20 1000 + 0 ID=Merlin_1_CDS ;Parent=Merlin_1_mRNA
+Merlin GeneMark.hmm CDS 24 30 500 + 0 ID=Merlin_1_CDS ;Parent=Merlin_1_mRNA
+
+Merlin GeneMark.hmm gene 14 30 . + . ID=Merlin_2;seqid=Merlin;color=#00ff00
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_2_mRNA;seqid=Merlin;color=#00ff00;Parent=Merlin_2
+Merlin GeneMark.hmm CDS 14 20 500 + 0 ID=Merlin_2_CDS ;Parent=Merlin_2_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 24 30 750 + 0 ID=Merlin_2_CDS ;Parent=Merlin_2_mRNA;color=#00ff00
+
+Merlin GeneMark.hmm gene 10 30 . + . ID=Merlin_3;seqid=Merlin
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_3A_mRNA;Parent=Merlin_3;color=#0000ff
+Merlin GeneMark.hmm CDS 14 18 1000 + 0 ID=Merlin_3A_CDS ;Parent=Merlin_3A_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 20 30 800 + 0 ID=Merlin_3A_CDS ;Parent=Merlin_3A_mRNA;color=#0000ff
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_3B_mRNA;Parent=Merlin_3;color=#0000ff
+Merlin GeneMark.hmm CDS 14 22 400 + 0 ID=Merlin_3B_CDS ;Parent=Merlin_3B_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 24 30 1000 + 0 ID=Merlin_3B_CDS ;Parent=Merlin_3B_mRNA;color=#0000ff
+
+
+
+Merlin exonerate gene 1740 2300 . + . Name=Apple3;Note=Gene with two splicing models;ID=1
+Merlin exonerate mRNA 1740 2300 . + . Name=Apple3-a;Note=mRNA A with both CDSs and UTRs;ID=1A;Parent=1;
+Merlin exonerate UTR 1740 1799 . + . Parent=1A
+Merlin exonerate CDS 1900 2080 . + 0 Parent=1A
+Merlin exonerate CDS 2100 2120 . + 2 Parent=1A
+Merlin exonerate UTR 2120 2300 . + . Parent=1A
+Merlin exonerate mRNA 1740 2300 . + . Name=Apple3-b;Note=mRNA B with both CDSs and UTRs;ID=1B;Parent=1;
+Merlin exonerate UTR 1740 1799 . + . Parent=1B
+Merlin exonerate CDS 1800 1880 . + 0 Parent=1B
+Merlin exonerate CDS 1900 1950 . + 1 Parent=1B
+Merlin exonerate CDS 2100 2120 . + 2 Parent=1B
+Merlin exonerate UTR 2120 2300 . + . Parent=1B
+
+
+
+#    {
+#    "baseUrl": "http://localhost:8000/out/data/"
+#    "compress": 0,
+#    "label": "Transcript",
+#    "storeClass": "JBrowse/Store/SeqFeature/NCList",
+#    "trackType": "JBrowse/View/Track/CanvasFeatures",
+#    "type": "JBrowse/View/Track/CanvasFeatures",
+#    "urlTemplate": "tracks/42ff9cb16c0509f0abb4a76ce14077bc_0/{refseq}/trackData.json",
+#    }
b
diff -r 000000000000 -r d78175596286 test-data/gff3/B.gff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/gff3/B.gff Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,46 @@
+##gff-version 3
+##sequence-region Merlin 1 172788
+Merlin GeneMark.hmm gene 10 30 . + . ID=Merlin_1;seqid=Merlin
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_1_mRNA;Parent=Merlin_1
+Merlin GeneMark.hmm CDS 14 20 1000 + 0 ID=Merlin_1_CDS ;Parent=Merlin_1_mRNA
+Merlin GeneMark.hmm CDS 24 30 500 + 0 ID=Merlin_1_CDS ;Parent=Merlin_1_mRNA
+
+Merlin GeneMark.hmm gene 14 30 . + . ID=Merlin_2;seqid=Merlin;color=#00ff00
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_2_mRNA;seqid=Merlin;color=#00ff00;Parent=Merlin_2
+Merlin GeneMark.hmm CDS 14 20 500 + 0 ID=Merlin_2_CDS ;Parent=Merlin_2_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 24 30 750 + 0 ID=Merlin_2_CDS ;Parent=Merlin_2_mRNA;color=#00ff00
+
+Merlin GeneMark.hmm gene 10 30 . + . ID=Merlin_3;seqid=Merlin
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_3A_mRNA;Parent=Merlin_3;color=#0000ff
+Merlin GeneMark.hmm CDS 14 18 1000 + 0 ID=Merlin_3A_CDS ;Parent=Merlin_3A_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 20 30 800 + 0 ID=Merlin_3A_CDS ;Parent=Merlin_3A_mRNA;color=#0000ff
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_3B_mRNA;Parent=Merlin_3;color=#0000ff
+Merlin GeneMark.hmm CDS 14 22 400 + 0 ID=Merlin_3B_CDS ;Parent=Merlin_3B_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 24 30 1000 + 0 ID=Merlin_3B_CDS ;Parent=Merlin_3B_mRNA;color=#0000ff
+
+
+
+Merlin exonerate gene 1740 2300 . + . Name=Apple3;Note=Gene with two splicing models;ID=1
+Merlin exonerate mRNA 1740 2300 . + . Name=Apple3-a;Note=mRNA A with both CDSs and UTRs;ID=1A;Parent=1;
+Merlin exonerate UTR 1740 1799 . + . Parent=1A
+Merlin exonerate CDS 1900 2080 . + 0 Parent=1A
+Merlin exonerate CDS 2100 2120 . + 2 Parent=1A
+Merlin exonerate UTR 2120 2300 . + . Parent=1A
+Merlin exonerate mRNA 1740 2300 . + . Name=Apple3-b;Note=mRNA B with both CDSs and UTRs;ID=1B;Parent=1;
+Merlin exonerate UTR 1740 1799 . + . Parent=1B
+Merlin exonerate CDS 1800 1880 . + 0 Parent=1B
+Merlin exonerate CDS 1900 1950 . + 1 Parent=1B
+Merlin exonerate CDS 2100 2120 . + 2 Parent=1B
+Merlin exonerate UTR 2120 2300 . + . Parent=1B
+
+
+
+#    {
+#    "baseUrl": "http://localhost:8000/out/data/"
+#    "compress": 0,
+#    "label": "Transcript",
+#    "storeClass": "JBrowse/Store/SeqFeature/NCList",
+#    "trackType": "JBrowse/View/Track/CanvasFeatures",
+#    "type": "JBrowse/View/Track/CanvasFeatures",
+#    "urlTemplate": "tracks/42ff9cb16c0509f0abb4a76ce14077bc_0/{refseq}/trackData.json",
+#    }
b
diff -r 000000000000 -r d78175596286 test-data/gff3/C.gff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/gff3/C.gff Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,46 @@
+##gff-version 3
+##sequence-region Merlin 1 172788
+Merlin GeneMark.hmm gene 10 30 . + . ID=Merlin_1;seqid=Merlin
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_1_mRNA;Parent=Merlin_1
+Merlin GeneMark.hmm CDS 14 20 1000 + 0 ID=Merlin_1_CDS ;Parent=Merlin_1_mRNA
+Merlin GeneMark.hmm CDS 24 30 500 + 0 ID=Merlin_1_CDS ;Parent=Merlin_1_mRNA
+
+Merlin GeneMark.hmm gene 14 30 . + . ID=Merlin_2;seqid=Merlin;color=#00ff00
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_2_mRNA;seqid=Merlin;color=#00ff00;Parent=Merlin_2
+Merlin GeneMark.hmm CDS 14 20 500 + 0 ID=Merlin_2_CDS ;Parent=Merlin_2_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 24 30 750 + 0 ID=Merlin_2_CDS ;Parent=Merlin_2_mRNA;color=#00ff00
+
+Merlin GeneMark.hmm gene 10 30 . + . ID=Merlin_3;seqid=Merlin
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_3A_mRNA;Parent=Merlin_3;color=#0000ff
+Merlin GeneMark.hmm CDS 14 18 1000 + 0 ID=Merlin_3A_CDS ;Parent=Merlin_3A_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 20 30 800 + 0 ID=Merlin_3A_CDS ;Parent=Merlin_3A_mRNA;color=#0000ff
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_3B_mRNA;Parent=Merlin_3;color=#0000ff
+Merlin GeneMark.hmm CDS 14 22 400 + 0 ID=Merlin_3B_CDS ;Parent=Merlin_3B_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 24 30 1000 + 0 ID=Merlin_3B_CDS ;Parent=Merlin_3B_mRNA;color=#0000ff
+
+
+
+Merlin exonerate gene 1740 2300 . + . Name=Apple3;Note=Gene with two splicing models;ID=1
+Merlin exonerate mRNA 1740 2300 . + . Name=Apple3-a;Note=mRNA A with both CDSs and UTRs;ID=1A;Parent=1;
+Merlin exonerate UTR 1740 1799 . + . Parent=1A
+Merlin exonerate CDS 1900 2080 . + 0 Parent=1A
+Merlin exonerate CDS 2100 2120 . + 2 Parent=1A
+Merlin exonerate UTR 2120 2300 . + . Parent=1A
+Merlin exonerate mRNA 1740 2300 . + . Name=Apple3-b;Note=mRNA B with both CDSs and UTRs;ID=1B;Parent=1;
+Merlin exonerate UTR 1740 1799 . + . Parent=1B
+Merlin exonerate CDS 1800 1880 . + 0 Parent=1B
+Merlin exonerate CDS 1900 1950 . + 1 Parent=1B
+Merlin exonerate CDS 2100 2120 . + 2 Parent=1B
+Merlin exonerate UTR 2120 2300 . + . Parent=1B
+
+
+
+#    {
+#    "baseUrl": "http://localhost:8000/out/data/"
+#    "compress": 0,
+#    "label": "Transcript",
+#    "storeClass": "JBrowse/Store/SeqFeature/NCList",
+#    "trackType": "JBrowse/View/Track/CanvasFeatures",
+#    "type": "JBrowse/View/Track/CanvasFeatures",
+#    "urlTemplate": "tracks/42ff9cb16c0509f0abb4a76ce14077bc_0/{refseq}/trackData.json",
+#    }
b
diff -r 000000000000 -r d78175596286 test-data/gff3/D.gff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/gff3/D.gff Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,46 @@
+##gff-version 3
+##sequence-region Merlin 1 172788
+Merlin GeneMark.hmm gene 10 30 . + . ID=Merlin_1;seqid=Merlin
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_1_mRNA;Parent=Merlin_1
+Merlin GeneMark.hmm CDS 14 20 1000 + 0 ID=Merlin_1_CDS ;Parent=Merlin_1_mRNA
+Merlin GeneMark.hmm CDS 24 30 500 + 0 ID=Merlin_1_CDS ;Parent=Merlin_1_mRNA
+
+Merlin GeneMark.hmm gene 14 30 . + . ID=Merlin_2;seqid=Merlin;color=#00ff00
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_2_mRNA;seqid=Merlin;color=#00ff00;Parent=Merlin_2
+Merlin GeneMark.hmm CDS 14 20 500 + 0 ID=Merlin_2_CDS ;Parent=Merlin_2_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 24 30 750 + 0 ID=Merlin_2_CDS ;Parent=Merlin_2_mRNA;color=#00ff00
+
+Merlin GeneMark.hmm gene 10 30 . + . ID=Merlin_3;seqid=Merlin
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_3A_mRNA;Parent=Merlin_3;color=#0000ff
+Merlin GeneMark.hmm CDS 14 18 1000 + 0 ID=Merlin_3A_CDS ;Parent=Merlin_3A_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 20 30 800 + 0 ID=Merlin_3A_CDS ;Parent=Merlin_3A_mRNA;color=#0000ff
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_3B_mRNA;Parent=Merlin_3;color=#0000ff
+Merlin GeneMark.hmm CDS 14 22 400 + 0 ID=Merlin_3B_CDS ;Parent=Merlin_3B_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS 24 30 1000 + 0 ID=Merlin_3B_CDS ;Parent=Merlin_3B_mRNA;color=#0000ff
+
+
+
+Merlin exonerate gene 1740 2300 . + . Name=Apple3;Note=Gene with two splicing models;ID=1
+Merlin exonerate mRNA 1740 2300 . + . Name=Apple3-a;Note=mRNA A with both CDSs and UTRs;ID=1A;Parent=1;
+Merlin exonerate UTR 1740 1799 . + . Parent=1A
+Merlin exonerate CDS 1900 2080 . + 0 Parent=1A
+Merlin exonerate CDS 2100 2120 . + 2 Parent=1A
+Merlin exonerate UTR 2120 2300 . + . Parent=1A
+Merlin exonerate mRNA 1740 2300 . + . Name=Apple3-b;Note=mRNA B with both CDSs and UTRs;ID=1B;Parent=1;
+Merlin exonerate UTR 1740 1799 . + . Parent=1B
+Merlin exonerate CDS 1800 1880 . + 0 Parent=1B
+Merlin exonerate CDS 1900 1950 . + 1 Parent=1B
+Merlin exonerate CDS 2100 2120 . + 2 Parent=1B
+Merlin exonerate UTR 2120 2300 . + . Parent=1B
+
+
+
+#    {
+#    "baseUrl": "http://localhost:8000/out/data/"
+#    "compress": 0,
+#    "label": "Transcript",
+#    "storeClass": "JBrowse/Store/SeqFeature/NCList",
+#    "trackType": "JBrowse/View/Track/CanvasFeatures",
+#    "type": "JBrowse/View/Track/CanvasFeatures",
+#    "urlTemplate": "tracks/42ff9cb16c0509f0abb4a76ce14077bc_0/{refseq}/trackData.json",
+#    }
b
diff -r 000000000000 -r d78175596286 test-data/gff3/interpro.gff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/gff3/interpro.gff Mon Jan 08 09:20:33 2024 +0000
b
b'@@ -0,0 +1,558 @@\n+##gff-version 3\n+##sequence-region Merlin 1 172788\n+Merlin\tannotation\tremark\t1\t172788\t.\t.\t.\tgff-version=3;sequence-region=%28%27Merlin%27%2C 0%2C 172788%29\n+Merlin\tfeature\tpolypeptide\t1\t229\t.\t+\t.\tID=Merlin_1;md5=4d58b2b569c2fe52e2945e3f6e380c48\n+Merlin\tGene3D\tprotein_match\t2\t50\t2.9E-21\t+\t.\tID=match%2477_2_50;Name=G3DSA:3.90.176.10;Target=Merlin_1 2 50;date=23-02-2015;status=T\n+Merlin\tGene3D\tprotein_match\t106\t165\t2.9E-21\t+\t.\tID=match%2477_106_165;Name=G3DSA:3.90.176.10;Target=Merlin_1 106 165;date=23-02-2015;status=T\n+Merlin\tPfam\tprotein_match\t7\t162\t1.9E-12\t+\t.\tDbxref=InterPro:IPR003540;ID=match%2478_7_162;Name=PF03496;Ontology_term=GO:0005576%22%2C%22GO:0009405;Target=Merlin_1 7 162;date=23-02-2015;signature_desc=ADP-ribosyltransferase exoenzyme;status=T\n+Merlin\tSUPERFAMILY\tprotein_match\t2\t48\t.\t+\t.\tID=match%2479_2_48;Name=SSF56399;Target=Merlin_1 2 48;date=23-02-2015;status=T\n+Merlin\tSUPERFAMILY\tprotein_match\t104\t164\t.\t+\t.\tID=match%2479_104_164;Name=SSF56399;Target=Merlin_1 104 164;date=23-02-2015;status=T\n+Merlin\tfeature\tpolypeptide\t1698\t2011\t.\t-\t.\tID=Merlin_3;md5=6b220b99a5d2dd40f55bb664a8dbdfb3\n+Merlin\tPfam\tprotein_match\t1912\t2011\t1.5E-8\t-\t.\tDbxref=InterPro:IPR010667;ID=match%24113_149_248;Name=PF06841;Ontology_term=GO:0005198;Target=Merlin_3 149 248;date=23-02-2015;signature_desc=T4-like virus tail tube protein gp19;status=T\n+Merlin\tfeature\tpolypeptide\t2716\t3066\t.\t-\t.\tID=Merlin_4;md5=bdb226d471fe35e28ce6a9ed4649a1f8\n+Merlin\tPfam\tprotein_match\t2725\t3066\t1.6E-150\t-\t.\tDbxref=InterPro:IPR024389;ID=match%24361_4_345;Name=PF11091;Target=Merlin_4 4 345;date=23-02-2015;signature_desc=Tail-tube assembly protein;status=T\n+Merlin\tfeature\tpolypeptide\t5144\t5317\t.\t-\t.\tID=Merlin_6;md5=c61e0e2dba259054b9c93fd931056fdd\n+Merlin\tPfam\tprotein_match\t5166\t5317\t1.5E-59\t-\t.\tDbxref=InterPro:IPR024342;ID=match%24360_21_172;Name=PF11110;Target=Merlin_6 21 172;date=23-02-2015;signature_desc=Baseplate hub distal subunit;status=T\n+Merlin\tfeature\tpolypeptide\t6052\t6431\t.\t-\t.\tID=Merlin_7;md5=b51a60ffef9f07b672e0d12d26d27bbc\n+Merlin\tSUPERFAMILY\tprotein_match\t6256\t6431\t.\t-\t.\tID=match%24227_199_374;Name=SSF69279;Target=Merlin_7 199 374;date=23-02-2015;status=T\n+Merlin\tSUPERFAMILY\tprotein_match\t6238\t6431\t.\t-\t.\tID=match%24228_5_198;Name=SSF69279;Target=Merlin_7 5 198;date=23-02-2015;status=T\n+Merlin\tPfam\tprotein_match\t6237\t6431\t4.3E-96\t-\t.\tDbxref=InterPro:IPR015181;ID=match%24229_4_198;Name=PF09097;Target=Merlin_7 4 198;date=23-02-2015;signature_desc=Baseplate structural protein,domain 1;status=T\n+Merlin\tGene3D\tprotein_match\t6320\t6431\t1.4E-54\t-\t.\tID=match%24230_3_114;Name=G3DSA:2.40.10.10;Target=Merlin_7 3 114;date=23-02-2015;status=T\n+Merlin\tPfam\tprotein_match\t6263\t6431\t3.9E-83\t-\t.\tDbxref=InterPro:IPR015180;ID=match%24231_201_369;Name=PF09096;Target=Merlin_7 201 369;date=23-02-2015;signature_desc=Baseplate structural protein,domain 2;status=T\n+Merlin\tfeature\tpolypeptide\t6931\t7180\t.\t-\t.\tID=Merlin_8;md5=78306f53371e5e47b051cad8a16b86e5\n+Merlin\tPfam\tprotein_match\t6985\t7180\t9.8E-56\t-\t.\tDbxref=InterPro:IPR024364;ID=match%24348_5_200;Name=PF12322;Target=Merlin_8 5 200;date=23-02-2015;signature_desc=T4 bacteriophage base plate protein;status=T\n+Merlin\tfeature\tpolypeptide\t7227\t7435\t.\t+\t.\tID=Merlin_9;md5=5ced4f78a57bd34e165ccf7b43ed3ef1\n+Merlin\tPfam\tprotein_match\t7231\t7433\t6.3E-63\t+\t.\tDbxref=InterPro:IPR024364;ID=match%24164_5_207;Name=PF12322;Target=Merlin_9 5 207;date=23-02-2015;signature_desc=T4 bacteriophage base plate protein;status=T\n+Merlin\tfeature\tpolypeptide\t7856\t7970\t.\t+\t.\tID=Merlin_10;md5=b0c491c633f373b9340ede7359636469\n+Merlin\tPfam\tprotein_match\t7863\t7956\t1.6E-17\t+\t.\tDbxref=InterPro:IPR007048;ID=match%2416_8_101;Name=PF04965;Target=Merlin_10 8 101;date=23-02-2015;signature_desc=Gene 25-like lysozyme;status=T\n+Merlin\tSUPERFAMILY\tprotein_match\t7862\t7957\t.\t+\t.\tID=match%2417_7_102;Name=SSF160719;Target=Merlin_10 7 102;date=23-02-2015;status=T\n+Merlin\tGene3D\tprotein_match\t7857\t7959\t9.3E-27\t+\t.\tDbxref=InterPro:IPR015801;ID=match%2418_2_104;N'..b'Pro:IPR023214;ID=match%24167_7_211;Name=SSF56784;Target=Merlin_302 7 211;date=23-02-2015;status=T\n+Merlin\tGene3D\tprotein_match\t166428\t166561\t5.5E-6\t+\t.\tDbxref=InterPro:IPR023214;ID=match%24168_78_211;Name=G3DSA:3.40.50.1000;Target=Merlin_302 78 211;date=23-02-2015;status=T\n+Merlin\tGene3D\tprotein_match\t166359\t166371\t5.5E-6\t+\t.\tDbxref=InterPro:IPR023214;ID=match%24168_9_21;Name=G3DSA:3.40.50.1000;Target=Merlin_302 9 21;date=23-02-2015;status=T\n+Merlin\tfeature\tpolypeptide\t167486\t167970\t.\t+\t.\tID=Merlin_304;md5=283a418fea20ac001bffdcbf72299ca8\n+Merlin\tSUPERFAMILY\tprotein_match\t167619\t167850\t.\t+\t.\tID=match%24122_134_365;Name=SSF56091;Target=Merlin_304 134 365;date=23-02-2015;status=T\n+Merlin\tGene3D\tprotein_match\t167834\t167952\t5.9E-8\t+\t.\tDbxref=InterPro:IPR012340;ID=match%24123_349_467;Name=G3DSA:2.40.50.140;Target=Merlin_304 349 467;date=23-02-2015;status=T\n+Merlin\tProSitePatterns\tprotein_match\t167827\t167850\t.\t+\t.\tDbxref=InterPro:IPR016059%22%2C%22Reactome:REACT_216;ID=match%24124_342_365;Name=PS00333;Ontology_term=GO:0003909%22%2C%22GO:0051103;Target=Merlin_304 342 365;date=23-02-2015;signature_desc=ATP-dependent DNA ligase signature 2.;status=T\n+Merlin\tPfam\tprotein_match\t167620\t167850\t9.0E-28\t+\t.\tDbxref=InterPro:IPR012310%22%2C%22Reactome:REACT_216;ID=match%24125_135_365;Name=PF01068;Ontology_term=GO:0003910%22%2C%22GO:0005524%22%2C%22GO:0006281%22%2C%22GO:0006310;Target=Merlin_304 135 365;date=23-02-2015;signature_desc=ATP dependent DNA ligase domain;status=T\n+Merlin\tProSitePatterns\tprotein_match\t167642\t167650\t.\t+\t.\tDbxref=InterPro:IPR016059%22%2C%22Reactome:REACT_216;ID=match%24126_157_165;Name=PS00697;Ontology_term=GO:0003909%22%2C%22GO:0051103;Target=Merlin_304 157 165;date=23-02-2015;signature_desc=ATP-dependent DNA ligase AMP-binding site.;status=T\n+Merlin\tGene3D\tprotein_match\t167803\t167833\t8.5E-8\t+\t.\tID=match%24127_318_348;Name=G3DSA:3.30.1490.70;Target=Merlin_304 318 348;date=23-02-2015;status=T\n+Merlin\tGene3D\tprotein_match\t167621\t167646\t8.5E-8\t+\t.\tID=match%24127_136_161;Name=G3DSA:3.30.1490.70;Target=Merlin_304 136 161;date=23-02-2015;status=T\n+Merlin\tSUPERFAMILY\tprotein_match\t167823\t167930\t.\t+\t.\tDbxref=InterPro:IPR012340;ID=match%24128_338_445;Name=SSF50249;Target=Merlin_304 338 445;date=23-02-2015;status=T\n+Merlin\tGene3D\tprotein_match\t167661\t167794\t1.2E-4\t+\t.\tID=match%24129_176_309;Name=G3DSA:3.30.470.30;Target=Merlin_304 176 309;date=23-02-2015;status=T\n+Merlin\tfeature\tpolypeptide\t169174\t169869\t.\t+\t.\tID=Merlin_306;md5=3f61e1cb18fb135a3dc061968bcd879c\n+Merlin\tSUPERFAMILY\tprotein_match\t169736\t169781\t.\t+\t.\tID=match%24253_563_608;Name=SSF56399;Target=Merlin_306 563 608;date=23-02-2015;status=T\n+Merlin\tSUPERFAMILY\tprotein_match\t169590\t169696\t.\t+\t.\tID=match%24253_417_523;Name=SSF56399;Target=Merlin_306 417 523;date=23-02-2015;status=T\n+Merlin\tPfam\tprotein_match\t169589\t169781\t1.6E-22\t+\t.\tDbxref=InterPro:IPR003540;ID=match%24254_416_608;Name=PF03496;Ontology_term=GO:0005576%22%2C%22GO:0009405;Target=Merlin_306 416 608;date=23-02-2015;signature_desc=ADP-ribosyltransferase exoenzyme;status=T\n+Merlin\tGene3D\tprotein_match\t169597\t169698\t2.1E-28\t+\t.\tID=match%24255_424_525;Name=G3DSA:3.90.176.10;Target=Merlin_306 424 525;date=23-02-2015;status=T\n+Merlin\tGene3D\tprotein_match\t169738\t169784\t2.1E-28\t+\t.\tID=match%24255_565_611;Name=G3DSA:3.90.176.10;Target=Merlin_306 565 611;date=23-02-2015;status=T\n+Merlin\tfeature\tpolypeptide\t171300\t171794\t.\t+\t.\tID=Merlin_307;md5=0f4b8b0843334ccf18e5a4a7cbdf67b2\n+Merlin\tSUPERFAMILY\tprotein_match\t171723\t171792\t.\t+\t.\tID=match%24339_424_493;Name=SSF56399;Target=Merlin_307 424 493;date=23-02-2015;status=T\n+Merlin\tGene3D\tprotein_match\t171722\t171791\t5.2E-11\t+\t.\tID=match%24340_423_492;Name=G3DSA:3.90.176.10;Target=Merlin_307 423 492;date=23-02-2015;status=T\n+Merlin\tPfam\tprotein_match\t171723\t171791\t2.0E-9\t+\t.\tDbxref=InterPro:IPR003540;ID=match%24341_424_492;Name=PF03496;Ontology_term=GO:0005576%22%2C%22GO:0009405;Target=Merlin_307 424 492;date=23-02-2015;signature_desc=ADP-ribosyltransferase exoenzyme;status=T\n'
b
diff -r 000000000000 -r d78175596286 test-data/gff3/merlin.gff3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/gff3/merlin.gff3 Mon Jan 08 09:20:33 2024 +0000
b
b'@@ -0,0 +1,1230 @@\n+##gff-version 3\n+##sequence-region Merlin 1 172788\n+Merlin  GeneMark.hmm    gene    2   691 -856.563659 +   .   ID=Merlin_1;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    2   691 .   +   .   ID=Merlin_1_mRNA;Parent=Merlin_1;seqid=Merlin;color=#00ff00\n+Merlin  GeneMark.hmm    exon    2   691 .   +   .   ID=Merlin_1_exon;Parent=Merlin_1_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 2   691 .   +   0   ID=Merlin_1_CDS;Parent=Merlin_1_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    752 1039    -339.046618 +   .   ID=Merlin_2;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    752 1039    .   +   .   ID=Merlin_2_mRNA;Parent=Merlin_2;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    752 1039    .   +   .   ID=Merlin_2_exon;Parent=Merlin_2_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 752 1039    .   +   0   ID=Merlin_2_CDS;Parent=Merlin_2_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    1067    2011    -1229.683915    -   .   ID=Merlin_3;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    1067    2011    .   -   .   ID=Merlin_3_mRNA;Parent=Merlin_3;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    1067    2011    .   -   .   ID=Merlin_3_exon;Parent=Merlin_3_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 1067    2011    .   -   0   ID=Merlin_3_CDS;Parent=Merlin_3_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    2011    3066    -1335.034872    -   .   ID=Merlin_4;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    2011    3066    .   -   .   ID=Merlin_4_mRNA;Parent=Merlin_4;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    2011    3066    .   -   .   ID=Merlin_4_exon;Parent=Merlin_4_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 2011    3066    .   -   0   ID=Merlin_4_CDS;Parent=Merlin_4_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    3066    4796    -2177.374893    -   .   ID=Merlin_5;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    3066    4796    .   -   .   ID=Merlin_5_mRNA;Parent=Merlin_5;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    3066    4796    .   -   .   ID=Merlin_5_exon;Parent=Merlin_5_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 3066    4796    .   -   0   ID=Merlin_5_CDS;Parent=Merlin_5_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    4793    5317    -682.565030 -   .   ID=Merlin_6;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    4793    5317    .   -   .   ID=Merlin_6_mRNA;Parent=Merlin_6;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    4793    5317    .   -   .   ID=Merlin_6_exon;Parent=Merlin_6_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 4793    5317    .   -   0   ID=Merlin_6_CDS;Parent=Merlin_6_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    5289    6431    -1457.525863    -   .   ID=Merlin_7;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    5289    6431    .   -   .   ID=Merlin_7_mRNA;Parent=Merlin_7;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    5289    6431    .   -   .   ID=Merlin_7_exon;Parent=Merlin_7_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 5289    6431    .   -   0   ID=Merlin_7_CDS;Parent=Merlin_7_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    6428    7180    -968.015933 -   .   ID=Merlin_8;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    6428    7180    .   -   .   ID=Merlin_8_mRNA;Parent=Merlin_8;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    6428    7180    .   -   .   ID=Merlin_8_exon;Parent=Merlin_8_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 6428    7180    .   -   0   ID=Merlin_8_CDS;Parent=Merlin_8_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    7228    7857    -809.330137 +   .   ID=Merlin_9;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    7228    7857    .   +   .   ID=Merlin_9_mRNA;Parent=Merlin_9;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    7228    7857    .   +   .   ID=Merlin_9_exon;Parent=Merlin_9_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 7228    7857    .   +   0   ID=Merlin_9_CDS;Parent=Merlin_9_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    7857    8252    -515.006678 +   .   ID=Merlin_10;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    7857    8252    .   +   .   ID=Merlin_'..b'7  165601  .   +   0   ID=Merlin_298_CDS;Parent=Merlin_298_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    165612  165773  -191.091430 +   .   ID=Merlin_299;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    165612  165773  .   +   .   ID=Merlin_299_mRNA;Parent=Merlin_299;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    165612  165773  .   +   .   ID=Merlin_299_exon;Parent=Merlin_299_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 165612  165773  .   +   0   ID=Merlin_299_CDS;Parent=Merlin_299_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    165770  166000  -285.030914 +   .   ID=Merlin_300;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    165770  166000  .   +   .   ID=Merlin_300_mRNA;Parent=Merlin_300;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    165770  166000  .   +   .   ID=Merlin_300_exon;Parent=Merlin_300_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 165770  166000  .   +   0   ID=Merlin_300_CDS;Parent=Merlin_300_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    165997  166191  -241.609251 +   .   ID=Merlin_301;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    165997  166191  .   +   .   ID=Merlin_301_mRNA;Parent=Merlin_301;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    165997  166191  .   +   .   ID=Merlin_301_exon;Parent=Merlin_301_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 165997  166191  .   +   0   ID=Merlin_301_CDS;Parent=Merlin_301_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    166352  167200  -1091.167753    +   .   ID=Merlin_302;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    166352  167200  .   +   .   ID=Merlin_302_mRNA;Parent=Merlin_302;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    166352  167200  .   +   .   ID=Merlin_302_exon;Parent=Merlin_302_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 166352  167200  .   +   0   ID=Merlin_302_CDS;Parent=Merlin_302_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    167197  167433  -294.645060 +   .   ID=Merlin_303;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    167197  167433  .   +   .   ID=Merlin_303_mRNA;Parent=Merlin_303;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    167197  167433  .   +   .   ID=Merlin_303_exon;Parent=Merlin_303_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 167197  167433  .   +   0   ID=Merlin_303_CDS;Parent=Merlin_303_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    167487  168944  -1811.170385    +   .   ID=Merlin_304;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    167487  168944  .   +   .   ID=Merlin_304_mRNA;Parent=Merlin_304;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    167487  168944  .   +   .   ID=Merlin_304_exon;Parent=Merlin_304_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 167487  168944  .   +   0   ID=Merlin_304_CDS;Parent=Merlin_304_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    168941  169120  -220.159549 +   .   ID=Merlin_305;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    168941  169120  .   +   .   ID=Merlin_305_mRNA;Parent=Merlin_305;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    168941  169120  .   +   .   ID=Merlin_305_exon;Parent=Merlin_305_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 168941  169120  .   +   0   ID=Merlin_305_CDS;Parent=Merlin_305_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    169175  171265  -2617.092758    +   .   ID=Merlin_306;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    169175  171265  .   +   .   ID=Merlin_306_mRNA;Parent=Merlin_306;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    169175  171265  .   +   .   ID=Merlin_306_exon;Parent=Merlin_306_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 169175  171265  .   +   0   ID=Merlin_306_CDS;Parent=Merlin_306_exon;seqid=Merlin\n+Merlin  GeneMark.hmm    gene    171301  172788  -1876.322043    +   .   ID=Merlin_307;seqid=Merlin\n+Merlin  GeneMark.hmm    mRNA    171301  172788  .   +   .   ID=Merlin_307_mRNA;Parent=Merlin_307;seqid=Merlin\n+Merlin  GeneMark.hmm    exon    171301  172788  .   +   .   ID=Merlin_307_exon;Parent=Merlin_307_mRNA;seqid=Merlin\n+Merlin  GeneMark.hmm    CDS 171301  172788  .   +   0   ID=Merlin_307_CDS;Parent=Merlin_307_exon;seqid=Merlin\n'
b
diff -r 000000000000 -r d78175596286 test-data/index.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/index.html Mon Jan 08 09:20:33 2024 +0000
[
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <title>JBrowse</title>
+    <link rel="stylesheet" type="text/css" href="css/genome.css">
+</head>
+<body>
+
+    <script type="text/javascript">
+            // jshint unused: false
+            var dojoConfig = {
+                async: true,
+                baseUrl: './src',
+                has: {
+                    'host-node': false // Prevent dojo from being fooled by Electron
+                }
+            };
+            // Move Electron's require out before loading Dojo
+            if(window.process&&process.versions&&process.versions.electron) {
+                window.electronRequire = require;
+                delete window.require;
+            }
+    </script>
+    <script type="text/javascript" src="src/dojo/dojo.js"></script>
+    <script type="text/javascript" src="src/JBrowse/init.js"></script>
+    <script type="text/javascript">
+        window.onerror=function(msg){
+            if( document.body )
+                document.body.setAttribute("JSError",msg);
+        }
+
+        // puts the main Browser object in this for convenience.  feel
+        // free to move it into function scope if you want to keep it
+        // out of the global namespace
+        var JBrowse;
+        require(['JBrowse/Browser', 'dojo/io-query', 'dojo/json' ],
+             function (Browser,ioQuery,JSON) {
+                   // the initial configuration of this JBrowse
+                   // instance
+
+                   // NOTE: this initial config is the same as any
+                   // other JBrowse config in any other file.  this
+                   // one just sets defaults from URL query params.
+                   // If you are embedding JBrowse in some other app,
+                   // you might as well just set this initial config
+                   // to something like { include: '../my/dynamic/conf.json' },
+                   // or you could put the entire
+                   // dynamically-generated JBrowse config here.
+
+                   // parse the query vars in the page URL
+                   var queryParams = ioQuery.queryToObject( window.location.search.slice(1) );
+
+                   var config = {
+                       containerID: "GenomeBrowser",
+
+                       dataRoot: queryParams.data,
+                       queryParams: queryParams,
+                       location: queryParams.loc,
+                       forceTracks: queryParams.tracks,
+                       initialHighlight: queryParams.highlight,
+                       show_nav: queryParams.nav,
+                       show_tracklist: queryParams.tracklist,
+                       show_overview: queryParams.overview,
+                       show_menu: queryParams.menu,
+                       show_tracklabels: queryParams.tracklabels,
+                       highResolutionMode: queryParams.highres,
+                       stores: { url: { type: "JBrowse/Store/SeqFeature/FromConfig", features: [] } },
+                       makeFullViewURL: function( browser ) {
+
+                           // the URL for the 'Full view' link
+                           // in embedded mode should be the current
+                           // view URL, except with 'nav', 'tracklist',
+                           // and 'overview' parameters forced to 1.
+
+                           return browser.makeCurrentViewURL({ nav: 1, tracklist: 1, overview: 1 });
+                       },
+                       updateBrowserURL: true
+                   };
+
+                   //if there is ?addFeatures in the query params,
+                   //define a store for data from the URL
+                   if( queryParams.addFeatures ) {
+                       config.stores.url.features = JSON.parse( queryParams.addFeatures );
+                   }
+
+                   // if there is ?addTracks in the query params, add
+                   // those track configurations to our initial
+                   // configuration
+                   if( queryParams.addTracks ) {
+                       config.tracks = JSON.parse( queryParams.addTracks );
+                   }
+
+                   // if there is ?addStores in the query params, add
+                   // those store configurations to our initial
+                   // configuration
+                   if( queryParams.addStores ) {
+                       config.stores = JSON.parse( queryParams.addStores );
+                   }
+
+                   // create a JBrowse global variable holding the JBrowse instance
+                   JBrowse = new Browser( config );
+        });
+    </script>
+
+  </head>
+
+  <body>
+    <div id="GenomeBrowser" style="height: 100%; width: 100%; padding: 0; border: 0;"></div>
+    <div style="display: none">JBrowseDefaultMainPage</div>
+  </body>
+</html>
b
diff -r 000000000000 -r d78175596286 test-data/maf/merlin.maf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/maf/merlin.maf Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,32 @@
+##maf version=1 scoring=lastz.v1.04.22
+# lastz.v1.04.22 --strand=both --ambiguous=iupac --traceback=160M --format=maf --action:target=multiple
+#
+# hsp_threshold      = 3000
+# gapped_threshold   = 3000
+# x_drop             = 910
+# y_drop             = 9400
+# gap_open_penalty   = 400
+# gap_extend_penalty = 30
+#        A    C    G    T
+#   A   91 -114  -31 -123
+#   C -114  100 -125  -31
+#   G  -31 -125  100 -114
+#   T -123  -31 -114   91
+a score=5613
+s Merlin.Merlin 960 60 + 172788 ATTTTCTGTAGCAGTTCAAACTGTAGAAAATGATGAAGTTATTTTAACTTTACCAGCTTT
+s merlin1.Merlin   960 60 +     60 ATTTTCTGTAGCAGTTCCAAACTGTAGAAAATGATGAAGTTATTTTAACTTACCAGCTTT
+a score=5667
+s Merlin.Merlin  1020 60 + 172788 CGTAATTTTCCGCAAATAAAACAATGGGGAGCTATGCTCCCCATTTTTACAATCCAAGTA
+s merlin2.Merlin    0 60 +     60 CGTAATTTTCCGCAATAAAACAATGGGGAGCTATGCTCCCCATTTTTACAATCACAAGTA
+a score=5721
+s Merlin.Merlin  1080 60 + 172788 TTTTCGAAGTAGAGTTTCGGGTCGAATTAATGACGTGAGACAACCCTCCAGCAGCTCCTC
+s merlin3.Merlin    0 60 +     60 TTTCGAAGTAGAGTTTCGGGTCGAATTAATGACGTGAGTACAACCCTCCAGCAGCTCCTC
+a score=5613
+s Merlin.Merlin  1140 60 + 172788 CAAGTCTAGATAATCTACTTAAACTTCCATTAAGAGACATTTCACTATTAATTCCAGTTA
+s merlin4.Merlin    0 60 +     60 CAAGTCTAGGATAATCTACTTAAACTTCCATTAAAGACATTTCACTATTAATTCCAGTTA
+a score=5703
+s Merlin.Merlin  1200 60 + 172788 TAGAATTAACAGCTCTATCTTCAATCCAATCAAGAGCAGCTTGACGTCCAACAGCACCCG
+s merlin5.Merlin    0 60 +     60 TAGAATTAACAGCTCTATTCAATCCAATCCCAAGAGCAGCTTGACGTCCAACAGCACCCG
+a score=5649
+s Merlin.Merlin  1260 60 + 172788 TTTGCATTACTCTGTAAGCAAATGTAACATCGAAAACCGCAATTTGGTTATCTCCTTCAT
+s merlin6.Merlin    0 60 +     60 TTTGCATTACTCTGTAAGCAA TGTAACATCGAAAACCGCAATTATGGTTATCTCCTTCAT
b
diff -r 000000000000 -r d78175596286 test-data/merlin.fa
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/merlin.fa Mon Jan 08 09:20:33 2024 +0000
b
b'@@ -0,0 +1,2881 @@\n+>Merlin\n+TCGTTTAGACAAAGGTACATTATTGTATCGTGGCCAAAAATTAGACCTTCCTACATTCGA\n+GCATAACGCAGAGAATAAGTTGTTCTATTTCAGAAACTACGTTTCAACTTCATTAAAGCC\n+TCTGATCTTTGGTGAATTTGGTCGTATGTTTATGGCACTAGATGACGATACTACAATTTA\n+TACTGCTGAGACGCCTGATGATTATAATCGTTTCGCAAACCCAGAAGATATAATTGATAT\n+TGGCGCTACTCAAAAAGACTCATTTGACGATAACAATAATGATGGAACATCTATTAATAT\n+CGGCAAACAAGTTAATTTAGGATTCGTTATTTCCGGTGCTGAAAATGTTCGAGTTATTGT\n+TCCAGGTTCTTTAACTGAATATCCAGAAGAAGCGGAAGTTATTCTGCCTCGTGGTACTCT\n+TTTGAAGATCAATAAAATCACTACTCAAGTAGATAAACGCTCGAATAAGTTCATGGTTGA\n+AGGTTCAATCGTTCCGCCTTCTGAGCAAATTGATGAATCTGTTGAGATTTATGACGGTGA\n+TCTGTTCATGGAAACAGGTGAAGTAGTAAAACTGTCCGGATTCATGCAGTTCGTCAACGA\n+ATCTGCATACGATGAAGAGCAAAACCAGATGGCTGCTGAGATTCTGTCTGGATTCTTGGA\n+CATTGATGACATGCCACGTAAGTTCCGCTAGCCGTTTACATCCACATGGAAGTGGATTAT\n+AATGGCTCTACGTTAACAAGAGGAAAACAACATGAAATCAATTTTTCGTATCAACGGTGT\n+AGAAATTGTAGTTGAAGATGTAGTTCCTATGTCTTATGAATTCAATGAAGTTGTTTTCAA\n+AGAGCTTAAGAAAATTTTAGGCGATAAGAAGCTTCAAAGTACTCCAATTGGACGTTTTGG\n+AATGAAAGAAAACGTTGATACTTATATTGAAAGTGTAGTGACAGGGCAGTTAGAAGGTGA\n+ATTTTCTGTAGCAGTTCAAACTGTAGAAAATGATGAAGTTATTTTAACTTTACCAGCTTT\n+CGTAATTTTCCGCAAATAAAACAATGGGGAGCTATGCTCCCCATTTTTACAATCCAAGTA\n+TTTTCGAAGTAGAGTTTCGGGTCGAATTAATGACGTGAGACAACCCTCCAGCAGCTCCTC\n+CAAGTCTAGATAATCTACTTAAACTTCCATTAAGAGACATTTCACTATTAATTCCAGTTA\n+TAGAATTAACAGCTCTATCTTCAATCCAATCAAGAGCAGCTTGACGTCCAACAGCACCCG\n+TTTGCATTACTCTGTAAGCAAATGTAACATCGAAAACCGCAATTTGGTTATCTCCTTCAT\n+ATGTAAGCTCAGGAGCTCCACACGCAACAGGAACACAACCTGTGAACATTATCACAGTAT\n+GAGGTAATCCATTTCGAGCATGAAGGTTAACCTGAATGTCAGCTTCGACGTCAGTTGGTA\n+ATGCTCGCAATCCAGTAACCGGGTCTTGAACGGAGTTCACCCAATCTTGCATTGCACGAT\n+AGTTACTTGCTTCGGGATCCATTCTGAATGATATAGTTAACGGATCGAGTTCACGTCCAG\n+TTATTCTAATATTCGGTGAGTTATGGTTGAAATCCATTTCATGAGACAATCTGTTCTCTG\n+GAATTTTGACCGAATAAATCATCAATCCAGATTGCGGATAAGCCATGTTAAAGAAGTCTA\n+ACAAATAAGTTCCGACTTCAAATTCACCTAATAAAGACTGAACAACACGATTGCTCATTG\n+CTCCAATAAGATATTTCGATACACCAGACTTTCTTACCAGCTGTTGAGTACCGGCAGTGA\n+TAATTGAGGTGAGTCCTGATGTGAACTCACCTTGTGTTAATCCAAGCCAGTCATTATTCA\n+ACGGAAGGTTATTAAAGAGCATACCGCCAAATTGATCGAGTAATTGTTGAGACTTTGCTG\n+ACGGAGTAGTTGCAAATACACAACTAAACATATTAGTACGCTGAAAGTCTATATTACCCG\n+CTTGGTTTTTAAATTCATCTAAAGTTAGCATCAGAATCCTTCCGCATATACTGAAGCTCG\n+GTTCAATGTCAAGATTTCACGCATAGTAATTTCTAATGTGAATGTACTTGGCAGGTTTGG\n+AGCTATAGCTAAACCGTTAAAGTTTCCATTTGGAGTTTTATCAAAACGGATACTCTGAAT\n+TTGACATGGACCGAATACTTCAGCACGTCCATCGAATTTACTTGTGGTTCCAAAGTTTCT\n+GACGAACCACACAGTAGGGTTACTTACAACAATAACATTACTTAAGAATGAAGTTATTTT\n+CTCAAAAACAGTGTCATTTTTATTAGCTTCATCTGGAGTTAATGTATCAAGGAAAGTTGA\n+TTTATACCATTCATCTAATTGAGACTTAACTTCTTTTGCATAAGTAGACGTTCCCGTTTC\n+GCCATAACTATAGTAGTTAAAGTATTCATAGATCTCGATAATAGCAATAAGATCTTGTAC\n+TGATCGAGGAGTTAAATCCCACGTGAATACCTTCGTACGGTTATCTGCGCCGCCATACAT\n+TGATCGAGCAGTGTTATAGATCTGCTCGTTATGGTCAGCCATTAATCCTTGAGTCAATGA\n+CTCTAATCCGCCAAAGACAGCAGTAGATGCAACGTTACTTAATACCCCTGTAGCAGTACC\n+GCCGCCACGAGAAATAAGTGAATCTCCAACGTCATTAAATTTATGAGAAACTGATTCAAC\n+ATCTGATTTCGAGCGTGGAAGTAAAATATTCACTACTGGAATTTTATCAACTTTATTAGT\n+ATTTGTTCCAGTGATTGATTTCACTACACTATTTGCAGTACGTTTCATTTCACCTAAACG\n+CATGCTACGCATATCACCGGTTGTACGAGAATTCATATCATACGCAGTGAACAACAACCC\n+GTTCTTATAAAGATCATGAACTCGTAAAGAACCAGATGTGTCATTACCAGCTGAACGTTC\n+AGACGGATATTGCGCAGTTATAGTGGATTTTATTTTTGCTGATTGTGAACTTTGACCAGC\n+GGAGGTTTTAACTCCGCTAATTAAAGCATCAGTCTTATCATCTAATTCTCTGACTTTAAT\n+GCTCATTAATTAACTCCTGTTGCCCCGAATACTCCAGGAGCTGGAGTAGCCGTGACTGTT\n+TGAACCTGGTGAATAGTCTTACTATTATTTACGTTATTAACCTGAGTGTTAGCAACATTC\n+ATATCACCGGTTGATTTTTTAGATTGCTCTTTAGCATTTTCAGCTTTTTGAATATTTTGA\n+ACTCGTTGATTATCTTCCGAAGTAGCTGGAGCCGCAGGCTTCGGAGTGTTATCTTCTTTG\n+AGCTTCTGATACTTGGATTCTACTCGTTGGAATCTTTTATCGAGTTCCTTTTTAGTAGCT\n+GGTTGATCACTTATAGCAGAATCACTAATAGACTTTTTGGCACTGTTATATGCCTTCTCT\n+AAAGATTGCATATTAGTTGGATTCTCTGGATCAACATCACCAATATATTTTTCTAAACGC\n+TGAACAGCTGCACGAGCTTCGTTTTGTTTGATCAGTGTTTCTTCGCGTTTTTCAGGAGCC\n+ATTGCTTTAAGATTCTGAGTCTCTTGATCACGGTCAGATGCTTGTGTAGAATCGATTTTA\n+TTCTCTCTTCCTAGTACCCAATCAAATGCACGAGTTTTAAATTCGCCAGCTTTATCAATA\n+ATTCCAGGACCTTCTTCAATACGCTTACTCTGATATTTAGCCAAAGCTTTTTGATCATCT\n+TCAGACAATGAATTACCAGTGCGTTCCTGGAATCCTTCTAGTGCTGAACCACGAATAGTA\n+GTTGCTGCATTTTCAAAGCCAAGTGCATCGAGTATAGAAGCAGATATCTTTGAAATTCCC\n+AA'..b'ATTTCCATGAGGTTACTGGGTTATGAGTTATAAAATTCTTTT\n+AGAAGTTACCGTGATGTCTTCGACTGGACATGTGGCGGTTAGTACTGAACAGCTGGATTT\n+TTATAGCTGGGATAATGCTAATATGTATTATGAAGCAGTAGAAGTTTATGAAGAAACGCC\n+AGATATTAAAGTATGGCGTCAAGTAACAAAACTTTATTAAAGCCCTTCGGGGCTTTTGTT\n+GTCTATAAATATAGTAAACTATAGAGGACTTTTTATGATCGAATTAAATGAAGTCTTCGA\n+TGAAGGGAAAGAACGTCTAGCAGTTACGAACCTTTATCCGAAGCTCAAGATTCCACAAAT\n+TTTTGCAATAGACAACACTAAAGTAGCTTATCGTATGTGCTCATATACTGGTGGTGGAGA\n+TGCAAATAAAAACATCAAACCCGGTGATAAAATGATGCATGTCATTGCATTAGGAGTTAC\n+TGATAAAGGCCTTGGTCAACTTAAGACCTTAGGTGATAATCCAATTGCTGTTATTGATAC\n+AATCTTTAACCACGTAATGGGTATCATGAAGTTTTATCGTTTTGACGCTGCTTTATTTCG\n+TGTTAAAAAGAATAAAACTGGTGGAGCAGGTCGCCAGATGCAAGTTATTGTTGATCGTCT\n+AATCAAGAAGAAAGGCGGTGGCAAATTCGTTATGCTTAAAGAGTTGTATGATTTTGATAA\n+GAAATACAACTACATTTTAGTATACAAGAAGAATGCTGATCTTGTCAATATCCCTGGAAT\n+GACTGAGATCATGGACTCAATTTATAAGAAAGTAGACACTGATGTAGGTGATGCTTATAT\n+CAACGTTGAGACCGGCAAACAAGTATCTAAGCTTGAAGCTATCGCGGGTTCAATCGCAGC\n+AGAAAATGATAAACGCTCAGACCAGGCGGTTGCGTCTCGAGCTAAAATATCTCGTCGTGC\n+TTTAATGGCTTCTCAATATTCAATCCAAGTGGGATTTGATACTCGTAAAGATGCGGTAGA\n+ACATGATAAGCGATTAGATGTAATTAACTCTAAACCTCCGGTTTATTTGACAGATAAGTC\n+TTCTGACCAAGTATCGAATATTCAAATGGCTATTGATAATTTCAGAAATGATTCTCAATC\n+AATTGCTAAAACCGGCGAAGCGTTTAAGACATTTGACCCGTCATGGAAAATGGATGATGA\n+TCGTCATTCTACTGGTACAATGAAAGCCCAAGAACTTGTTCTAAGGCTCACTAATATATT\n+AACCAGTGGAACAGTAGACGATTTCAGTCAACATCCTACTGATAGAAGAGAAGCATTTAA\n+AACATTAGCGGTCAGAGACATTTATCGTATTGGTGAAGCCTGGTCTAAATTAGAGCCTAA\n+TGACTATTATGGTGCTATTAAAGAACTTACTCGAGTCGCAATGGAAGACAAAGAATGGTC\n+TTCTGATGCAAATCGTGAATACGCAGTAAAAGAGATTGTAGAATTAATTTCTAAACAGTT\n+CTCTGATTTAGCAGCTAGCATGTACAAAAATACATCAGATGTGGATCGTTATACTCCGGT\n+ACAATTGTCAGGTTTACATGCTTACGTCGGTTCATCTTATAAGTACATCAACGACTATCT\n+TTTAGGCCTTGATGATTATGGCAAAGAAACTGTTGAAAAATGGATTGAGTCTATCGATTC\n+TGCGTTTGAAAATGGTGTTCGTCTTCCGAAGGGAACTAAGCTATTTCGAGGTCAACATAC\n+TAAGCGCGAAGCTATTGAAGTTAGTTTAGAAAACAAGCACTTCTATTTCAAGAATTATGT\n+GTCAACTTCAATGGCTCCTATTATCTTTGGTGGATATGGACGAGCATATGATGCAATGGA\n+CCCCGCTGCATTGAACACAGATACATCGACTCCTAAAGAAGTGCTTGACTCTGTTTCAAC\n+TGTTCGGCCTGATAGTATTACTAACTCTGAAATGGGTGAATTGCGTTTAGCGTTCGTTAT\n+TTCTGGCGCAGAGAAAATAAAGACTATCGTAACCAATGCTGGAATCTCAGGATTGTCATT\n+TGAAGCTGAAGTTATTCTTCCTCGTGGTACTGTTCTTAGAATTGATAAAATGTATGGAAC\n+AGCTCAGAAACTTCAAGCTAATGACTACACAGCATCAAAGAGTGTTCTTATGGAATGCAC\n+TGTAGTATCTCCAGAACAATTATCTGAAACTACAATTTATGATGGCGATAAATTGTTAGA\n+AGGTGAATTGGTTGAATCTGATTATTCGTTCAGTTCTTTTATTGGTCAATTAAATGAAGC\n+TAAAGTTGAAACACCAGATTGGTTAGGTGAAGCTCTAGCATCATTTGTTGACATAAATAA\n+TTTACCAGAACGATTCATAAATTAATATTTTCACATGGACGTGAATTCAGAGAGGGCTTT\n+ATGGAAATTTTAAACGAAGTACTAGACGAAAGTAAACTGGATTTACCAGTTACGAACCTT\n+TATCCAAAGACGAAAATTCCACAAATTTTTGCTATTCAAACTAACTCCGAGGGTTCACTG\n+CCAGCATTCAGGATGTGTTCATATACATCTGGCGGTGATACCAATAAGAACGTTAAACCT\n+GGCGACAAAATGATTCATGTTGTTATGCTATCATTGAGCGAAAAAGGATCATTAGTTAAG\n+CTTAAAAACTTAGGCGGCGATCCAATTGGTGTTATCTCTACTACGTTCAATATCGTTTAT\n+TCAACGATGAAGCAGTATAAAATGGACGCATGCTTGTTCCGAATGGCCAAAAGCAAAATC\n+GGTGGACAAGCTCGTCAGATGCAGGTTATTATGGACCGACTCGTACGTTCTCGTACTGGT\n+GGTAAATTTGTTATCCTGAAAGAACTCTGGGATTATGATAAGAAGTACGCATATATTCTT\n+ATTCATCGTAAAAATGTTGATCTCTCAACCATCCCTGGCGTCCCAGAGATTGATACTGGA\n+CTGTTCACTGCAGTTGAAACTAAAGTTGGTGAAGTTTATGTTGAAAAGAAATCAGGTCAA\n+CAAGTAACTAAAGCCCAAGCCGTTGCTGCTTCTATTGCAGTCGAAAACGATAAGCGTTCA\n+GATCAAAACGTTATTTCTCGTGCTAAGATAAATCGTCGTCAAGCTATTGCTGCTCAGTAT\n+TCTGTTGATGCATCTAGCATCCAAGGCGATGATCGTGCTGCTGAAGAATTTAAACGCTTA\n+GAAGCTAAAGTTCCAGTTAAAAGCTCTAAAGGCGCTGAGTCATCAGACATGGTAGCAAAA\n+GTTAATACCATCGCTGACCGTCAAGGAAATGAGTATATCGGCAAAGTACTAAACTTCATC\n+ACTAATCCTGAAACATCTCAGGACACAGATGGTAAAGCATTGACTGCACGAATAGGTCAA\n+TTGCGCCAGTTATCTAAAATGCCTAAAGGTGCCATGTTATCAGGTGGATTTGAAACTGGT\n+GGTATGAAGTACTACATGGAAAACCAAAAAGAAATGTACAATGAAGTTCGTTCATTTGCT\n+CGATTGATAGCTGGGGTGAATACAACTAACTCCTTTCAGACGATGAAAGATTTAGTTAAA\n+ATGGCTTCAGCTGGAACTAGACCTGAAGATCGTGAACAGTTAATTGCAAATTTAATTGGA\n+TTAGCTTATAAAGAAATAAGTGCAATCATCAGAGATTCATACCAAACTGCAGCAAGTTTA\n+TCTAAAGAGAATGATCATTATTCTAAAGATGAAAAACAAGCTATCAGTGAATACTGCGCA\n+AACGCTTTCGAATACGTGAATATGTTCTTAATCGGTAAGCCGGAAGAAGGGTATTCAACT\n+TCTGATTCTCTCGAGATCATCGATAATATGGACTCTGCGTTTGAAAAAGGAACTCGTTTA\n+GACAAAGGTACATTATTGTATCGTGGCCAAAAATTAGACCTTCCTACA\n'
b
diff -r 000000000000 -r d78175596286 test-data/vcf/merlin.vcf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/vcf/merlin.vcf Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,23 @@
+##fileformat=VCFv4.0
+##fileDate=20090805
+##source=myImputationProgramV3.1
+##reference=1000GenomesPilot-NCBI36
+##phasing=partial
+##INFO=<ID=NS,Number=1,Type=Integer,Description="Number of Samples With Data">
+##INFO=<ID=DP,Number=1,Type=Integer,Description="Total Depth">
+##INFO=<ID=AF,Number=.,Type=Float,Description="Allele Frequency">
+##INFO=<ID=AA,Number=1,Type=String,Description="Ancestral Allele">
+##INFO=<ID=DB,Number=0,Type=Flag,Description="dbSNP membership, build 129">
+##INFO=<ID=H2,Number=0,Type=Flag,Description="HapMap2 membership">
+##FILTER=<ID=q10,Description="Quality below 10">
+##FILTER=<ID=s50,Description="Less than 50% of samples have data">
+##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
+##FORMAT=<ID=GQ,Number=1,Type=Integer,Description="Genotype Quality">
+##FORMAT=<ID=DP,Number=1,Type=Integer,Description="Read Depth">
+##FORMAT=<ID=HQ,Number=2,Type=Integer,Description="Haplotype Quality">
+#CHROM POS     ID        REF ALT    QUAL FILTER INFO                              FORMAT      NA00001        NA00002        NA00003
+Merlin  170   rs6054257   G   A   29  PASS    NS=3;DP=14;AF=0.5;DB;H2 GT:GQ:DP:HQ 0|0:48:1:51,51  1|0:48:8:51,51  1/1:43:5:.,.
+Merlin  1020   .   T   A   3   q10 NS=3;DP=11;AF=0.017 GT:GQ:DP:HQ 0|0:49:3:58,50  0|1:3:5:65,3    0/0:41:3
+Merlin  3445 rs6040355   A   G,T 67  PASS    NS=2;DP=10;AF=0.333,0.667;AA=T;DB   GT:GQ:DP:HQ 1|2:21:6:23,27  2|1:2:0:18,2    2/2:35:4
+Merlin  5050 .   T   .   47  PASS    NS=3;DP=13;AA=T GT:GQ:DP:HQ 0|0:54:7:56,60  0|0:48:4:51,51  0/0:61:2
+Merlin  20000 microsat1   GTCT    G,GTACT 50  PASS    NS=3;DP=9;AA=G  GT:GQ:DP    0/1:35:4    0/2:17:2    1/1:40:3
b
diff -r 000000000000 -r d78175596286 tstar.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tstar.sh Mon Jan 08 09:20:33 2024 +0000
b
@@ -0,0 +1,1 @@
+tar -cvz --exclude *.gz --exclude *.png jbrowse2/* > jb2.tgz