747d414a3053db1454d223d0db7e74a4765e7c98
braney
  Tue Jan 24 17:00:18 2023 -0800
re-introducing chainSnakes into the browser

diff --git src/hg/hgTracks/snakeTrack.c src/hg/hgTracks/snakeTrack.c
deleted file mode 100644
index 7825910..0000000
--- src/hg/hgTracks/snakeTrack.c
+++ /dev/null
@@ -1,1945 +0,0 @@
-/* Copyright (C) 2014 The Regents of the University of California 
- * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
-
-#ifdef USE_HAL
-/* snakeTrack - stuff to load and display snake type tracks in browser.  */
-
-#include "common.h"
-#include "hash.h"
-#include "localmem.h"
-#include "linefile.h"
-#include "jksql.h"
-#include "hdb.h"
-#include "hgTracks.h"
-#include "chainBlock.h"
-#include "chainLink.h"
-#include "chainDb.h"
-#include "chainCart.h"
-#include "errCatch.h"
-#include "twoBit.h"
-#include "bigWarn.h"
-#include <pthread.h>
-#include "trackHub.h"
-#include "limits.h"
-#include "snakeUi.h"
-#include "bits.h"
-#include "trix.h"
-#include "chromAlias.h"
-
-#include "halBlockViz.h"
-#include "bigPsl.h"
-
-// this is the number of pixels used by the target self-align bar
-#define DUP_LINE_HEIGHT	4
-// this is the number of pixels used when displaying the insertion lengths
-#define INSERT_TEXT_HEIGHT 10
-
-struct snakeFeature
-    {
-    struct snakeFeature *next;
-    int start, end;			/* Start/end in browser coordinates. */
-    int qStart, qEnd;			/* query start/end */
-    int level;				/* level in snake */
-    int orientation;			/* strand... -1 is '-', 1 is '+' */
-    boolean drawn;			/* did we draw this feature? */
-    char *qSequence;			/* may have sequence, or NULL */
-    char *tSequence;			/* may have sequence, or NULL */
-    char *qName;			/* chrom name on other species */
-    unsigned pixX1, pixX2;              /* pixel coordinates within window */
-    };
-
-static int snakeFeatureCmpTStart(const void *va, const void *vb)
-/* sort by start position on the target sequence */
-{
-const struct snakeFeature *a = *((struct snakeFeature **)va);
-const struct snakeFeature *b = *((struct snakeFeature **)vb);
-int diff = a->start - b->start;
-
-return diff;
-}
-
-static int snakeFeatureCmpQStart(const void *va, const void *vb)
-/* sort by start position on the query sequence */
-{
-const struct snakeFeature *a = *((struct snakeFeature **)va);
-const struct snakeFeature *b = *((struct snakeFeature **)vb);
-int diff = a->qStart - b->qStart;
-
-if (diff == 0)
-    {
-    diff = a->start - b->start;
-    }
-
-return diff;
-}
-
-// static machinery to calculate full and pack snake
-
-#define NUM_LEVELS	1000
-
-struct level
-{
-boolean init;		/* has this level been initialized */
-int orientation;	/* strand.. see above */
-unsigned long edge;	/* the leading edge of this level */
-int adjustLevel;	/* used to compress out the unused levels */
-boolean hasBlock;	/* are there any blocks in this level */
-
-// these fields are used to compact full snakes
-unsigned *connectsToLevel;  /* what levels does this level connect to */
-Bits *pixels;               /* keep track of what pixels are used */
-struct snakeFeature *blocks; /* the ungapped blocks attached to this level */
-};
-
-static struct level Levels[NUM_LEVELS]; /* for packing the snake, not re-entrant! */
-static int maxLevel = 0;     	     /* deepest level */	
-
-/* blocks that make it through the min size filter */
-static struct snakeFeature *newList = NULL;   
-
-static void clearLevels()
-/* clear out the data structure that we use to calculate snakes */
-{
-int ii;
-
-for(ii=0; ii < sizeof(Levels) / sizeof(Levels[0]); ii++)
-    Levels[ii].init = FALSE;
-maxLevel = 0;
-}
-
-static void calcFullSnakeHelper(struct snakeFeature *list, int level)
-// calculate a full snake
-// updates global newList with unsorted blocks that pass the min
-// size filter.
-{
-struct snakeFeature *cb = list;
-struct snakeFeature *proposedList = NULL;
-
-if (level > maxLevel)
-    maxLevel = level;
-if (level > ArraySize(Levels))
-    errAbort("too many levels");
-
-if (Levels[level].init == FALSE)
-    {
-    // initialize the level if this is the first time we've seen it
-    Levels[level].init = TRUE;
-    Levels[level].orientation = list->orientation;
-    if (list->orientation == -1)
-	Levels[level].edge = LONG_MAX; // bigger than the biggest chrom
-    else
-	Levels[level].edge = 0;
-    }
-
-// now we step through the blocks and assign them to levels
-struct snakeFeature *next;
-struct snakeFeature *insertHead = NULL;
-for(; cb; cb = next)
-    {
-    // we're going to add this block to a different list 
-    // so keep track of the next pointer
-    next = cb->next;
-
-    // if this block can't fit on this level add to the insert
-    // list and move on to the next block
-    if ((Levels[level].orientation != cb->orientation) ||
-	((cb->orientation == 1) && (Levels[level].edge > cb->start)) ||
-	((cb->orientation == -1) && (Levels[level].edge < cb->end)))
-	{
-	// add this to the list of an insert
-	slAddHead(&insertHead, cb);
-	continue;
-	}
-
-    // the current block will fit on this level
-    // go ahead and deal with the blocks that wouldn't 
-    if (insertHead)
-	{
-	// we had an insert, go ahead and calculate where that goes
-	slReverse(&insertHead);
-	calcFullSnakeHelper(insertHead, level + 1);
-	insertHead = NULL;
-	}
-
-    // assign the current block to this level
-    cb->level = level;
-
-    if (cb->orientation == 1)
-	Levels[level].edge = cb->end;
-    else
-	Levels[level].edge = cb->start;
-
-    // add this block to the list of proposed blocks for this level
-    slAddHead(&proposedList, cb);
-    }
-
-// we're at the end of the list.  Deal with any blocks
-// that didn't fit on this level
-if (insertHead)
-    {
-    slReverse(&insertHead);
-    int nextLevel = level + 1;
-    calcFullSnakeHelper(insertHead, nextLevel);
-    insertHead = NULL;
-    }
-
-// do we have any proposed blocks
-if (proposedList == NULL) 
-    return;
-
-// we parsed all the blocks in the list to see if they fit in our level
-// now let's see if the list of blocks for this level is big enough
-// to actually add
-
-struct snakeFeature *temp;
-double scale = scaleForWindow(insideWidth, winStart, winEnd);
-int start, end;
-
-// order the blocks so lowest start position is first
-if (Levels[level].orientation == 1)
-    slReverse(&proposedList);
-
-start=proposedList->start;
-for(temp=proposedList; temp->next; temp = temp->next)
-    ;
-end=temp->end;
-
-// calculate how big the string of blocks is in screen coordinates
-double apparentSize = scale * (end - start);
-
-if (apparentSize < 0)
-    errAbort("size of a list of blocks should not be less than zero");
-
-// check to see if the apparent size is big enough
-if (apparentSize < 1)
-    return;
-
-// transfer proposedList to new block list
-for(temp=proposedList; temp; temp = next)
-    {
-    next = temp->next;
-    temp->next = NULL;
-    slAddHead(&newList, temp);
-    }
-}
-
-struct snakeInfo
-{
-int maxLevel;
-} snakeInfo;
-
-static void freeFullLevels()
-// free the connection levels and bitmaps for each level
-{
-int ii;
-
-for(ii=0; ii <= maxLevel; ii++)
-    {
-    freez(&Levels[ii].connectsToLevel);
-    bitFree(&Levels[ii].pixels);
-    }
-}
-
-static void initializeFullLevels(struct snakeFeature *sfList)
-/* initialize levels for compact snakes */
-{
-int ii;
-
-for(ii=0; ii <= maxLevel; ii++)
-    {
-    Levels[ii].connectsToLevel = needMem((maxLevel+1) * sizeof(unsigned));
-    Levels[ii].pixels = bitAlloc(insideWidth);
-    Levels[ii].blocks = NULL;
-    }
-
-struct snakeFeature *sf, *next;
-int prevLevel = -1;
-double scale = scaleForWindow(insideWidth, winStart, winEnd);
-
-for(sf=sfList; sf; sf = next)
-    {
-    next = sf->next;
-
-    if (positiveRangeIntersection(sf->start, sf->end, winStart, winEnd))
-	{
-	int sClp = (sf->start < winStart) ? winStart : sf->start;
-	sf->pixX1 = round((sClp - winStart)*scale);
-	int eClp = (sf->end > winEnd) ? winEnd : sf->end;
-	sf->pixX2 = round((eClp - winStart)*scale);
-	}
-    else
-	{
-	sf->pixX1 = sf->pixX2 = 0;
-	}
-
-    bitSetRange(Levels[sf->level].pixels, sf->pixX1, sf->pixX2 - sf->pixX1);
-
-    if (prevLevel != -1)
-	Levels[sf->level].connectsToLevel[prevLevel] = 1;
-
-    if(next != NULL)
-	Levels[sf->level].connectsToLevel[next->level] = 1;
-
-    prevLevel = sf->level;
-
-    slAddHead(&Levels[sf->level].blocks, sf);
-    }
-}
-
-static int highestLevelBelowUs(int level)
-// is there a level below us that doesn't connect to us
-{
-int newLevel;
-
-// find the highest level below us that we connect to
-for(newLevel = level - 1; newLevel >= 0; newLevel--)	 
-    if (Levels[level].connectsToLevel[newLevel])
-	break;
-
-// if the next level is more than one below us, we may
-// be able to push our blocks to it.
-if ((newLevel < 0) || (newLevel + 1 == level))
-    return -1;
-
-return newLevel + 1;
-}
-
-// the number of pixels we need clear on either side of the blocks we push
-#define EXTRASPACE	10
-
-static boolean checkBlocksOnLevel(int level, struct snakeFeature *sfList)
-// is there enough pixels on this level to hold our blocks?
-{
-struct snakeFeature *sf;
-
-for(sf=sfList; sf;  sf = sf->next)
-    {
-    if (bitCountRange(Levels[level].pixels, sf->pixX1 - EXTRASPACE, (sf->pixX2 - sf->pixX1) + 2*EXTRASPACE))
-	return FALSE;
-    }
-return TRUE;
-}
-
-static void collapseLevel(int oldLevel, int newLevel)
-// push level up to higher level
-{
-struct snakeFeature *sf;
-struct snakeFeature *next;
-
-for(sf=Levels[oldLevel].blocks; sf;  sf = next)
-    {
-    next = sf->next;
-    sf->level = newLevel;
-    slAddHead(&Levels[newLevel].blocks, sf);
-
-    bitSetRange(Levels[sf->level].pixels, sf->pixX1, sf->pixX2 - sf->pixX1);
-    }
-Levels[oldLevel].blocks = NULL;
-Levels[oldLevel].pixels = bitAlloc(insideWidth);
-}
-
-static void remapConnections(int oldLevel, int newLevel)
-// if we've moved a level, we need to remap all the connections
-{
-int ii, jj;
-
-for(ii=0; ii <= maxLevel; ii++)
-    {
-    for(jj=0; jj <= maxLevel; jj++)
-	{
-	if (Levels[ii].connectsToLevel[oldLevel])
-	    {
-	    Levels[ii].connectsToLevel[oldLevel] = 0;
-	    Levels[ii].connectsToLevel[newLevel] = 1;
-	    }
-	}
-    }
-}
-
-static struct snakeFeature *compactSnakes(struct snakeFeature *sfList)
-// collapse levels that will fit on a higer level
-{
-int ii;
-
-initializeFullLevels(sfList);
-
-// start with third level to see what can be compacted
-for(ii=2; ii <= maxLevel; ii++) 
-    {
-    int newLevel;
-    // is there a level below us that doesn't connect to us
-    if ((newLevel = highestLevelBelowUs(ii)) > 0)
-	{
-	int jj;
-	for (jj=newLevel; jj < ii; jj++)
-	    {
-	    if (checkBlocksOnLevel(jj, Levels[ii].blocks))
-		{
-		collapseLevel(ii, jj);
-		remapConnections(ii, jj);
-		break;
-		}
-	    }
-	}
-    }
-
-// reattach blocks in the levels to linkedFeature
-struct snakeFeature *newList = NULL;
-for(ii=0; ii <= maxLevel; ii++)
-    {
-    newList = slCat(Levels[ii].blocks, newList);
-    }
-slSort(&newList, snakeFeatureCmpQStart);
-
-// figure out the new max
-int newMax = 0;
-for(ii=0; ii <= maxLevel; ii++)
-    if (Levels[ii].blocks != NULL)
-	newMax = ii;
-
-freeFullLevels();
-maxLevel = newMax;
-
-return newList;
-}
-
-static void calcFullSnake(struct track *tg, void *item)
-// calculate a full snake
-{
-struct linkedFeatures  *lf = (struct linkedFeatures *)item;
-
-// if there aren't any blocks, don't bother
-if (lf->components == NULL)
-    return;
-
-// we use the codons field to keep track of whether we already
-// calculated the height of this snake
-if (lf->codons == NULL)
-    {
-    clearLevels();
-    struct snakeFeature *sf;
-
-    // this will destroy lf->components, and add to newList
-    calcFullSnakeHelper((struct snakeFeature *)lf->components, 0);
-    lf->components = (struct simpleFeature *)newList;
-    newList = NULL;
-    slSort(&lf->components, snakeFeatureCmpQStart);
-
-    // now we're going to compress the levels that aren't used
-    // to do that, we need to see which blocks are on the screen,
-    // or connected to something on the screen
-    int oldMax = maxLevel;
-    clearLevels();
-    struct snakeFeature *prev = NULL;
-    for(sf=(struct snakeFeature *)lf->components; sf; prev = sf, sf = sf->next)
-	{
-	if (Levels[sf->level].init == FALSE)
-	    {
-	    Levels[sf->level].init = TRUE;
-	    Levels[sf->level].orientation = sf->orientation;
-	    Levels[sf->level].hasBlock = FALSE;
-	    }
-	else
-	    {
-	    if (Levels[sf->level].orientation != sf->orientation)
-		errAbort("found snakeFeature with wrong orientation");
-	    if ((sf->orientation == 1) && (Levels[sf->level].edge > sf->start)) 
-		errAbort("found snakeFeature that violates edge");
-	    if ((sf->orientation == -1) && (Levels[sf->level].edge < sf->end))
-		errAbort("found snakeFeature that violates edge");
-	    }
-	if (sf->orientation == 1)
-	    Levels[sf->level].edge = sf->end;
-	else
-	    Levels[sf->level].edge = sf->start;
-	if (sf->level > maxLevel)
-	    maxLevel = sf->level;
-	if(positiveRangeIntersection(winStart, winEnd, sf->start, sf->end))
-	    {
-	    Levels[sf->level].hasBlock = TRUE;
-	    if (sf->next != NULL)
-		Levels[sf->next->level].hasBlock = TRUE;
-	    if (prev != NULL)
-		Levels[prev->level].hasBlock = TRUE;
-
-	    }
-	}
-
-    // now figure out how to remap the blocks
-    int ii;
-    int count = 0;
-    for(ii=0; ii < oldMax + 1; ii++)
-	{
-	Levels[ii].adjustLevel = count;
-	if ((Levels[ii].init) && (Levels[ii].hasBlock))
-	    count++;
-	}
-    maxLevel = count;
-
-    // remap blocks
-    for(sf=(struct snakeFeature *)lf->components; sf; sf = sf->next)
-	sf->level = Levels[sf->level].adjustLevel;
-
-    // now compact the snakes
-    lf->components = (void *)compactSnakes((struct snakeFeature *)lf->components);
-    struct snakeInfo *si;
-    AllocVar(si);
-    si->maxLevel = maxLevel;
-    lf->codons = (struct simpleFeature *)si;
-    }
-}
-
-static void calcPackSnakeHelper(struct snakeFeature *list, int level)
-// calculate a packed snake
-// updates global newList with unsorted blocks that pass the min
-// size filter.
-{
-struct snakeFeature *cb = list;
-struct snakeFeature *proposedList = NULL;
-
-if (level > maxLevel)
-    maxLevel = level;
-if (level > ArraySize(Levels))
-    errAbort("too many levels");
-
-if (Levels[level].init == FALSE)
-    {
-    // initialize the level if this is the first time we've seen it
-    Levels[level].init = TRUE;
-    Levels[level].edge = 0;
-    }
-
-// now we step through the blocks and assign them to levels
-struct snakeFeature *next;
-struct snakeFeature *insertHead = NULL;
-for(; cb; cb = next)
-    {
-    // we're going to add this block to a different list 
-    // so keep track of the next pointer
-    next = cb->next;
-
-    // if this block can't fit on this level add to the insert
-    // list and move on to the next block
-    if ( Levels[level].edge > cb->start)
-	{
-	// add this to the list of an insert
-	slAddHead(&insertHead, cb);
-	continue;
-	}
-
-    // the current block will fit on this level
-    // go ahead and deal with the blocks that wouldn't 
-    if (insertHead)
-	{
-	// we had an insert, go ahead and calculate where that goes
-	slReverse(&insertHead);
-	calcPackSnakeHelper(insertHead, level + 1);
-	insertHead = NULL;
-	}
-
-    // assign the current block to this level
-    cb->level = level;
-
-    Levels[level].edge = cb->end;
-
-    // add this block to the list of proposed blocks for this level
-    slAddHead(&proposedList, cb);
-    }
-
-// we're at the end of the list.  Deal with any blocks
-// that didn't fit on this level
-if (insertHead)
-    {
-    slReverse(&insertHead);
-    calcPackSnakeHelper(insertHead,  level + 1);
-    insertHead = NULL;
-    }
-
-// do we have any proposed blocks
-if (proposedList == NULL) 
-    return;
-
-// we parsed all the blocks in the list to see if they fit in our level
-// now let's see if the list of blocks for this level is big enough
-// to actually add
-
-struct snakeFeature *temp;
-double scale = scaleForWindow(insideWidth, winStart, winEnd);
-int start, end;
-
-// order the blocks so lowest start position is first
-slReverse(&proposedList);
-
-start=proposedList->start;
-for(temp=proposedList; temp->next; temp = temp->next)
-    ;
-end=temp->end;
-
-// calculate how big the string of blocks is in screen coordinates
-double apparentSize = scale * (end - start);
-
-if (apparentSize < 0)
-    errAbort("size of a list of blocks should not be less than zero");
-
-// check to see if the apparent size is big enough
-if (apparentSize < 1)
-    return;
-
-// transfer proposedList to new block list
-for(temp=proposedList; temp; temp = next)
-    {
-    next = temp->next;
-    temp->next = NULL;
-    slAddHead(&newList, temp);
-    }
-}
-
-static void calcPackSnake(struct track *tg, void *item)
-{
-struct linkedFeatures  *lf = (struct linkedFeatures *)item;
-if (lf->components == NULL)
-    return;
-
-// we use the codons field to keep track of whether we already
-// calculated the height of this snake
-if (lf->codons == NULL)
-    {
-    clearLevels();
-
-    // this will destroy lf->components, and add to newList
-    calcPackSnakeHelper((struct snakeFeature *)lf->components, 0);
-    lf->components = (struct simpleFeature *)newList;
-    newList = NULL;
-    
-    //slSort(&lf->components, snakeFeatureCmpQStart);
-
-    struct snakeInfo *si;
-    AllocVar(si);
-    si->maxLevel = maxLevel;
-    lf->codons = (struct simpleFeature *)si;
-    }
-}
-
-static int snakeItemHeight(struct track *tg, void *item)
-// return height of a single packed snake 
-{
-if ((item == NULL) || (tg->visibility == tvSquish) || (tg->visibility == tvDense)) 
-    return 0;
-
-struct linkedFeatures  *lf = (struct linkedFeatures *)item;
-if (lf->components == NULL)
-    return 0;
-
-if (tg->visibility == tvFull) 
-    calcFullSnake(tg, item);
-else if (tg->visibility == tvPack) 
-    calcPackSnake(tg, item);
-
-struct snakeInfo *si = (struct snakeInfo *)lf->codons;
-int lineHeight = tg->lineHeight ;
-int multiplier = 1;
-
-if (tg->visibility == tvFull)
-    multiplier = 2;
-return (si->maxLevel + 1) * (multiplier * lineHeight);
-}
-
-static int linkedFeaturesCmpScore(const void *va, const void *vb)
-/* Help sort linkedFeatures by score */
-{
-const struct linkedFeatures *a = *((struct linkedFeatures **)va);
-const struct linkedFeatures *b = *((struct linkedFeatures **)vb);
-if (a->score > b->score)
-    return -1;
-else if (a->score < b->score)
-    return 1;
-return 0;
-}
-
-static int snakeHeight(struct track *tg, enum trackVisibility vis)
-/* calculate height of all the snakes being displayed */
-{
-if (tg->networkErrMsg != NULL)
-    {
-    // we had a parallel load failure
-    tg->drawItems = bigDrawWarning;
-    tg->totalHeight = bigWarnTotalHeight;
-    return bigWarnTotalHeight(tg, vis);
-    }
-
-if (vis == tvDense)
-    return tg->lineHeight;
-
-if (vis == tvSquish)
-    return tg->lineHeight/2;
-
-int height = DUP_LINE_HEIGHT + INSERT_TEXT_HEIGHT; 
-struct slList *item = tg->items;
-
-item = tg->items;
-
-for (item=tg->items;item; item = item->next)
-    {
-    height += tg->itemHeight(tg, item);
-    }
-if (height < DUP_LINE_HEIGHT + tg->lineHeight)
-    height = DUP_LINE_HEIGHT + tg->lineHeight;
-return height;
-}
-
-static void snakeDraw(struct track *tg, int seqStart, int seqEnd,
-        struct hvGfx *hvg, int xOff, int yOff, int width, 
-        MgFont *font, Color color, enum trackVisibility vis)
-/* Draw linked features items. */
-{
-struct slList *item;
-int y;
-struct linkedFeatures  *lf;
-double scale = scaleForWindow(width, seqStart, seqEnd);
-int height = snakeHeight(tg, vis);
-
-hvGfxSetClip(hvg, xOff, yOff, width, height);
-
-if ((tg->visibility == tvFull) || (tg->visibility == tvPack))
-    {
-    // score snakes by how many bases they cover
-    for (item = tg->items; item != NULL; item = item->next)
-	{
-	lf = (struct linkedFeatures *)item;
-	struct snakeFeature  *sf;
-
-	lf->score = 0;
-	for (sf =  (struct snakeFeature *)lf->components; sf != NULL;  sf = sf->next)
-	    {
-	    lf->score += sf->end - sf->start;
-	    }
-	}
-
-    slSort(&tg->items, linkedFeaturesCmpScore);
-    }
-
-y = yOff;
-for (item = tg->items; item != NULL; item = item->next)
-    {
-    if(tg->itemColor != NULL) 
-	color = tg->itemColor(tg, item, hvg);
-    tg->drawItemAt(tg, item, hvg, xOff, y, scale, font, color, vis);
-    if (vis == tvFull)
-	y += tg->itemHeight(tg, item);
-    } 
-}
-
-//  this is a 16 color palette with every other color being a lighter version of
-//  the color before it
-static int snakePalette2[] =
-{
-0x1f77b4, 0xaec7e8, 0xff7f0e, 0xffbb78, 0x2ca02c, 0x98df8a, 0xd62728, 0xff9896, 0x9467bd, 0xc5b0d5, 0x8c564b, 0xc49c94, 0xe377c2, 0xf7b6d2, 0x7f7f7f, 0xc7c7c7, 0xbcbd22, 0xdbdb8d, 0x17becf, 0x9edae5
-};
-
-static int snakePalette[] =
-{
-0x1f77b4, 0xff7f0e, 0x2ca02c, 0xd62728, 0x9467bd, 0x8c564b, 0xe377c2, 0x7f7f7f, 0xbcbd22, 0x17becf
-};
-
-static Color hashColor(char *name)
-{
-bits32 hashVal = hashString(name);
-unsigned int colorInt = snakePalette2[hashVal % (sizeof(snakePalette2)/sizeof(Color))];
-
-return MAKECOLOR_32(((colorInt >> 16) & 0xff),((colorInt >> 8) & 0xff),((colorInt >> 0) & 0xff));
-}
-
-static void boundMapBox(struct hvGfx *hvg, int start, int end, int x, int y, int width, int height,
-                       char *track, char *item, char *statusLine, char *directUrl, boolean withHgsid,
-                       char *extra)
-// make sure start x and end x position are on the screen
-// otherwise the tracking box code gets confused
-{
-if (x > insideWidth)
-    return;
-
-if (x < 0)
-    {
-    width -= -x;
-    x = 0;
-    }
-
-if (x + width > insideWidth)
-    {
-    width -= x + width - insideWidth;
-    }
-
-mapBoxHgcOrHgGene(hvg, start, end, x, y, width, height,
-                       track, item, statusLine, directUrl, withHgsid,
-                       extra);
-}
-
-static void snakeDrawAt(struct track *tg, void *item,
-	struct hvGfx *hvg, int xOff, int y, double scale, 
-	MgFont *font, Color color, enum trackVisibility vis)
-/* Draw a single simple bed item at position. */
-{
-unsigned showSnpWidth = cartOrTdbInt(cart, tg->tdb, 
-    SNAKE_SHOW_SNP_WIDTH, SNAKE_DEFAULT_SHOW_SNP_WIDTH);
-struct linkedFeatures  *lf = (struct linkedFeatures *)item;
-
-
-if (tg->visibility == tvFull) 
-    calcFullSnake(tg, item);
-else if (tg->visibility == tvPack)
-    calcPackSnake(tg, item);
-
-if (lf->components == NULL)
-    return;
-
-boolean isHalSnake = lf->isHalSnake;
-
-struct snakeFeature  *sf = (struct snakeFeature *)lf->components, *prevSf = NULL;
-int s = tg->itemStart(tg, item);
-int sClp = (s < winStart) ? winStart : s;
-int x1 = round((sClp - winStart)*scale) + xOff;
-int textX = x1;
-int yOff = y;
-boolean withLabels = (withLeftLabels && (vis == tvFull) && !tg->drawName);
-unsigned   labelColor = MG_BLACK;
-
-// draw the labels
-if (withLabels)
-    {
-    char *name = tg->itemName(tg, item);
-    int nameWidth = mgFontStringWidth(font, name);
-    int dotWidth = tl.nWidth/2;
-    boolean snapLeft = FALSE;
-    boolean drawNameInverted = FALSE;
-    textX -= nameWidth + dotWidth;
-    snapLeft = (textX < fullInsideX);
-    /* Special tweak for expRatio in pack mode: force all labels
-     * left to prevent only a subset from being placed right: */
-    snapLeft |= (startsWith("expRatio", tg->tdb->type));
-#ifdef IMAGEv2_NO_LEFTLABEL_ON_FULL
-    if (theImgBox == NULL && snapLeft)
-#else///ifndef IMAGEv2_NO_LEFTLABEL_ON_FULL
-    if (snapLeft)        /* Snap label to the left. */
-#endif ///ndef IMAGEv2_NO_LEFTLABEL_ON_FULL
-        {
-        textX = leftLabelX;
-        assert(hvgSide != NULL);
-        hvGfxUnclip(hvgSide);
-        hvGfxSetClip(hvgSide, leftLabelX, yOff, fullInsideX - leftLabelX, tg->height);
-        if(drawNameInverted)
-            {
-            int boxStart = leftLabelX + leftLabelWidth - 2 - nameWidth;
-            hvGfxBox(hvgSide, boxStart, y, nameWidth+1, tg->heightPer - 1, color);
-            hvGfxTextRight(hvgSide, leftLabelX, y, leftLabelWidth-1, tg->heightPer,
-                        MG_WHITE, font, name);
-            }
-        else
-            hvGfxTextRight(hvgSide, leftLabelX, y, leftLabelWidth-1, tg->heightPer,
-                        labelColor, font, name);
-        hvGfxUnclip(hvgSide);
-        hvGfxSetClip(hvgSide, insideX, yOff, insideWidth, tg->height);
-        }
-    else
-        {
-        int pdfSlop=nameWidth/5;
-        hvGfxUnclip(hvg);
-        hvGfxSetClip(hvg, textX-1-pdfSlop, y, nameWidth+1+pdfSlop, tg->heightPer);
-        if(drawNameInverted)
-            {
-            hvGfxBox(hvg, textX - 1, y, nameWidth+1, tg->heightPer-1, color);
-            hvGfxTextRight(hvg, textX, y, nameWidth, tg->heightPer, MG_WHITE, font, name);
-            }
-        else
-            hvGfxTextRight(hvg, textX, y, nameWidth, tg->heightPer, labelColor, font, name);
-        hvGfxUnclip(hvg);
-        hvGfxSetClip(hvg, insideX, yOff, insideWidth, tg->height);
-        }
-    }
-
-// let's draw some blue bars for the duplications
-struct hal_target_dupe_list_t* dupeList = lf->dupeList;
-
-int count = 0;
-if ((tg->visibility == tvFull) || (tg->visibility == tvPack)) 
-    {
-    for(; dupeList ; dupeList = dupeList->next, count++)
-	{
-	struct hal_target_range_t *range = dupeList->tRange;
-
-	unsigned int colorInt = snakePalette[count % (sizeof(snakePalette)/sizeof(Color))];
-	Color color = MAKECOLOR_32(((colorInt >> 16) & 0xff),((colorInt >> 8) & 0xff),((colorInt >> 0) & 0xff));
-
-	for(; range; range = range->next)
-	    {
-	    int s = range->tStart;
-	    int e = range->tStart + range->size;
-	    int sClp = (s < winStart) ? winStart : s;
-	    int eClp = (e > winEnd) ? winEnd : e;
-	    int x1 = round((sClp - winStart)*scale) + xOff;
-	    int x2 = round((eClp - winStart)*scale) + xOff;
-	    hvGfxBox(hvg, x1, y , x2-x1, DUP_LINE_HEIGHT - 1 , color);
-	    }
-	}
-    y+=DUP_LINE_HEIGHT;
-    }
-
-// now we're going to draw the boxes
-
-s = sf->start;
-int lastE = -1;
-int lastS = -1;
-int offY = y;
-int lineHeight = tg->lineHeight ;
-int  qs, qe;
-int heightPer = tg->heightPer;
-int lastX = -1;
-int lastQEnd = 0;
-int lastLevel = -1;
-int e;
-qe = lastQEnd = 0;
-for (sf =  (struct snakeFeature *)lf->components; sf != NULL; lastQEnd = qe, prevSf = sf, sf = sf->next)
-    {
-    qs = sf->qStart;
-    qe = sf->qEnd;
-    if (vis == tvDense)
-	y = offY;
-    else if ((vis == tvPack) || (vis == tvSquish))
-	y = offY + (sf->level * 1) * lineHeight;
-    else if (vis == tvFull)
-	y = offY + (sf->level * 2) * lineHeight;
-    s = sf->start; e = sf->end;
-
-    int sx, ex;
-    if (!positiveRangeIntersection(winStart, winEnd, s, e))
-	continue;
-    sx = round((double)((int)s-winStart)*scale) + xOff;
-    ex = round((double)((int)e-winStart)*scale) + xOff;
-
-    // color by strand
-    static Color darkBlueColor = 0;
-    static Color darkRedColor = 0;
-    if (darkRedColor == 0)
-	{
-	//the light blue: rgb(149, 204, 252)
-	//the light red: rgb(232, 156, 156)
-	darkRedColor = hvGfxFindColorIx(hvg, 232,156,156);
-	darkBlueColor = hvGfxFindColorIx(hvg, 149,204,252);
-	}
-    
-    char *colorBy = cartOrTdbString(cart, tg->tdb, 
-	SNAKE_COLOR_BY, SNAKE_DEFAULT_COLOR_BY);
-
-    extern Color getChromColor(char *name, struct hvGfx *hvg);
-    if (sameString(colorBy, SNAKE_COLOR_BY_STRAND_VALUE))
-	color = (sf->orientation == -1) ? darkRedColor : darkBlueColor;
-    else if (sameString(colorBy, SNAKE_COLOR_BY_CHROM_VALUE))
-	color = hashColor(sf->qName);
-    else
-	color =  darkBlueColor;
-
-    int w = ex - sx;
-    if (w == 0) 
-	w = 1;
-    assert(w > 0);
-    char buffer[1024];
-	
-    if (vis == tvFull)
-	safef(buffer, sizeof buffer, "%d-%d",sf->qStart,sf->qEnd);
-    else
-	safef(buffer, sizeof buffer, "%s:%d-%d",sf->qName,sf->qStart,sf->qEnd);
-    if (sx < insideX)
-	{
-	int olap = insideX - sx;
-	sx = insideX;
-	w -= olap;
-	}
-    char qAddress[4096];
-    if ((vis == tvFull) || (vis == tvPack) )
-	{
-	safef(qAddress, sizeof qAddress, "qName=%s&qs=%d&qe=%d&qWidth=%d",sf->qName,  qs, qe,  winEnd - winStart);
-	boundMapBox(hvg, s, e, sx+1, y, w-2, heightPer, tg->track,
-		    buffer, buffer, NULL, TRUE, qAddress);
-	}
-    hvGfxBox(hvg, sx, y, w, heightPer, color);
-
-    // now draw the mismatches if we're at high enough resolution 
-    if ((isHalSnake && sf->qSequence != NULL) && (winBaseCount < showSnpWidth) && ((vis == tvFull) || (vis == tvPack)))
-	{
-	char *twoBitString = trackDbSetting(tg->tdb, "twoBit");
-	static struct twoBitFile *tbf = NULL;
-	static char *lastTwoBitString = NULL;
-	static struct dnaSeq *seq = NULL;
-	static char *lastQName = NULL;
-
-	// sequence for chain snakes is in 2bit files which we cache
-	if (!isHalSnake)
-	    {
-	    if (twoBitString == NULL)
-		twoBitString = "/gbdb/hg19/hg19.2bit";
-
-	    if ((lastTwoBitString == NULL) ||
-		differentString(lastTwoBitString, twoBitString))
-		{
-		if (tbf != NULL)
-		    {
-		    lastQName = NULL;
-		    twoBitClose(&tbf);
-		    }
-		tbf = twoBitOpen(twoBitString);
-		}
-
-	    // we're reading in the whole chrom
-	    if ((lastQName == NULL) || differentString(sf->qName, lastQName))
-		seq = twoBitReadSeqFrag(tbf, sf->qName,  0, 0);
-	    lastQName = sf->qName;
-	    lastTwoBitString = twoBitString;
-	    }
-
-	char *ourDna;
-	if (isHalSnake)
-	    ourDna = sf->qSequence;
-	else
-	    ourDna = &seq->dna[sf->qStart];
-
-	int seqLen = sf->qEnd - sf->qStart;
-	toUpperN(ourDna, seqLen);
-	if (!isHalSnake && (sf->orientation == -1))
-	    reverseComplement(ourDna,seqLen);
-
-	// get the reference sequence
-	char *refDna;
-        if (isHalSnake && differentString(tg->tdb->type, "pslSnake"))
-	    {
-	    refDna = sf->tSequence;
-	    }
-	else
-	    {
-	    struct dnaSeq *extraSeq = hDnaFromSeq(database, chromName, sf->start, sf->end, dnaUpper);
-	    refDna = extraSeq->dna;
-	    }
-	int si = s;
-	char *ptr1 = refDna;
-	char *ptr2 = ourDna;
-	for(; si < e; si++,ptr1++,ptr2++)
-	    {
-	    // if mismatch!  If reference is N ignore, if query is N, paint yellow
-	    if ( (*ptr1 != *ptr2) && !((*ptr1 == 'N') || (*ptr1 == 'n')))
-		{
-		int misX1 = round((double)((int)si-winStart)*scale) + xOff;
-		int misX2 = round((double)((int)(si+1)-winStart)*scale) + xOff;
-		int w1 = misX2 - misX1;
-		if (w1 < 1)
-		    w1 = 1;
-
-		Color boxColor = MG_RED;
-		if ((*ptr2 == 'N') || (*ptr2 == 'n'))
-		    boxColor = hvGfxFindRgb(hvg, &undefinedYellowColor);
-		hvGfxBox(hvg, misX1, y, w1, heightPer, boxColor);
-		}
-	    }
-
-	// if we're zoomed to base level, draw sequence of mismatch
-	if (zoomedToBaseLevel)
-	    {
-	    int mysx = round((double)((int)s-winStart)*scale) + xOff;
-	    int myex = round((double)((int)e-winStart)*scale) + xOff;
-	    int myw = myex - mysx;
-	    spreadAlignString(hvg, mysx, y, myw, heightPer, MG_WHITE, font, ourDna,
-		refDna, seqLen, TRUE, FALSE);
-	    }
-
-	}
-    sf->drawn = TRUE;
-    lastLevel = sf->level;
-    //lastX = x;
-    }
-
-if (vis != tvFull)
-    return;
-
-// now we're going to draw the lines between the blocks
-
-lastX = -1;
-lastQEnd = 0;
-lastLevel = 0;
-qe = lastQEnd = 0;
-prevSf = NULL;
-for (sf =  (struct snakeFeature *)lf->components; sf != NULL; lastQEnd = qe, prevSf = sf, sf = sf->next)
-    {
-    int y1, y2;
-    int sx, ex;
-    qs = sf->qStart;
-    qe = sf->qEnd;
-    if (lastLevel == sf->level)
-	{
-	y1 = offY + (lastLevel * 2) * lineHeight + lineHeight/2;
-	y2 = offY + (sf->level * 2) * lineHeight + lineHeight/2;
-	}
-    else if (lastLevel > sf->level)
-	{
-	y1 = offY + (lastLevel * 2 ) * lineHeight;
-	y2 = offY + (sf->level * 2 + 1) * lineHeight + lineHeight/3;
-	}
-    else
-	{
-	y1 = offY + (lastLevel * 2 + 1) * lineHeight - 1;
-	y2 = offY + (sf->level * 2 ) * lineHeight - lineHeight/3;;
-	}
-    s = sf->start; e = sf->end;
-
-    sx = round((double)((int)s-winStart)*scale) + xOff;
-    ex = round((double)((int)e-winStart)*scale) + xOff;
-    color = (sf->orientation == -1) ? MG_RED : MG_BLUE;
-
-    if (lastX != -1)
-	{
-	char buffer[1024];
-#define MG_ORANGE  0xff0082E6
-	int color = MG_GRAY;
-
-	if (lastQEnd != qs) {
-            long long queryInsertSize = llabs(lastQEnd - qs);
-            long long targetInsertSize;
-            if (sf->orientation == 1)
-                targetInsertSize = s - lastE;
-            else
-                targetInsertSize = lastS - e;
-            int blue = 0;
-            int red = 0;
-            int green = 0;
-            if (queryInsertSize > targetInsertSize) {
-                double frac = ((double) queryInsertSize - targetInsertSize) / targetInsertSize;
-                if (frac > 1.0)
-                    frac = 1.0;
-                red = 255 - 255 * frac;
-                blue = 255 * frac;
-            } else {
-                double frac = ((double) targetInsertSize - queryInsertSize) / targetInsertSize;
-                if (frac > 1.0)
-                    frac = 1.0;
-                red = 255 - 255 * frac;
-                green = 255 * frac;
-            }
-            color = hvGfxFindColorIx(hvg, red, green, blue);
-        }
-        double queryGapNFrac = 0.0;
-        double queryGapMaskedFrac = 0.0;
-        if ((qs > lastQEnd) && qs - lastQEnd < 1000000) {
-            // sketchy
-            char *fileName = trackDbSetting(tg->tdb, "bigDataUrl");
-            char *otherSpecies = trackDbSetting(tg->tdb, "otherSpecies");
-            int handle = halOpenLOD(fileName, NULL);
-            char *queryGapDna = halGetDna(handle, otherSpecies, sf->qName, lastQEnd, qs, NULL);
-            long long numNs = 0;
-            long long numMasked = 0;
-            char *i = queryGapDna;
-            while (*i != '\0') {
-                if (*i == 'N' || *i == 'n') {
-                    numNs++;
-                    numMasked++;
-                }
-                if (*i == 'a' || *i == 't' || *i == 'g' || *i == 'c') {
-                        numMasked++;
-                }
-                i++;
-            }
-            free(queryGapDna);
-            queryGapMaskedFrac = ((double) numMasked) / (qs - lastQEnd);
-            queryGapNFrac = ((double) numNs) / (qs - lastQEnd);
-        }
-
-	// draw the vertical orange bars if there is an insert in the other sequence
-	if ((winBaseCount < showSnpWidth) )
-	    {
-	    if ((sf->orientation == 1) && (qs != lastQEnd) && (lastE == s))
-		{
-		hvGfxLine(hvg, sx, y2 - lineHeight/2 , sx, y2 + lineHeight/2, MG_ORANGE);
-		safef(buffer, sizeof buffer, "%dbp (%.1lf%% N, %.1lf%% masked)", qs - lastQEnd, queryGapNFrac*100, queryGapMaskedFrac*100);
-		boundMapBox(hvg, s, e, sx, y2 - lineHeight/2, 1, lineHeight, tg->track,
-				    "foo", buffer, NULL, TRUE, NULL);
-		safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd);
-                hvGfxTextCentered(hvg, sx - 10, y2 + lineHeight/2, 20, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer);
-		}
-	    else if ((sf->orientation == -1) && (qs != lastQEnd) && (lastS == e))
-		{
-		hvGfxLine(hvg, ex, y2 - lineHeight/2 , ex, y2 + lineHeight/2, MG_ORANGE);
-		safef(buffer, sizeof buffer, "%dbp (%.1lf%% N, %.1lf%% masked)", qs - lastQEnd, queryGapNFrac*100, queryGapMaskedFrac*100);
-		boundMapBox(hvg, s, e, ex, y2 - lineHeight/2, 1, lineHeight, tg->track,
-				    "foo", buffer, NULL, TRUE, NULL);
-		safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd);
-                hvGfxTextCentered(hvg, ex - 10, y2 + lineHeight/2, 20, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer);
-		}
-	    }
-
-	// now draw the lines between blocks
-	if ((!((lastX == sx) && (y1 == y2))) &&
-	    (sf->drawn  || ((prevSf != NULL) && (prevSf->drawn))) &&
-	    (((lastE >= winStart) && (lastE <= winEnd)) || 
-	    ((s > winStart) && (s < winEnd))))
-	    {
-	    if (lastLevel == sf->level)
-		{
-                if (sf->orientation == 1)
-                    safef(buffer, sizeof buffer, "%dbp (%dbp in ref) (%.1lf%% N, %.1lf%% masked)", qs - lastQEnd, s - lastE, queryGapNFrac*100, queryGapMaskedFrac*100);
-                else
-                    safef(buffer, sizeof buffer, "%dbp (%dbp in ref) (%.1lf%% N, %.1lf%% masked)", qs - lastQEnd, lastS - e, queryGapNFrac*100, queryGapMaskedFrac*100);
-		if (sf->orientation == -1)
-		    {
-		    if (lastX != ex)
-			{
-			hvGfxLine(hvg, ex, y1, lastX, y2, color);
-			boundMapBox(hvg, s, e, ex, y1, lastX-ex, 1, tg->track,
-				"", buffer, NULL, TRUE, NULL);
-                        if (lastQEnd != qs) {
-                            safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd);
-                            hvGfxTextCentered(hvg, ex, y2 + lineHeight/2, lastX-ex, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer);
-                        }
-			}
-		    }
-		else
-		    {
-		    if (lastX != sx)
-			{
-			hvGfxLine(hvg, lastX, y1, sx, y2, color);
-			boundMapBox(hvg, s, e, lastX, y1, sx-lastX, 1, tg->track,
-				"", buffer, NULL, TRUE, NULL);
-                        if (lastQEnd != qs) {
-                            safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd);
-                            hvGfxTextCentered(hvg, lastX, y2 + lineHeight/2, sx-lastX, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer);
-                        }
-			}
-		    }
-		}
-	    else if (lastLevel > sf->level)
-		{
-		hvGfxLine(hvg, lastX, y1, sx, y2, color);
-		hvGfxLine(hvg, sx, y2, sx, y2 - lineHeight - lineHeight/3, color);
-		char buffer[1024];
-		safef(buffer, sizeof buffer, "%d-%d %dbp gap (%.1lf%% N, %.1lf%% masked)",prevSf->qStart,prevSf->qEnd, qs - lastQEnd, queryGapNFrac*100, queryGapMaskedFrac*100);
-		boundMapBox(hvg, s, e, sx, y2 - lineHeight - lineHeight/3, 2, lineHeight + lineHeight/3, tg->track,
-	                    "", buffer, NULL, TRUE, NULL);
-		safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd);
-                if (lastQEnd != qs)
-                    hvGfxTextCentered(hvg, sx - 10, y2 + lineHeight/2, 20, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer);
-
-		}
-	    else
-		{
-		char buffer[1024];
-		safef(buffer, sizeof buffer, "%d-%d %dbp gap (%.1lf%% N, %.1lf%% masked)",prevSf->qStart,prevSf->qEnd, qs - lastQEnd, queryGapNFrac*100, queryGapMaskedFrac*100);
-		if (sf->orientation == -1)
-		    {
-		    hvGfxLine(hvg, lastX-1, y1, ex, y2, color);
-		    hvGfxLine(hvg, ex, y2, ex, y2 + lineHeight , color);
-		    boundMapBox(hvg, s, e, ex-1, y2, 2, lineHeight , tg->track,
-				"", buffer, NULL, TRUE, NULL);
-                    safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd);
-                    if (lastQEnd != qs)
-                        hvGfxTextCentered(hvg, ex - 10, y2 + lineHeight, 20, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer);
-		    }
-		else
-		    {
-		    hvGfxLine(hvg, lastX-1, y1, sx, y2, color);
-		    hvGfxLine(hvg, sx, y2, sx, y2 + lineHeight , color);
-		    boundMapBox(hvg, s, e, sx-1, y2, 2, lineHeight , tg->track,
-				"", buffer, NULL, TRUE, NULL);
-
-                    safef(buffer, sizeof buffer, "%dbp", qs - lastQEnd);
-                    if (lastQEnd != qs)
-                        hvGfxTextCentered(hvg, sx - 10, y2 + lineHeight, 20, INSERT_TEXT_HEIGHT, MG_ORANGE, font, buffer);
-		    }
-		}
-	    }
-	}
-    if (sf->orientation == -1)
-	lastX = sx;
-    else
-	lastX = ex;
-    lastS = s;
-    lastE = e;
-    lastLevel = sf->level;
-    lastQEnd = qe;
-    }
-}
-
-static char *doChromIxSearch(char *trixFile, char *searchName)
-/* search ixFile for the searchName, return name if found */
-{
-struct trix *trix = trixOpen(trixFile);
-char *trixWords[1];
-int trixWordCount = 1;
-trixWords[0] = strLower(searchName);
-char *name = NULL;  // assume NOT found
-
-struct trixSearchResult *tsList = trixSearch(trix, trixWordCount, trixWords, tsmExact);
-if (tsList)
-   name = tsList->itemId;  // FOUND
-return name;
-}
-
-static struct hal_block_results_t *pslSnakeBlocks(char *fileName, struct track *track, char *chrom, unsigned start, unsigned end, unsigned int maxItems)
-/* create HAL-like blocks from a bigPsl file. */
-{
-struct hal_block_results_t *head;
-
-AllocVar(head);
-
-struct lm *lm = lmInit(0);
-//struct bigBedInterval *bb, *bbList = bigBedSelectRangeExt(track, chrom, start, end, lm, maxItems);
-struct bigBedInterval *bb, *bbList = bigBedSelectRangeExt(track, chrom, 0, hChromSize(database,chromName), lm, maxItems);
-
-struct bbiFile *bbi = fetchBbiForTrack(track);
-int seqTypeField =  0;
-if (sameString(track->tdb->type, "bigPsl"))
-    {
-    seqTypeField =  bbExtraFieldIndex(bbi, "seqType");
-    }
-bbiFileClose(&bbi);
-for (bb = bbList; bb != NULL; bb = bb->next)
-    {
-    char *seq, *cds;
-    struct psl *psl = pslFromBigPsl(chromName, bb, seqTypeField,  &seq, &cds); 
-    unsigned *targetStart = psl->tStarts;
-    unsigned *queryStart = psl->qStarts;
-    unsigned *size = psl->blockSizes;
-    int ii;
-
-    if ((seq != NULL) && (psl->strand[0] == '-'))
-        reverseComplement(seq, strlen(seq));
-    for(ii = 0; ii < psl->blockCount; ii++)
-        {
-        struct hal_block_t *block;
-        AllocVar(block);
-        slAddHead(&head->mappedBlocks, block);
-
-        block->qChrom = psl->qName;
-        block->tStart = *targetStart++;
-        block->qStart = *queryStart++;
-        block->size = *size++;
-        block->strand = psl->strand[0];
-        block->qSequence = &seq[block->qStart];
-
-        if (block->strand == '-')
-            block->qStart = psl->qSize - block->qStart;
-        }
-    }
-
-return head;
-}
-
-void halSnakeLoadItems(struct track *tg)
-// load up a snake from a HAL file.   This code is called in threads
-// so *no* use of globals please. All but full snakes are read into a single
-// linked feature.
-{
-unsigned showSnpWidth = cartOrTdbInt(cart, tg->tdb, 
-    SNAKE_SHOW_SNP_WIDTH, SNAKE_DEFAULT_SHOW_SNP_WIDTH);
-
-char * chromAlias = NULL;	// create later when needed
-char * chromAliasFile = trackDbSetting(tg->tdb, "searchTrix");
-if (chromAliasFile)
-   chromAlias = doChromIxSearch(chromAliasFile, chromName);
-
-char *aliasName = chromName;
-if (chromAlias)
-   {
-       if (differentWord(chromAlias, aliasName))
-          aliasName = chromAlias;
-   }
-
-boolean isPsl = sameString(tg->tdb->type, "pslSnake");
-
-// if we have a network error we want to put out a message about it
-struct errCatch *errCatch = errCatchNew();
-if (errCatchStart(errCatch))
-    {
-    char *fileName = trackDbSetting(tg->tdb, "bigDataUrl");
-    char *otherSpecies = trackDbSetting(tg->tdb, "otherSpecies");
-    char *errString = "<HAL error message not set>";
-    int handle = -1;
-    if (!isPsl)
-        {
-        handle = halOpenLOD(fileName, &errString);
-        if (handle < 0)
-            {
-            errAbort("HAL open error: %s\n", errString);
-            goto out;
-            }
-        }
-    boolean isPackOrFull = (tg->visibility == tvFull) || 
-	(tg->visibility == tvPack);
-    hal_dup_type_t dupMode =  (isPackOrFull) ? HAL_QUERY_AND_TARGET_DUPS :
-	HAL_QUERY_DUPS;
-    hal_seqmode_type_t needSeq = isPackOrFull && (winBaseCount < showSnpWidth) ? HAL_LOD0_SEQUENCE : HAL_NO_SEQUENCE;
-    int mapBackAdjacencies = (tg->visibility == tvFull);
-    char codeVarName[1024];
-    safef(codeVarName, sizeof codeVarName, "%s.coalescent", tg->tdb->track);
-    char *coalescent = cartOptionalString(cart, codeVarName);
-    char *otherDbName = trackHubSkipHubName(database);
-    struct hal_block_results_t *head = NULL;
-    if (isPsl)
-        {
-        head = pslSnakeBlocks(fileName, tg, chromName, winStart, winEnd, 10000000);
-        }
-    else 
-        {
-        struct slName *aliasList = chromAliasFindAliases(chromName);
-        struct slName *nativeName = newSlName(aliasName);
-        slAddHead(&aliasList, nativeName);
-        for (; aliasList; aliasList = aliasList->next)
-            {
-            head = halGetBlocksInTargetRange(handle, otherSpecies, otherDbName, aliasList->name, winStart, winEnd, 0, needSeq, dupMode,mapBackAdjacencies, coalescent, &errString);
-            if (head != NULL) 
-                break;
-            }
-        }
-
-    // did we get any blocks from HAL
-    if (head == NULL)
-	{
-	errAbort("HAL get blocks error: %s\n", errString);
-	goto out;
-	}
-    struct hal_block_t* cur = head->mappedBlocks;
-    struct linkedFeatures *lf = NULL;
-    struct hash *qChromHash = newHash(5);
-    struct linkedFeatures *lfList = NULL;
-    char buffer[4096];
-
-#ifdef NOTNOW
-    struct hal_target_dupe_list_t* targetDupeBlocks = head->targetDupeBlocks;
-
-    for(;targetDupeBlocks; targetDupeBlocks = targetDupeBlocks->next)
-	{
-	printf("<br>id: %d qChrom %s\n", targetDupeBlocks->id, targetDupeBlocks->qChrom);
-	struct hal_target_range_t *range = targetDupeBlocks->tRange;
-	for(; range; range = range->next)
-	    {
-	    printf("<br>   %ld : %ld\n", range->tStart, range->size);
-	    }
-	}
-#endif
-
-    while (cur)
-    {
-	struct hashEl* hel;
-
-	if (tg->visibility == tvFull)
-	    safef(buffer, sizeof buffer, "%s", cur->qChrom);
-	else
-	    {
-	    // make sure the block is on the screen 
-	    if (!positiveRangeIntersection(winStart, winEnd, cur->tStart,  cur->tStart + cur->size))
-		{
-		cur = cur->next;
-		continue;
-		}
-	    safef(buffer, sizeof buffer, "allInOne");
-	    }
-
-	if ((hel = hashLookup(qChromHash, buffer)) == NULL)
-	    {
-	    AllocVar(lf);
-	    lf->isHalSnake = TRUE;
-	    slAddHead(&lfList, lf);
-	    lf->start = 0;
-	    lf->end = 1000000000;
-	    lf->grayIx = maxShade;
-	    lf->name = cloneString(buffer);
-	    lf->extra = cloneString(buffer);
-	    lf->orientation = (cur->strand == '+') ? 1 : -1;
-	    hashAdd(qChromHash, lf->name, lf);
-
-	    // now figure out where the duplication bars go
-	    struct hal_target_dupe_list_t* targetDupeBlocks = head->targetDupeBlocks;
-
-	    if ((tg->visibility == tvPack) || (tg->visibility == tvFull))
-		for(;targetDupeBlocks; targetDupeBlocks = targetDupeBlocks->next)
-		    {
-		    if ((tg->visibility == tvPack) ||
-			((tg->visibility == tvFull) &&
-			 (sameString(targetDupeBlocks->qChrom, cur->qChrom))))
-			{
-			struct hal_target_dupe_list_t* dupeList;
-			AllocVar(dupeList);
-			*dupeList = *targetDupeBlocks;
-			slAddHead(&lf->dupeList, dupeList);
-			// TODO: should clone the target_range structures
-			// rather than copying them
-			}
-		    }
-	    }
-	else
-	    {
-	    lf = hel->val;
-	    }
-
-	struct snakeFeature  *sf;
-	AllocVar(sf);
-	slAddHead(&lf->components, sf);
-	
-	sf->start = cur->tStart;
-	sf->end = cur->tStart + cur->size;
-	sf->qStart = cur->qStart;
-	sf->qEnd = cur->qStart + cur->size;
-	sf->orientation = (cur->strand == '+') ? 1 : -1;
-	sf->tSequence = cloneString(cur->tSequence);
-	sf->qSequence = cloneString(cur->qSequence);
-	if (sf->tSequence != NULL)
-	    toUpperN(sf->tSequence, strlen(sf->tSequence));
-	if (sf->qSequence != NULL)
-	    toUpperN(sf->qSequence, strlen(sf->qSequence));
-	sf->qName = cur->qChrom;
-
-	cur = cur->next;
-    }
-    if (tg->visibility == tvFull)
-	{
-	for(lf=lfList; lf ; lf = lf->next)
-	    {
-	    slSort(&lf->components, snakeFeatureCmpQStart);
-	    }
-	}
-    else if ((tg->visibility == tvPack) && (lfList != NULL))
-	{
-	assert(lfList->next == NULL);
-	slSort(&lfList->components, snakeFeatureCmpTStart);
-	}
-    
-    //halFreeBlocks(head);
-    //halClose(handle, myThread);
-
-    tg->items = lfList;
-    }
-
-out:
-errCatchEnd(errCatch);
-if (errCatch->gotError)
-    {
-    tg->networkErrMsg = cloneString(errCatch->message->string);
-    tg->drawItems = bigDrawWarning;
-    tg->totalHeight = bigWarnTotalHeight;
-    }
-errCatchFree(&errCatch);
-}
-
-void halSnakeDrawLeftLabels(struct track *tg, int seqStart, int seqEnd,
-        struct hvGfx *hvg, int xOff, int yOff, int width, int height,
-        boolean withCenterLabels, MgFont *font,
-        Color color, enum trackVisibility vis)
-/* Draw left label (shortLabel) in pack and dense modes. */
-{
-if ((vis == tvDense) ||  (vis == tvPack))
-    {
-    hvGfxSetClip(hvgSide, leftLabelX, yOff + tg->lineHeight, insideWidth, tg->height);
-    hvGfxTextRight(hvgSide, leftLabelX, yOff + tg->lineHeight, leftLabelWidth-1, tg->lineHeight,
-                   color, font, tg->shortLabel);
-    hvGfxUnclip(hvgSide);
-    }
-}
-
-void halSnakeMethods(struct track *tg, struct trackDb *tdb, 
-	int wordCount, char *words[])
-{
-linkedFeaturesMethods(tg);
-tg->canPack = tdb->canPack = TRUE;
-tg->loadItems = halSnakeLoadItems;
-tg->drawItems = snakeDraw;
-tg->mapItemName = lfMapNameFromExtra;
-tg->subType = lfSubChain;
-//tg->extraUiData = (void *) chainCart;
-tg->totalHeight = snakeHeight; 
-tg->drawLeftLabels = halSnakeDrawLeftLabels;
-
-tg->drawItemAt = snakeDrawAt;
-tg->itemHeight = snakeItemHeight;
-tg->nextItemButtonable = FALSE;
-}
-#endif  // USE_HAL
-
-#ifdef NOTNOW
-
-// from here down are routines to support the visualization of chains as snakes
-// this code is currently BROKEN, and may be removed completely in the future
-
-struct cartOptions
-    {
-    enum chainColorEnum chainColor; /*  ChromColors, ScoreColors, NoColors */
-    int scoreFilter ; /* filter chains by score if > 0 */
-    };
-
-// mySQL code to read in chains
-
-static void doQuery(struct sqlConnection *conn, char *fullName, 
-			struct lm *lm, struct hash *hash, 
-			int start, int end,  boolean isSplit, int chainId)
-/* doQuery- check the database for chain elements between
- * 	start and end.  Use the passed hash to resolve chain
- * 	id's and place the elements into the right
- * 	linkedFeatures structure
- */
-{
-struct sqlResult *sr = NULL;
-char **row;
-struct linkedFeatures *lf;
-struct snakeFeature *sf;
-struct dyString *query = dyStringNew(1024);
-
-if (chainId == -1)
-    {
-    sqlDyStringPrintf(query, 
-	"select chainId,tStart,tEnd,qStart from %sLink ", fullName);
-    if (isSplit)
-	sqlDyStringPrintf(query,"force index (bin) ");
-    sqlDyStringPrintf(query, "where ",
-    }
-else
-    sqlDyStringPrintf(query, 
-	"select chainId, tStart,tEnd,qStart from %sLink where chainId=%d and ",
-	fullName, chainId);
-if (!isSplit)
-    sqlDyStringPrintf(query, "tName='%s' and ", chromName);
-hAddBinToQuery(start, end, query);
-sqlDyStringPrintf(query, "tStart<%u and tEnd>%u", end, start);
-sr = sqlGetResult(conn, query->string);
-
-/* Loop through making up simple features and adding them
- * to the corresponding linkedFeature. */
-while ((row = sqlNextRow(sr)) != NULL)
-    {
-    lf = hashFindVal(hash, row[0]);
-    if (lf != NULL)
-	{
-	struct chain *pChain = lf->extra;
-	lmAllocVar(lm, sf);
-	sf->start = sqlUnsigned(row[1]);
-	sf->end = sqlUnsigned(row[2]);
-	sf->qStart = sqlUnsigned(row[3]); 
-
-	sf->qEnd = sf->qStart + (sf->end - sf->start);
-	if ((pChain) && pChain->qStrand == '-')
-	    {
-	    int temp;
-
-	    temp = sf->qStart;
-	    sf->qStart = pChain->qSize - sf->qEnd;
-	    sf->qEnd = pChain->qSize - temp;
-	    }
-	sf->orientation = lf->orientation;
-	slAddHead(&lf->components, sf);
-	}
-    }
-sqlFreeResult(&sr);
-dyStringFree(&query);
-}
-
-static void fixItems(struct linkedFeatures *lf)
-// put all chain blocks from a single query chromosome into one
-// linkedFeatures structure
-{
-struct linkedFeatures *firstLf, *next;
-struct snakeFeature  *sf,  *nextSf;
-
-firstLf = lf;
-for (;lf; lf = next)
-    {
-    next = lf->next;
-    if (!sameString(firstLf->name, lf->name) && (lf->components != NULL))
-	{
-	slSort(&firstLf->components, snakeFeatureCmpQStart);
-	firstLf = lf;
-	}
-    for (sf =  (struct snakeFeature *)lf->components; sf != NULL; sf = nextSf)
-	{
-	sf->qName = lf->name;
-	sf->orientation = lf->orientation;
-	nextSf = sf->next;
-	if (firstLf != lf)
-	    {
-	    lf->components = NULL;
-	    slAddHead(&firstLf->components, sf);
-	    }
-	}
-    }
-
-if (firstLf != NULL)
-    {
-    slSort(&firstLf->components, snakeFeatureCmpQStart);
-    firstLf->next = 0;
-    }
-}
-
-
-static void loadLinks(struct track *tg, int seqStart, int seqEnd,
-         enum trackVisibility vis)
-// load up the chain elements into linkedFeatures
-{
-int start, end, extra;
-char fullName[64];
-int maxOverLeft = 0, maxOverRight = 0;
-int overLeft, overRight;
-struct linkedFeatures *lf;
-struct lm *lm;
-struct hash *hash;	/* Hash of chain ids. */
-struct sqlConnection *conn;
-lm = lmInit(1024*4);
-hash = newHash(0);
-conn = hAllocConn(database);
-
-/* Make up a hash of all linked features keyed by
- * id, which is held in the extras field.  */
-for (lf = tg->items; lf != NULL; lf = lf->next)
-    {
-    char buf[256];
-    struct chain *pChain = lf->extra;
-    safef(buf, sizeof(buf), "%d", pChain->id);
-    hashAdd(hash, buf, lf);
-    overRight = lf->end - seqEnd;
-    if (overRight > maxOverRight)
-	maxOverRight = overRight;
-    overLeft = seqStart - lf->start ;
-    if (overLeft > maxOverLeft)
-	maxOverLeft = overLeft;
-    }
-
-if (hash->size)
-    {
-    boolean isSplit = TRUE;
-    /* Make up range query. */
-    safef(fullName, sizeof fullName, "%s_%s", chromName, tg->table);
-    if (!hTableExists(database, fullName))
-	{
-	strcpy(fullName, tg->table);
-	isSplit = FALSE;
-	}
-
-    /* in dense mode we don't draw the lines 
-     * so we don't need items off the screen 
-     */
-    if (vis == tvDense)
-	doQuery(conn, fullName, lm,  hash, seqStart, seqEnd,  isSplit, -1);
-    else
-	{
-	/* if chains extend beyond edge of window we need to get 
-	 * elements that are off the screen
-	 * in both directions so we know whether to draw
-	 * one or two lines to the edge of the screen.
-	 */
-#define STARTSLOP	0
-#define MULTIPLIER	10
-#define MAXLOOK		100000
-	extra = (STARTSLOP < maxOverLeft) ? STARTSLOP : maxOverLeft;
-	start = seqStart - extra;
-	extra = (STARTSLOP < maxOverRight) ? STARTSLOP : maxOverRight;
-	end = seqEnd + extra;
-	doQuery(conn, fullName, lm,  hash, start, end,  isSplit, -1);
-	}
-    }
-hFreeConn(&conn);
-}
-
-void snakeLoadItems(struct track *tg)
-// Load chains from a mySQL database
-{
-char *track = tg->table;
-struct chain chain;
-int rowOffset;
-char **row;
-struct sqlConnection *conn = hAllocConn(database);
-struct sqlResult *sr = NULL;
-struct linkedFeatures *list = NULL, *lf;
-int qs;
-char optionChr[128]; /* Option -  chromosome filter */
-char *optionChrStr;
-char extraWhere[128] ;
-struct cartOptions *chainCart;
-struct chain *pChain;
-
-chainCart = (struct cartOptions *) tg->extraUiData;
-
-safef( optionChr, sizeof(optionChr), "%s.chromFilter", tg->table);
-optionChrStr = cartUsualString(cart, optionChr, "All");
-int ourStart = winStart;
-int ourEnd = winEnd;
-
-// we're grabbing everything now.. we really should be 
-// doing this as a preprocessing stage, rather than at run-time
-ourStart = 0;
-ourEnd = 500000000;
-//ourStart = winStart;
-//ourEnd = winEnd;
-if (startsWith("chr",optionChrStr)) 
-    {
-    sqlSafef(extraWhere, sizeof(extraWhere), 
-            "qName = \"%s\" and score > %d",optionChrStr, 
-            chainCart->scoreFilter);
-    sr = hRangeQuery(conn, track, chromName, ourStart, ourEnd, 
-            extraWhere, &rowOffset);
-    }
-else
-    {
-    if (chainCart->scoreFilter > 0)
-        {
-        sqlSafef(extraWhere, sizeof(extraWhere), 
-                "score > \"%d\"",chainCart->scoreFilter);
-        sr = hRangeQuery(conn, track, chromName, ourStart, ourEnd, 
-                extraWhere, &rowOffset);
-        }
-    else
-        {
-        sqlSafef(extraWhere, sizeof(extraWhere), " ");
-        sr = hRangeQuery(conn, track, chromName, ourStart, ourEnd, 
-                NULL, &rowOffset);
-        }
-    }
-while ((row = sqlNextRow(sr)) != NULL)
-    {
-    chainHeadStaticLoad(row + rowOffset, &chain);
-    AllocVar(pChain);
-    *pChain = chain;
-    AllocVar(lf);
-    lf->start = lf->tallStart = chain.tStart;
-    lf->end = lf->tallEnd = chain.tEnd;
-    lf->grayIx = maxShade;
-    if (chainCart->chainColor == chainColorScoreColors)
-	{
-	float normScore = sqlFloat((row+rowOffset)[11]);
-	lf->grayIx = (int) ((float)maxShade * (normScore/100.0));
-	if (lf->grayIx > (maxShade+1)) lf->grayIx = maxShade+1;
-	lf->score = normScore;
-	}
-    else
-	lf->score = chain.score;
-
-    lf->filterColor = -1;
-
-    if (chain.qStrand == '-')
-	{
-	lf->orientation = -1;
-        qs = chain.qSize - chain.qEnd;
-	}
-    else
-        {
-	lf->orientation = 1;
-	qs = chain.qStart;
-	}
-    char buffer[1024];
-    safef(buffer, sizeof(buffer), "%s", chain.qName);
-    lf->name = cloneString(buffer);
-    lf->extra = pChain;
-    slAddHead(&list, lf);
-    }
-
-/* Make sure this is sorted if in full mode. Sort by score when
- * coloring by score and in dense */
-if (tg->visibility != tvDense)
-    slSort(&list, linkedFeaturesCmpStart);
-else if ((tg->visibility == tvDense) &&
-	(chainCart->chainColor == chainColorScoreColors))
-    slSort(&list, chainCmpScore);
-else
-    slReverse(&list);
-tg->items = list;
-
-
-/* Clean up. */
-sqlFreeResult(&sr);
-hFreeConn(&conn);
-
-/* now load the items */
-loadLinks(tg, ourStart, ourEnd, tg->visibility);
-lf=tg->items;
-fixItems(lf);
-}	/*	chainLoadItems()	*/
-
-void snakeMethods(struct track *tg, struct trackDb *tdb, 
-	int wordCount, char *words[])
-/* Fill in custom parts of alignment chains. */
-{
-
-struct cartOptions *chainCart;
-
-AllocVar(chainCart);
-
-boolean normScoreAvailable = chainDbNormScoreAvailable(tdb);
-
-/*	what does the cart say about coloring option	*/
-chainCart->chainColor = chainFetchColorOption(cart, tdb, FALSE);
-
-chainCart->scoreFilter = cartUsualIntClosestToHome(cart, tdb,
-	FALSE, SCORE_FILTER, 0);
-
-
-linkedFeaturesMethods(tg);
-tg->itemColor = lfChromColor;	/*	default coloring option */
-
-/*	if normScore column is available, then allow coloring	*/
-if (normScoreAvailable)
-    {
-    switch (chainCart->chainColor)
-	{
-	case (chainColorScoreColors):
-	    tg->itemColor = chainScoreColor;
-	    tg->colorShades = shadesOfGray;
-	    break;
-	case (chainColorNoColors):
-	    setNoColor(tg);
-	    break;
-	default:
-	case (chainColorChromColors):
-	    break;
-	}
-    }
-else
-    {
-    char option[128]; /* Option -  rainbow chromosome color */
-    char *optionStr;	/* this old option was broken before */
-
-    safef(option, sizeof(option), "%s.color", tg->table);
-    optionStr = cartUsualString(cart, option, "on");
-    if (differentWord("on",optionStr))
-	{
-	setNoColor(tg);
-	chainCart->chainColor = chainColorNoColors;
-	}
-    else
-	chainCart->chainColor = chainColorChromColors;
-    }
-
-tg->canPack = FALSE;
-tg->loadItems = snakeLoadItems;
-tg->drawItems = snakeDraw;
-tg->mapItemName = lfMapNameFromExtra;
-tg->subType = lfSubChain;
-tg->extraUiData = (void *) chainCart;
-tg->totalHeight = snakeHeight; 
-
-tg->drawItemAt = snakeDrawAt;
-tg->itemHeight = snakeItemHeight;
-}
-
-static Color chainScoreColor(struct track *tg, void *item, struct hvGfx *hvg)
-{
-struct linkedFeatures *lf = (struct linkedFeatures *)item;
-
-return(tg->colorShades[lf->grayIx]);
-}
-
-static Color chainNoColor(struct track *tg, void *item, struct hvGfx *hvg)
-{
-return(tg->ixColor);
-}
-
-static void setNoColor(struct track *tg)
-{
-tg->itemColor = chainNoColor;
-tg->color.r = 0;
-tg->color.g = 0;
-tg->color.b = 0;
-tg->altColor.r = 127;
-tg->altColor.g = 127;
-tg->altColor.b = 127;
-tg->ixColor = MG_BLACK;
-tg->ixAltColor = MG_GRAY;
-}
-#endif