5194786c88bd4ab5e802eec79089897461389fe9
hiram
  Fri Mar 22 14:52:22 2019 -0700
getting a little bit better refs #18869

diff --git src/hg/hubApi/hubApi.c src/hg/hubApi/hubApi.c
index 410a905..76c7c93 100644
--- src/hg/hubApi/hubApi.c
+++ src/hg/hubApi/hubApi.c
@@ -6,33 +6,34 @@
 | Field            | Type             | Null | Key | Default | Extra |
 +------------------+------------------+------+-----+---------+-------+
 | hubUrl           | longblob         | NO   | PRI | NULL    |       |
 | shortLabel       | varchar(255)     | NO   |     | NULL    |       |
 | longLabel        | varchar(255)     | NO   |     | NULL    |       |
 | registrationTime | varchar(255)     | NO   |     | NULL    |       |
 | dbCount          | int(10) unsigned | NO   |     | NULL    |       |
 | dbList           | blob             | YES  |     | NULL    |       |
 | descriptionUrl   | longblob         | YES  |     | NULL    |       |
 +------------------+------------------+------+-----+---------+-------+
 */
 
 /* Global Variables for all modules */
 
 int maxItemsOutput = 1000;	/* can be set in URL maxItemsOutput=N */
+static int maxItemLimit = 1000000;   /* maximum of 1,000,000 items returned */
 
 /* Global only to this one source file */
-static boolean debug = FALSE;	/* can be set in URL debug=1 */
+static boolean debug = TRUE;	/* can be set in URL debug=1 */
 static struct cart *cart;             /* CGI and other variables */
 static struct hash *oldVars = NULL;
 static struct hash *trackCounter = NULL;
 static long totalTracks = 0;
 static boolean measureTiming = FALSE;	/* set by CGI parameters */
 static boolean allTrackSettings = FALSE;	/* checkbox setting */
 static char **shortLabels = NULL;	/* public hub short labels in array */
 // struct hubPublic *publicHubList = NULL;
 static int publicHubCount = 0;
 static char *defaultHub = "Plants";
 static char *defaultDb = "ce11";
 static long enteredMainTime = 0;	/* will become = clock1000() on entry */
 		/* to allow calculation of when to bail out, taking too long */
 static long timeOutSeconds = 100;
 static boolean timedOut = FALSE;
@@ -192,31 +193,31 @@
     hashIncInt(countTracks, "superTrack child");
     hashIncInt(countTracks, stripType);
     hashIncInt(countTracks, "track count");
     }
 else if (isEmpty(tdb->type))
     hashIncInt(countTracks, "no type specified");
 else
     {
     hashIncInt(countTracks, stripType);
     hashIncInt(countTracks, "track count");
     }
 freeMem(stripType);
 // showCounts(countTracks);
 }
 
-static void sampleUrl(struct trackHub *hub, char *db, struct trackDb *tdb, char *chrom, long long chromSize, char *errorString)
+static void sampleUrl(struct trackHub *hub, char *db, struct trackDb *tdb, char *chrom, unsigned chromSize, char *errorString)
 /* print out a sample getData URL */
 {
 char errorPrint[2048];
 errorPrint[0] = 0;
 
 if (isNotEmpty(errorString))
     {
     safef(errorPrint, sizeof(errorPrint), " <font color='red'>ERROR: %s</font>", errorString);
     }
 
 unsigned start = chromSize / 4;
 unsigned end = start + 10000;
 if (end > chromSize)
     end = chromSize;
 char *genome = NULL;
@@ -239,92 +240,84 @@
 	else
 	    hPrintf("<li>%s : %s <a href='%s/getData/track?db=%s&amp;chrom=%s&amp;track=%s&amp;start=%u&amp;end=%u' target=_blank>(sample getData)%s</a></li>\n", tdb->track, tdb->type, urlPrefix, db, chrom, tdb->track, start, end, errorPrint);
 	}
     }
 else if (hub)
     {
     if (tdb->parent)
 	hPrintf("<li>%s : %s subtrack of parent: %s <a href='%s/getData/track?hubUrl=%s&amp;genome=%s&amp;chrom=%s&amp;track=%s&amp;start=%u&amp;end=%u' target=_blank>(sample getData)%s</a></li>\n", tdb->track, tdb->type, tdb->parent->track, urlPrefix, hub->url, genome, chrom, tdb->track, start, end, errorPrint);
     else
 	hPrintf("<li>%s : %s <a href='%s/getData/track?hubUrl=%s&amp;genome=%s&amp;chrom=%s&amp;track=%s&amp;start=%u&amp;end=%u' target=_blank>(sample getData)%s</a></li>\n", tdb->track, tdb->type, urlPrefix, hub->url, genome, chrom, tdb->track, start, end, errorPrint);
     }
 else
     hPrintf("<li>%s : %s not db hub track ?</li>\n", tdb->track, tdb->type);
 }
 
-static void showSubTracks(struct trackHub *hub, char *db, struct trackDb *tdb, struct hash *countTracks,
-    char *chromName, long long chromSize, char *errorString)
-/* tdb has subtracks, show only subTracks, no details */
-{
-hPrintf("    <li><ul>\n");
-if (debug)
-    hPrintf("    <li>subtracks for '%s' db: '%s'</li>\n", tdb->track, db);
-if (tdb->subtracks)
+static void hubSampleUrl(struct trackHub *hub, struct trackDb *tdb,
+    long chromCount, long itemCount, char *chromName, unsigned chromSize,
+      char *genome, char *errorString)
 {
-    struct trackDb *tdbEl = NULL;
-    for (tdbEl = tdb->subtracks; tdbEl; tdbEl = tdbEl->next)
+unsigned start = chromSize / 4;
+unsigned end = start + 10000;
+if (end > chromSize)
+    end = chromSize;
+
+char errorPrint[2048];
+errorPrint[0] = 0;
+
+if (isNotEmpty(errorString))
     {
-        if (tdbIsCompositeView(tdbEl))
-	    hPrintf("<li>%s : %s : composite view of parent: %s</li>\n", tdbEl->track, tdbEl->type, tdbEl->parent->track);
-	else
+    safef(errorPrint, sizeof(errorPrint), " : <font color='red'>ERROR: %s</font>", errorString);
+    }
+
+char countsMessage[512];
+countsMessage[0] = 0;
+if (chromCount > 0 || itemCount > 0)
     {
-	    if (isSupportedType(tdbEl->type))
-		sampleUrl(hub, db, tdbEl, chromName, chromSize, errorString);
+    if (startsWithWord("bigBed", tdb->type))
+        safef(countsMessage, sizeof(countsMessage), " : %ld chroms : %ld item count ", chromCount, itemCount);
+    else if (startsWithWord("bigWig", tdb->type))
+        safef(countsMessage, sizeof(countsMessage), " : %ld chroms : %ld bases covered ", chromCount, itemCount);
     else
-		hPrintf("<li>%s : %s : subtrack of parent: %s</li>\n", tdbEl->track, tdbEl->type, tdbEl->parent->track);
-	    }
-	hashCountTrack(tdbEl, countTracks);
-        if (tdbEl->subtracks)
-	    showSubTracks(hub, db, tdbEl, countTracks, chromName, chromSize, errorString);
-	}
-    }
-hPrintf("    </ul></li>\n");
+        safef(countsMessage, sizeof(countsMessage), " : %ld chroms : %ld count ", chromCount, itemCount);
     }
 
-static void trackSettings(struct trackDb *tdb, struct hash *countTracks)
-/* process the settingsHash for a trackDb, recursive when subtracks */
-{
-hPrintf("    <li><ul>\n");
-// if (tdb->children)  haven't yet seen a track with children ?
-//   hPrintf("    <li>%s: has children</li>\n", tdb->track);
-// else
-//   hPrintf("    <li>%s: NO children</li>\n", tdb->track);
-struct hashEl *hel;
-struct hashCookie hc = hashFirst(tdb->settingsHash);
-while ((hel = hashNext(&hc)) != NULL)
+if (isSupportedType(tdb->type))
     {
-    if (sameWord("track", hel->name))
-	continue;	// already output in header
-    if (isEmpty((char *)hel->val))
-	hPrintf("    <li>%s : &lt;empty&gt;</li>\n", hel->name);
+	char urlReference[2048];
+	safef(urlReference, sizeof(urlReference), "<a href='%s/getData/track?hubUrl=%s&amp;genome=%s&amp;track=%s&amp;chrom=%s&amp;start=%u&amp;end=%u' target=_blank>(sample getData)%s</a>\n", urlPrefix, hub->url, genome, tdb->track, chromName, start, end, errorPrint);
+
+        if (startsWithWord("bigBed", tdb->type))
+            hPrintf("    <li>%s : %s%s%s</li>\n", tdb->track, tdb->type, countsMessage, urlReference);
+        else if (startsWithWord("bigWig", tdb->type))
+            hPrintf("    <li>%s : %s%s%s</li>\n", tdb->track, tdb->type, countsMessage, urlReference);
         else
-	hPrintf("    <li>%s : '%s'</li>\n", hel->name, (char *)hel->val);
+            hPrintf("    <li>%s : %s%s%s</li>\n", tdb->track, tdb->type, countsMessage, urlReference);
     }
-if (tdb->subtracks)
-    {
-    struct trackDb *tdbEl = NULL;
-    if (debug)
-	hPrintf("   <li>has %d subtrack(s)</li>\n", slCount(tdb->subtracks));
-    for (tdbEl = tdb->subtracks; tdbEl; tdbEl = tdbEl->next)
+else
     {
-        hPrintf("<li>subtrack: %s of parent: %s : type: '%s'</li>\n", tdbEl->track, tdbEl->parent->track, tdbEl->type);
-	hashCountTrack(tdbEl, countTracks);
-	trackSettings(tdbEl, countTracks);
-	}
-    }
-hPrintf("    </ul></li>\n");
+        if (startsWithWord("bigBed", tdb->type))
+            hPrintf("    <li>%s : %s%s</li>\n", tdb->track, tdb->type, countsMessage);
+        else if (startsWithWord("bigWig", tdb->type))
+            hPrintf("    <li>%s : %s%s</li>\n", tdb->track, tdb->type, countsMessage);
+        else
+            hPrintf("    <li>%s : %s%s</li>\n", tdb->track, tdb->type, countsMessage);
     }
+}	/* static void hubSampleUrl(struct trackHub *hub, struct trackDb *tdb,
+	 * long chromCount, long itemCount, char *chromName, unsigned chromSize,
+	 *   char *genome)
+	 */
 
 static void bbiBiggestChrom(struct bbiChromInfo *chromList, char **chromName,
     unsigned *chromSize)
 /* find largest chromosome name and size in the chromList */
 {
 if (chromName && chromSize)
     {
     *chromSize = 0;
     char *returnName = NULL;
     struct bbiChromInfo *el;
     for (el = chromList; el; el = el->next)
 	{
 	if (el->size > *chromSize)
 	    { 
 	    *chromSize = el->size;
@@ -425,149 +418,222 @@
         retVal = 1;
         }
 
     }
 errCatchEnd(errCatch);
 if (errCatch->gotError)
     {
     retVal = 1;
     dyStringPrintf(errors, "%s", errCatch->message->string);
     }
 errCatchFree(&errCatch);
 
 return retVal;
 }	/* static int bbiBriefMeasure() */
 
-static void hubSampleUrl(struct trackHub *hub, struct trackDb *tdb,
-    long chromCount, long itemCount, char *chromName, unsigned chromSize,
-      char *genome, char *errorString)
+static void hubSubTracks(struct trackHub *hub, char *db, struct trackDb *tdb,
+    struct hash *countTracks,  long chromCount, long itemCount,
+    char *chromName, unsigned chromSize, char *genome, char *errorString)
+/* tdb has subtracks, show only subTracks, no details */
 {
-unsigned start = chromSize / 4;
-unsigned end = start + 10000;
-if (end > chromSize)
-    end = chromSize;
-
-char errorPrint[2048];
-errorPrint[0] = 0;
-
-if (isNotEmpty(errorString))
+hPrintf("    <li><ul>\n");
+if (debug)
     {
-    safef(errorPrint, sizeof(errorPrint), " : <font color='red'>ERROR: %s</font>", errorString);
+    hPrintf("    <li>subtracks for '%s' db: '%s'</li>\n", tdb->track, db);
+    hPrintf("    <li>chrom: '%s' size: %u</li>\n", chromName, chromSize);
     }
-
-if (isSupportedType(tdb->type))
+if (tdb->subtracks)
     {
-        if (startsWithWord("bigBed", tdb->type))
-            hPrintf("    <li>%s : %s : %ld chroms : %ld item count <a href='%s/getData/track?hubUrl=%s&amp;genome=%s&amp;track=%s&amp;chrom=%s&amp;start=%u&amp;end=%u' target=_blank>(sample getData)%s</a></li>\n", tdb->track, tdb->type, chromCount, itemCount, urlPrefix, hub->url, genome, tdb->track, chromName, start, end, errorPrint);
-        else if (startsWithWord("bigWig", tdb->type))
-            hPrintf("    <li>%s : %s : %ld chroms : %ld bases covered <a href='%s/getData/track?hubUrl=%s&amp;genome=%s&amp;track=%s&amp;chrom=%s&amp;start=%u&amp;end=%u' target=_blank>(sample getData)%s</a></li>\n", tdb->track, tdb->type, chromCount, itemCount, urlPrefix, hub->url, genome, tdb->track, chromName, start, end, errorPrint);
+    struct trackDb *tdbEl = NULL;
+    for (tdbEl = tdb->subtracks; tdbEl; tdbEl = tdbEl->next)
+	{
+	boolean compositeContainer = tdbIsComposite(tdbEl);
+	boolean compositeView = tdbIsCompositeView(tdbEl);
+	if (! (compositeContainer || compositeView) )
+	    {
+	    if (chromSize < 1)
+		{
+		char *bigDataIndex = NULL;
+		char *relIdxUrl = trackDbSetting(tdbEl, "bigDataIndex");
+		if (relIdxUrl != NULL)
+		    bigDataIndex = trackHubRelativeUrl(hub->genomeList->trackDbFile, relIdxUrl);
+		char *bigDataUrl = trackDbSetting(tdbEl, "bigDataUrl");
+		char *longName = NULL;
+		unsigned longSize = 0;
+		struct dyString *errors = newDyString(1024);
+		(void) bbiBriefMeasure(tdbEl->type, bigDataUrl, bigDataIndex, &chromCount, &itemCount, errors, &longName, &longSize);
+		chromSize = longSize;
+		chromName = longName;
+		}
+	    }
+        if (tdbIsCompositeView(tdbEl))
+	    hPrintf("<li>%s : %s : composite view of parent: %s</li>\n", tdbEl->track, tdbEl->type, tdbEl->parent->track);
 	else
-            hPrintf("    <li>%s : %s : %ld chroms : %ld count <<a href='%s/getData/track?hubUrl=%s&amp;genome=%s&amp;track=%s&amp;chrom=%s&amp;start=%u&amp;end=%u' target=_blank>(sample getData)%s</a></li>\n", tdb->track, tdb->type, chromCount, itemCount, urlPrefix, hub->url, genome, tdb->track, chromName, start, end, errorPrint);
+	    {
+	    if (isSupportedType(tdbEl->type))
+		hubSampleUrl(hub, tdbEl, chromCount, itemCount, chromName, chromSize, genome, errorString);
+	    else
+		hPrintf("<li>%s : %s : subtrack of parent: %s</li>\n", tdbEl->track, tdbEl->type, tdbEl->parent->track);
 	    }
+	hashCountTrack(tdbEl, countTracks);
+        if (tdbEl->subtracks)
+	    hubSubTracks(hub, db, tdbEl, countTracks, chromCount, itemCount, chromName, chromSize, genome, errorString);
+	}
+    }
+hPrintf("    </ul></li>\n");
+}	/* hubSubTracks() */
+
+static void showSubTracks(struct trackHub *hub, char *db, struct trackDb *tdb, struct hash *countTracks,
+    char *chromName, unsigned chromSize, char *errorString)
+/* tdb has subtracks, show only subTracks, no details */
+{
+hPrintf("    <li><ul>\n");
+if (debug)
+    hPrintf("    <li>subtracks for '%s' db: '%s'</li>\n", tdb->track, db);
+if (tdb->subtracks)
+    {
+    struct trackDb *tdbEl = NULL;
+    for (tdbEl = tdb->subtracks; tdbEl; tdbEl = tdbEl->next)
+	{
+        if (tdbIsCompositeView(tdbEl))
+	    hPrintf("<li>%s : %s : composite view of parent: %s</li>\n", tdbEl->track, tdbEl->type, tdbEl->parent->track);
 	else
 	    {
-        if (startsWithWord("bigBed", tdb->type))
-            hPrintf("    <li>%s : %s : %ld chroms : %ld item count</li>\n", tdb->track, tdb->type, chromCount, itemCount);
-        else if (startsWithWord("bigWig", tdb->type))
-            hPrintf("    <li>%s : %s : %ld chroms : %ld bases covered</li>\n", tdb->track, tdb->type, chromCount, itemCount);
+	    if (isSupportedType(tdbEl->type))
+		sampleUrl(hub, db, tdbEl, chromName, chromSize, errorString);
 	    else
-            hPrintf("    <li>%s : %s : %ld chroms : %ld count</li>\n", tdb->track, tdb->type, chromCount, itemCount);
+		hPrintf("<li>%s : %s : subtrack of parent: %s</li>\n", tdbEl->track, tdbEl->type, tdbEl->parent->track);
+	    }
+	hashCountTrack(tdbEl, countTracks);
+        if (tdbEl->subtracks)
+	    showSubTracks(hub, db, tdbEl, countTracks, chromName, chromSize, errorString);
+	}
+    }
+hPrintf("    </ul></li>\n");
+}
+
+static void trackSettings(struct trackDb *tdb, struct hash *countTracks)
+/* process the settingsHash for a trackDb, recursive when subtracks */
+{
+hPrintf("    <li><ul>\n");
+// if (tdb->children)  haven't yet seen a track with children ?
+//   hPrintf("    <li>%s: has children</li>\n", tdb->track);
+// else
+//   hPrintf("    <li>%s: NO children</li>\n", tdb->track);
+struct hashEl *hel;
+struct hashCookie hc = hashFirst(tdb->settingsHash);
+while ((hel = hashNext(&hc)) != NULL)
+    {
+    if (sameWord("track", hel->name))
+	continue;	// already output in header
+    if (isEmpty((char *)hel->val))
+	hPrintf("    <li>%s : &lt;empty&gt;</li>\n", hel->name);
+    else
+	hPrintf("    <li>%s : '%s'</li>\n", hel->name, (char *)hel->val);
+    }
+if (tdb->subtracks)
+    {
+    struct trackDb *tdbEl = NULL;
+    if (debug)
+	hPrintf("   <li>has %d subtrack(s)</li>\n", slCount(tdb->subtracks));
+    for (tdbEl = tdb->subtracks; tdbEl; tdbEl = tdbEl->next)
+	{
+        hPrintf("<li>subtrack: %s of parent: %s : type: '%s'</li>\n", tdbEl->track, tdbEl->parent->track, tdbEl->type);
+	hashCountTrack(tdbEl, countTracks);
+	trackSettings(tdbEl, countTracks);
+	}
+    }
+hPrintf("    </ul></li>\n");
 }
-}	/* static void hubSampleUrl(struct trackHub *hub, struct trackDb *tdb,
-	 * long chromCount, long itemCount, char *chromName, unsigned chromSize,
-	 *   char *genome)
-	 */
 
 static void hubCountOneTdb(struct trackHub *hub, char *db, struct trackDb *tdb,
     char *bigDataIndex, struct hash *countTracks, char *chromName,
     unsigned chromSize, char *genome)
 {
 char *bigDataUrl = trackDbSetting(tdb, "bigDataUrl");
 // char *compositeTrack = trackDbSetting(tdb, "compositeTrack");
 boolean compositeContainer = tdbIsComposite(tdb);
 boolean compositeView = tdbIsCompositeView(tdb);
 // char *superTrack = trackDbSetting(tdb, "superTrack");
 boolean superChild = tdbIsSuperTrackChild(tdb);
 boolean depthSearch = cartUsualBoolean(cart, "depthSearch", FALSE);
 hashCountTrack(tdb, countTracks);
 
-char *longName = NULL;
-unsigned longSize = 0;
 long chromCount = 0;
 long itemCount = 0;
 
 struct dyString *errors = newDyString(1024);
 
+/* if given a chromSize, it belongs to a UCSC db and this is *not* an
+ *   assembly hub, otherwise, look up a chrom and size in the bbi file
+ */
 if (! (compositeContainer || compositeView) )
+    {
+    if (chromSize < 1 || depthSearch)
+	{
+	char *longName = NULL;
+	unsigned longSize = 0;
         (void) bbiBriefMeasure(tdb->type, bigDataUrl, bigDataIndex, &chromCount, &itemCount, errors, &longName, &longSize);
+	chromSize = longSize;
+	chromName = longName;
+	}
+    }
 
 if (depthSearch && bigDataUrl)
     {
     if (isSupportedType(tdb->type))
-	{
-	if (chromSize > 0)
 	    hubSampleUrl(hub, tdb, chromCount, itemCount, chromName, chromSize, genome, errors->string);
-	else
-	    hubSampleUrl(hub, tdb, chromCount, itemCount, longName, longSize, genome, errors->string);
-	}
     }
 else
     {
     if (compositeContainer)
         hPrintf("    <li>%s : %s : composite track container has %d subtracks</li>\n", tdb->track, tdb->type, slCount(tdb->subtracks));
     else if (compositeView)
         hPrintf("    <li>%s : %s : composite view of parent: %s</li>\n", tdb->track, tdb->type, tdb->parent->track);
     else if (superChild)
         hPrintf("    <li>%s : %s : superTrack child of parent: %s (sample getData)</li>\n", tdb->track, tdb->type, tdb->parent->track);
     else if (! depthSearch && bigDataUrl)
 	{
         if (isSupportedType(tdb->type))
 	    {
-	    if (chromSize > 0)
 	    hubSampleUrl(hub, tdb, chromCount, itemCount, chromName, chromSize, genome, errors->string);
-	    else
-		hubSampleUrl(hub, tdb, chromCount, itemCount, longName, longSize, genome, errors->string);
 	    }
-        // hPrintf("    <li>%s : %s : %s (maybe sample ?)</li>\n", tdb->track, tdb->type, bigDataUrl);
 	}
     else
 	{
         if (isSupportedType(tdb->type))
 	    {
-	    if (chromSize > 0)
 	    hubSampleUrl(hub, tdb, chromCount, itemCount, chromName, chromSize, genome, errors->string);
-	    else
-		hubSampleUrl(hub, tdb, chromCount, itemCount, longName, longSize, genome, errors->string);
 	    }
 	else
 	    hPrintf("    <li>%s : %s (what is this)</li>\n", tdb->track, tdb->type);
         }
     }
 if (allTrackSettings)
     {
     hPrintf("    <li><ul>\n");
     trackSettings(tdb, countTracks); /* show all settings */
     hPrintf("    </ul></li>\n");
     }
 else if (tdb->subtracks)
     {
-    showSubTracks(hub, db, tdb, countTracks, chromName, chromSize, errors->string);
+    hubSubTracks(hub, db, tdb, countTracks, chromCount, itemCount, chromName, chromSize, genome, errors->string);
     }
 return;
 }	/*	static void hubCountOneTdb(char *db, struct trackDb *tdb,
 	 *	char *bigDataIndex, struct hash *countTracks,
-	 *	char *chromName, long long chromSize)
+	 *	char *chromName, unsigned chromSize)
 	 */
 
 
 static void countOneTdb(char *db, struct trackDb *tdb,
     struct hash *countTracks, char *chromName, unsigned chromSize,
       char *errorString)
 /* for this tdb in this db, count it up and provide a sample */
 {
 char *bigDataUrl = trackDbSetting(tdb, "bigDataUrl");
 // char *compositeTrack = trackDbSetting(tdb, "compositeTrack");
 boolean compositeContainer = tdbIsComposite(tdb);
 boolean compositeView = tdbIsCompositeView(tdb);
 // char *superTrack = trackDbSetting(tdb, "superTrack");
 boolean superChild = tdbIsSuperTrackChild(tdb);
 boolean depthSearch = cartUsualBoolean(cart, "depthSearch", FALSE);
@@ -710,53 +776,44 @@
 struct trackHubGenome *genome = hubTop->genomeList;
 
 hPrintf("<h4>genome sequences (and tracks) present in this track hub</h4>\n");
 
 if (NULL == genome)
     {
     hPrintf("<h4>odd error, can not find a gnomeList ? at url: '%s'</h4>\n", hubTop->url);
     return;
     }
 
 hPrintf("<ul>\n");
 long lastTime = clock1000();
 for ( ; genome; genome = genome->next )
     {
     ++totalAssemblyCount;
-#ifdef NOT
-    char *twoBitPath;  /* URL to twoBit.  If not null, this is an assmebly hub*/
-    struct twoBitFile *tbf;  /* open handle to two bit file */
-    char *groups;	     /* URL to group.txt file */
-    char *defaultPos;        /* default position */
-    char *organism;          /* organism name, like Human */
-    char *description;       /* description, also called freeze name */
-    struct trackHub *trackHub; /* associated track hub */
-#endif
     if (isNotEmpty(genome->twoBitPath))
 	{
 	hPrintf("<li>assembly hub twoBitFile: %s</li>\n", genome->twoBitPath);
 	}
     if (genome->organism)
 	{
 	hPrintf("<li>%s - %s - %s</li>\n", genome->organism, genome->name, genome->description);
 	}
     else
 	{	/* can there be a description when organism is empty ? */
 	hPrintf("<li>name: %s</li>\n", genome->name);
 	}
     hubAssemblySettings(hubTop, genome);
-    if (measureTiming)
+    if (measureTiming || debug)
 	{
 	long thisTime = clock1000();
 	hPrintf("<li><em>processing time %s: %ld millis</em></li>\n", genome->name, thisTime - lastTime);
 	}
     if (timeOutReached())
 	break;
     }
 if (trackCounter->elCount)
     {
     hPrintf("    <li>total genome assembly count: %ld</li>\n", totalAssemblyCount);
     hPrintf("    <li>%ld total tracks counted, %d different track types:</li>\n", totalTracks, trackCounter->elCount);
     hPrintf("    <li><ol>\n");
     struct hashEl *hel, *helList = hashElListHash(trackCounter);
     slSort(&helList, hashElCmpIntValDesc);
     for (hel = helList; hel; hel = hel->next)
@@ -921,38 +978,43 @@
 hPrintf("<h3>Supported track types, at this time, for getData functions:</h3>\n");
 hPrintf("<ul>\n");
 static struct slName *el;
 for (el = supportedTypes; el; el = el->next)
     {
     hPrintf("<li>%s</li>\n", el->name);
     }
 hPrintf("</ul>\n");
 }
 
 static void initUrlPrefix()
 /* set up urlPrefix for self referenes */
 {
 char *httpHost = getenv("HTTP_HOST");
 
+if (isEmpty(httpHost))
+    urlPrefix = "";
+else
+    {
     if (! startsWith("hgwdev-api", httpHost))
 	{
 	if (startsWith("hgwdev",httpHost) || startsWith("genome-test", httpHost))
 	    {
 	    urlPrefix = "../cgi-bin/hubApi";
 	    }
 	}
     }
+}
 
 static void showExamples(char *url, struct trackHubGenome *hubGenome, char *ucscDb)
 {
 hPrintf("<h2>Example URLs to return json data structures:</h2>\n");
 
 hPrintf("<h3>listing functions</h3>\n");
 hPrintf("<ol>\n");
 hPrintf("<li><a href='%s/list/publicHubs' target=_blank>list public hubs</a> <em>%s/list/publicHubs</em></li>\n", urlPrefix, urlPrefix);
 hPrintf("<li><a href='%s/list/ucscGenomes' target=_blank>list database genomes</a> <em>%s/list/ucscGenomes</em></li>\n", urlPrefix, urlPrefix);
 hPrintf("<li><a href='%s/list/hubGenomes?hubUrl=%s' target=_blank>list genomes from specified hub</a> <em>%s/list/hubGenomes?hubUrl=%s</em></li>\n", urlPrefix, url, urlPrefix, url);
 hPrintf("<li><a href='%s/list/tracks?hubUrl=%s&amp;genome=%s' target=_blank>list tracks from specified hub and genome</a> <em>%s/list/tracks?hubUrl=%s&amp;genome=%s</em></li>\n", urlPrefix, url, hubGenome->name, urlPrefix, url, hubGenome->name);
 hPrintf("<li><a href='%s/list/tracks?db=%s' target=_blank>list tracks from specified UCSC database</a> <em>%s/list/tracks?db=%s</em></li>\n", urlPrefix, ucscDb, urlPrefix, ucscDb);
 hPrintf("<li><a href='%s/list/chromosomes?db=%s' target=_blank>list chromosomes from specified UCSC database</a> <em>%s/list/chromosomes?db=%s</em></li>\n", urlPrefix, ucscDb, urlPrefix, ucscDb);
 hPrintf("<li><a href='%s/list/chromosomes?db=%s&amp;track=gold' target=_blank>list chromosomes from specified track from UCSC databaset</a> <em>%s/list/chromosomes?db=%s&amp;track=gold</em></li>\n", urlPrefix, ucscDb, urlPrefix, ucscDb);
 hPrintf("</ol>\n");
@@ -997,30 +1059,34 @@
 cart = theCart;
 measureTiming = hPrintStatus() && isNotEmpty(cartOptionalString(cart, "measureTiming"));
 measureTiming = TRUE;
 char *database = NULL;
 char *genome = NULL;
 
 cgiVarSet("ignoreCookie", "1");
 
 getDbAndGenome(cart, &database, &genome, oldVars);
 initGenbankTableNames(database);
 initSupportedTypes();
 initUrlPrefix();
 
 /* global variable for all workers to honor this limit */
 maxItemsOutput = cartUsualInt(cart, "maxItemsOutput", maxItemsOutput);
+if (maxItemsOutput > maxItemLimit)	/* safety check */
+    maxItemsOutput = maxItemLimit;
+if (maxItemsOutput < 1)	/* safety check */
+    maxItemsOutput = 1;
 
 debug = cartUsualBoolean(cart, "debug", debug);
 int timeout = cartUsualInt(cart, "udcTimeout", 300);
 if (udcCacheTimeout() < timeout)
     udcSetCacheTimeout(timeout);
 knetUdcInstall();
 
 char *pathInfo = getenv("PATH_INFO");
 /* nothing on incoming path, then display the WEB page instead */
 if (sameOk("/",pathInfo))
     pathInfo = NULL;
 
 boolean commandError = FALSE;
 /*expect no more than MAX_PATH_INFO number of words*/
 char *words[MAX_PATH_INFO];
@@ -1107,31 +1173,31 @@
 char *urlDropDown = urlFromShortLabel(hubDropDown);
 char *ucscDb = cartUsualString(cart, "ucscGenomes", defaultDb);
 char *urlInput = urlDropDown;	/* assume public hub */
 if (sameWord("go", goOtherHub))	/* requested other hub URL */
     urlInput = otherHubUrl;
 else if (isEmpty(otherHubUrl))
     otherHubUrl = urlInput;
 
 if (commandError)
   {
   hPrintf("<h3>ERROR: no such command: '%s/%s' for endpoint '%s'</h3>", words[0], words[1], pathInfo);
   }
 
 long lastTime = clock1000();
 struct trackHub *hub = errCatchTrackHubOpen(urlInput);
-if (measureTiming)
+if (measureTiming || debug)
     {
     long thisTime = clock1000();
     if (debug)
        hPrintf("<em>hub open time: %ld millis</em><br>\n", thisTime - lastTime);
     }
 
 // hPrintf("<h3>ucscDb: '%s'</h2>\n", ucscDb);
 
 struct trackHubGenome *hubGenome = hub->genomeList;
 
 introductionText();
 
 showExamples(urlInput, hubGenome, ucscDb);
 
 if (debug)
@@ -1199,31 +1265,31 @@
 else
     {
     hPrintf("<h4>Examine %s at: %s</h4>\n", sameWord("go",goPublicHub) ? "public hub" : "other hub", urlInput);
     hPrintf("<ul>\n");
     hPrintf("<li>%s</li>\n", hub->shortLabel);
     hPrintf("<li>%s</li>\n", hub->longLabel);
     if (isNotEmpty(hub->defaultDb))
         hPrintf("<li>%s - default database</li>\n", hub->defaultDb);
     hPrintf("</ul>\n");
 
     genomeList(hub);
     }
 
 if (timedOut)
     hPrintf("<h1>Reached time out %ld seconds</h1>", timeOutSeconds);
-if (measureTiming)
+if (measureTiming || debug)
     hPrintf("<em>Overall total time: %ld millis</em><br>\n", clock1000() - enteredMainTime);
 
 hPrintf("</p>\n");
 
 cartWebEnd();
 }	/*	void doMiddle(struct cart *theCart)	*/
 
 /* Null terminated list of CGI Variables we don't want to save
  * permanently. */
 static char *excludeVars[] = {"Submit", "submit", "goOtherHub", "goPublicHub", "goUcscDb", "ucscGenomes", "publicHubs", NULL,};
 
 int main(int argc, char *argv[])
 /* Process command line. */
 {
 enteredMainTime = clock1000();