You have already generated an api key for use in hubtools. If you would like to generate a new key (which automatically revokes old keys), please click 'generate key'. Otherwise, you can copy and paste the below key to your ~/.hubtools.conf file: ");
puts("
");
printf("%s\n", existingKey);
puts("
");
puts("
");
puts("
Generate an api key
");
}
else
{
puts("
To use the hubtools up command, click 'generate key'");
puts("
");
printf("
Now, create a file ~/.hubtools.conf and add the key: \n", existingKey != NULL ? "block" : "none");
puts("
");
puts("
");
}
printf("
\nTo revoke any apiKeys associated with your account, click the revoke button: \n
", existingKey != NULL ? "block" : "none");
// add the event handlers for clicking the generate/revoke buttons
jsInlineF(""
"document.getElementById('generateApiKey').addEventListener('click', generateApiKey);\n"
"document.getElementById('revokeApiKeys').addEventListener('click', revokeApiKeys);\n"
);
}
puts("
"); // tabSection apiKey
}
void hgHubConnectDeveloperMode()
/* Put up the controls for the "Hub Development" Tab, which includes a button to run the
* hubCheck utility on a hub and load a hub with the udcTimeout and measureTiming
* variables turned on */
{
// put out the top of our page
char *hubUrl = cartOptionalString(cart, "validateHubUrl");
// the outer div for all the elements in the tab
puts("
\n"
" You may also contact us if you have any "
"issues or questions on hub development.");
puts("
"); // .tabSection
puts("
");
puts("
Check a hub for errors
");
printf("");
printf("\n", hubUrlVal);
printf("\n");
printf("  Load Example URL\n");
puts("
Use the URL bar above to check a hub for errors. This will "
"validate the hub's configuration files, including hub.txt, "
"genomes.txt and trackDb.txt. "
"It will also present a hierarchical tree of tracks with any errors in red. A hub "
"with no errors still shows the tree which can be used to explore the track hierarchy. "
"Hub error checking will always refresh the files and never use our remote file cache (see below)."
"
\n "
);
puts("
"); // .tabSection
puts("
");
puts("
Enable Genome Browser debugging modes
");
puts("
These apply to all connected hubs. By default, caching is activated and track load times are not shown, but you can change these settings while developing your hub:
");
puts("
");
puts("");
puts("
"); // margin-left
puts("
"); // tabSection
jsOnEventById("click", "hubValidateButton", "makeIframe(event)");
// API Key section
-if (cfgOptionBooleanDefault("showHubApiKey", FALSE)) // This should probably not be shown on mirrors, so default to FALSE
+
+if (cfgOptionBooleanDefault("storeUserFiles", FALSE) && cfgOptionBooleanDefault("showHubApiKey", FALSE)) // This should probably not be shown on mirrors, so default to FALSE
printApiKeySection();
puts("
"); // hub developement tab
}
void printSearchAndFilterBoxes(int searchEnabled, char *hubSearchTerms, char *dbFilter)
/* Create the text boxes for search and database filtering along with the required
* javscript */
{
printf("");
}
void printSearchTerms(char *hubSearchTerms)
/* Write out a reminder about the current search terms and a note about
* how to navigate detailed search results */
{
printf("Displayed list restricted by above search terms \n");
puts("\n");
jsOnEventById("click", "hubDeleteSearchButton",
"document.searchHubForm.elements['hubSearchTerms'].value='';"
"document.searchHubForm.elements['hubDbFilter'].value='';"
"document.searchHubForm.submit();return true;");
puts("
\n");
printf("When exploring the detailed search results for a hub, you may right-click "
"on an assembly or track line to open it in a new window.\n");
puts("
\n");
}
void printHubListHeader()
/* Write out the header for a list of hubs in its own table */
{
puts("
"
"
"
"
Display
"
"
Hub Name
"
"
Description
"
"
AssembliesClick to connect and browse directly
"
"
");
}
void printHubListFooter()
/* Write out the header for a list of hubs in its own table */
{
puts("
");
}
void outputPublicTableRow(struct hubEntry *hubInfo, int count)
/* Prints out a table row with basic information about a hub and a button
* to connect to that hub */
{
int id = hubInfo->id;
char jsId[256];
struct slName *dbListNames = slNameListFromComma(hubInfo->dbList);
printf("
\n");
if (id != 0)
{
ourCellStart();
char hubName[32];
safef(hubName, sizeof(hubName), "%s%u", hgHubConnectHubVarPrefix, id);
if (cartUsualBoolean(cart, hubName, FALSE))
{
safef(jsId, sizeof jsId, "hubDisconnectButtonP%d", count);
printf("\n", jsId);
jsOnEventByIdF("click", jsId,
"document.disconnectHubForm.elements['hubId'].value= '%d';"
"document.disconnectHubForm.submit();return true;", id);
}
else
{
// get first name off of list of supported databases
char * name = dbListNames->name;
// if the name isn't currently loaded, we assume it's a hub
if (!hDbExists(name))
{
char buffer[512];
safef(buffer, sizeof buffer, "hub_%d_%s", id, name);
name = cloneString(buffer);
}
safef(jsId, sizeof jsId, "hubConnectButton%d", count);
printf("\n", jsId);
jsOnEventByIdF("click", jsId,
"document.connectHubForm.elements['hubUrl'].value= '%s';"
"document.connectHubForm.elements['db'].value= '%s';"
"document.connectHubForm.submit();return true;", hubInfo->hubUrl,name);
}
ourCellEnd();
}
else
errAbort("cannot get id for hub with url %s\n", hubInfo->hubUrl);
ourPrintCellLink(hubInfo->shortLabel, hubInfo->hubUrl);
boolean hubHasNoError = isEmpty(hubInfo->errorMessage);
if (hubHasNoError)
{
if (hubInfo->tableHasDescriptionField && !isEmpty(hubInfo->descriptionUrl))
ourPrintCellLink(hubInfo->longLabel, hubInfo->descriptionUrl);
else
ourPrintCell(hubInfo->longLabel);
}
else
{
ourCellStart();
printf("ERROR: %s "
"Debug Help",
hubInfo->errorMessage);
safef(jsId, sizeof jsId, "hubClearButton%d", count);
printf(
""
, jsId);
jsOnEventByIdF("click", jsId,
"document.resetHubForm.elements['hubCheckUrl'].value='%s';"
"document.resetHubForm.submit();return true;", hubInfo->hubUrl);
ourCellEnd();
}
printGenomeList(hubInfo->hubUrl, dbListNames, count, hubHasNoError, FALSE);
printf("
\n");
}
struct trackHub *fetchTrackHub(struct hubEntry *hubInfo)
/* Fetch the hub structure for a public hub, trapping the error
* if the hub cannot be reached */
{
struct errCatch *errCatch = errCatchNew();
struct trackHub *hub = NULL;
if (errCatchStart(errCatch))
{
char hubName[4096];
safef(hubName, sizeof(hubName), "hub_%d", hubInfo->id);
hub = trackHubOpen(hubInfo->hubUrl, hubName);
}
errCatchEnd(errCatch);
if (errCatch->gotError)
{
fprintf(stderr, "%s\n", errCatch->message->string);
}
errCatchFree(&errCatch);
return hub;
}
char *getPositionStringForDb(struct trackHubGenome *genome)
{
char positionVar[1024];
safef(positionVar, sizeof(positionVar), "position.%s", genome->name);
char *position = cartOptionalString(cart, positionVar);
if (position == NULL)
{
struct dyString *tmp = dyStringCreate("position=");
if (genome->defaultPos != NULL)
dyStringAppend(tmp, genome->defaultPos);
else
dyStringAppend(tmp, hDefaultPos(genome->name)); // memory leak from hDefaultPos return value
position = dyStringCannibalize(&tmp);
}
return position;
}
struct tdbOutputStructure *hstToTdbOutput(struct hubSearchText *hst, struct genomeOutputStructure *genomeOut, struct trackHub *hub)
/* Convert a hubSearchText entry to a (list of) tdbOutputStructure(s) */
{
struct tdbOutputStructure *tdbOut = hashFindVal(genomeOut->tdbOutHash, hst->track);
if (tdbOut == NULL)
{
genomeOut->trackCount++;
AllocVar(tdbOut);
tdbOut->shortLabel = dyStringNew(0);
tdbOut->metaTags = dyStringNew(0);
tdbOut->descriptionMatch = dyStringNew(0);
tdbOut->configUrl = dyStringNew(0);
dyStringPrintf(tdbOut->shortLabel, "%s", hst->label);
char *hubId = hubNameFromUrl(hub->url);
if (isNotEmpty(hst->parents))
{
// hst->parents is a comma-sep list like "track1","track1Label","track2","track2Label"
int i;
int parentCount;
int parentTypesCount;
char *parentTrack = NULL;
char *parentLabel = NULL;
char *parentTrackLabels[16]; // 2 slots per parent, can tracks nest more than 8 deep?
char *parentTypes[16]; // the types of parents, "comp", "super", "view", "other" for each track in parentTrackLabels
struct tdbOutputStructure *parentTdbOut = NULL;
struct tdbOutputStructure *savedParent = NULL;
parentCount = chopByCharRespectDoubleQuotes(cloneString(hst->parents), ',', parentTrackLabels, sizeof(parentTrackLabels));
parentTypesCount = chopCommas(cloneString(hst->parentTypes), parentTypes);
if (parentCount == 0 || parentCount % 2 != 0)
{
errAbort("error parsing hubSearchText->parents for %s.%s in hub: '%s'",
genomeOut->genomeName, hst->track, hub->url);
}
if (parentTypesCount != (parentCount / 2))
{
errAbort("error parsing hubSearchText->parentTypes: '%s' for %s.%s in hub: '%s'",
hst->parentTypes, genomeOut->genomeName, hst->track, hub->url);
}
boolean foundParent = FALSE;
boolean doAddSaveParent = FALSE;
for (i = 0; i < parentCount; i += 2)
{
parentTrack = stripEnclosingDoubleQuotes(cloneString(parentTrackLabels[i]));
parentLabel = stripEnclosingDoubleQuotes(cloneString(parentTrackLabels[i+1]));
// wait until the first valid trackui page for the track hit
if (isEmpty(dyStringContents(tdbOut->configUrl)) && sameString(parentTypes[i/2], "comp"))
{
dyStringPrintf(tdbOut->configUrl, "../cgi-bin/hgTrackUi?hubUrl=%s&db=%s&g=%s_%s&hgsid=%s&%s",
hub->url, genomeOut->genomeName, hubId, parentTrack, cartSessionId(cart),
genomeOut->positionString);
}
else if (isEmpty(dyStringContents(tdbOut->configUrl)) && sameString(parentTypes[i/2], "super"))
{
dyStringPrintf(tdbOut->configUrl, "../cgi-bin/hgTrackUi?hubUrl=%s&db=%s&g=%s_%s&hgsid=%s&%s",
hub->url, genomeOut->genomeName, hubId, hst->track, cartSessionId(cart),
genomeOut->positionString);
}
parentTdbOut = hashFindVal(genomeOut->tdbOutHash, parentTrack);
if (parentTdbOut == NULL)
{
AllocVar(parentTdbOut);
parentTdbOut->shortLabel = dyStringNew(0);
parentTdbOut->metaTags = dyStringNew(0);
parentTdbOut->descriptionMatch = dyStringNew(0);
parentTdbOut->configUrl = dyStringNew(0);
// views will be in the parent list, but the &g parameter to trackUi should be the view's parent
if (sameString(parentTypes[(i/2)], "view"))
dyStringPrintf(parentTdbOut->configUrl,
"../cgi-bin/hgTrackUi?hubUrl=%s&db=%s&g=%s_%s&hgsid=%s&%s",
hub->url, genomeOut->genomeName, hubId, stripEnclosingDoubleQuotes(parentTrackLabels[(i/2)+2]), cartSessionId(cart), genomeOut->positionString);
else // everything else has the correct &g param
dyStringPrintf(parentTdbOut->configUrl,
"../cgi-bin/hgTrackUi?hubUrl=%s&db=%s&g=%s_%s&hgsid=%s&%s",
hub->url, genomeOut->genomeName, hubId, parentTrack, cartSessionId(cart), genomeOut->positionString);
dyStringPrintf(parentTdbOut->shortLabel, "%s", parentLabel);
parentTdbOut->childCount += 1;
if (savedParent)
slAddHead(&(parentTdbOut->children), savedParent);
else
slAddHead(&(parentTdbOut->children), tdbOut);
savedParent = parentTdbOut;
doAddSaveParent = TRUE;
hashAdd(genomeOut->tdbOutHash, parentTrack, parentTdbOut);
}
else
{
foundParent = TRUE; // don't add this track to the genomeOut->tracks hash again
if (savedParent && doAddSaveParent)
{
parentTdbOut->childCount += 1;
slAddHead(&(parentTdbOut->children), savedParent);
}
else if (!savedParent)
{
parentTdbOut->childCount += 1;
slAddHead(&(parentTdbOut->children), tdbOut);
}
savedParent = parentTdbOut;
doAddSaveParent = FALSE;
}
}
if (!foundParent)
{
slAddHead(&(genomeOut->tracks), parentTdbOut);
}
}
else
{
dyStringPrintf(tdbOut->configUrl, "../cgi-bin/hgTrackUi?hubUrl=%s&db=%s&g=%s_%s&hgsid=%s&%s",
hub->url, genomeOut->genomeName, hubId, hst->track, cartSessionId(cart),
genomeOut->positionString);
slAddHead(&(genomeOut->tracks), tdbOut);
}
hashAdd(genomeOut->tdbOutHash, hst->track, tdbOut);
}
return tdbOut;
}
struct hubOutputStructure *buildHubSearchOutputStructure(struct trackHub *hub,
struct hubSearchText *searchResults)
/* Build a structure that contains the data for writing out the hub search results for this hub */
{
struct hash *missingGenomes = hashNew(0);
struct hubOutputStructure *hubOut = NULL;
AllocVar(hubOut);
hubOut->metaTags = dyStringNew(0);
hubOut->descriptionMatch = dyStringNew(0);
hubOut->genomeOutHash = newHash(5);
struct hubSearchText *hst = NULL;
for (hst = searchResults; hst != NULL; hst = hst->next)
{
if (isEmpty(hst->db))
{
// must be a hit to the hub itself, not an assembly or track within it
if (hst->textLength == hubSearchTextLong)
{
dyStringPrintf(hubOut->descriptionMatch, "%s", hst->text);
}
else if (hst->textLength == hubSearchTextMeta)
{
if (isNotEmpty(dyStringContents(hubOut->metaTags)))
dyStringPrintf(hubOut->metaTags, ", %s", hst->text);
else
dyStringPrintf(hubOut->metaTags, "%s", hst->text);
}
continue;
}
char *db = cloneString(hst->db);
if (hashLookup(missingGenomes, db) != NULL)
continue;
struct trackHubGenome *genome = hashFindVal(hub->genomeHash, db);
if (genome == NULL)
{
// assembly hub genomes are stored with a prefix; try that
char withHubName[4096];
safef(withHubName, sizeof(withHubName), "%s_%s", hub->name, db);
genome = hashFindVal(hub->genomeHash, withHubName);
if (genome == NULL)
{
hashStoreName(missingGenomes, db);
warn("Error: Unable to find info for matching assembly '%s'. Skipping ...\n", withHubName);
continue;
}
}
struct genomeOutputStructure *genomeOut = hashFindVal(hubOut->genomeOutHash, db);
if (genomeOut == NULL)
{
AllocVar(genomeOut);
genomeOut->tdbOutHash = newHash(5);
genomeOut->metaTags = dyStringNew(0);
genomeOut->descriptionMatch = dyStringNew(0);
genomeOut->shortLabel = dyStringNew(0);
genomeOut->assemblyLink = dyStringNew(0);
genomeOut->positionString = getPositionStringForDb(genome);
dyStringPrintf(genomeOut->assemblyLink, "../cgi-bin/hgTracks?hubUrl=%s&db=%s&hgsid=%s&%s",
hub->url, genome->name, cartSessionId(cart), genomeOut->positionString);
char *name = trackHubSkipHubName(genome->name);
if (isNotEmpty(genome->description))
dyStringPrintf(genomeOut->shortLabel, "%s (%s)", genome->description, name);
else if (isNotEmpty(genome->organism))
dyStringPrintf(genomeOut->shortLabel, "%s %s", genome->organism, name);
else
dyStringPrintf(genomeOut->shortLabel, "%s", name);
genomeOut->genomeName = cloneString(genome->name);
hashAdd(hubOut->genomeOutHash, db, genomeOut);
slAddTail(&(hubOut->genomes), genomeOut);
hubOut->genomeCount++;
}
if (isEmpty(hst->track))
{
if (hst->textLength == hubSearchTextLong) // Genome description match
dyStringPrintf(genomeOut->descriptionMatch, "%s", hst->text);
else if (hst->textLength == hubSearchTextMeta)
{
if (isNotEmpty(dyStringContents(genomeOut->metaTags)))
dyStringPrintf(genomeOut->metaTags, ", %s", hst->text);
else
dyStringPrintf(genomeOut->metaTags, "%s", hst->text);
}
}
if (isNotEmpty(hst->track))
{
// Time to add a track! (or add info to one, maybe)
struct tdbOutputStructure *tdbOut = hstToTdbOutput(hst, genomeOut, hub);
if (tdbOut != NULL)
{
if (hst->textLength == hubSearchTextLong)
dyStringPrintf(tdbOut->descriptionMatch, "%s", hst->text);
else if (hst->textLength == hubSearchTextMeta)
{
if (isNotEmpty(dyStringContents(tdbOut->metaTags)))
dyStringPrintf(tdbOut->metaTags, ", %s", hst->text);
else
dyStringPrintf(tdbOut->metaTags, "%s", hst->text);
}
}
}
}
return hubOut;
}
static char *tdbOutputStructureLabelToId(struct tdbOutputStructure *tdbOut)
/* Make an array name out of a tdbOutputStruct */
{
struct dyString *id = dyStringNew(0);
dyStringPrintf(id, "%s", htmlEncode(dyStringContents(tdbOut->shortLabel)));
if (tdbOut->childCount > 0)
{
dyStringPrintf(id, " (%d subtrack%s)", tdbOut->childCount,
tdbOut->childCount == 1 ? "" : "s");
}
return dyStringCannibalize(&id);
}
static void printTdbOutputStructureToDyString(struct tdbOutputStructure *tdbOut, struct dyString *dy, char *arrayName)
/* Print a tdbOutputStructure to a dyString, recursive for subtracks. */
{
dyStringPrintf(dy, "trackData['%s'] = [", arrayName);
if (tdbOut->childCount > 0)
{
struct dyString *subtrackDy = dyStringNew(0);
struct tdbOutputStructure *child = tdbOut->children;
while (child != NULL)
{
char *childId = tdbOutputStructureLabelToId(child);
dyStringPrintf(dy, "\n\t{\n\tid: '%s',\n\tparent: '%s',\n\t"
"li_attr: {nodetype:'track', configlink:'%s'},\n\ttext: \'%s ",
childId, arrayName, dyStringContents(child->configUrl), childId);
if (isNotEmpty(dyStringContents(child->metaTags)))
{
dyStringPrintf(dy, " Metadata: %s",
htmlEncode(dyStringContents(child->metaTags)));
}
if (isNotEmpty(dyStringContents(child->descriptionMatch)))
{
dyStringPrintf(dy, " Description: %s",
htmlEncode(dyStringContents(child->descriptionMatch)));
}
dyStringPrintf(dy, "\'");
if (child->childCount > 0)
{
dyStringPrintf(dy, ",\n\tchildren: true");
printTdbOutputStructureToDyString(child, subtrackDy, childId);
}
dyStringPrintf(dy, "\n\t},");
child = child->next;
}
dyStringPrintf(dy, "];\n");
if (isNotEmpty(dyStringContents(subtrackDy)))
dyStringPrintf(dy, "%s", subtrackDy->string);
}
else
dyStringPrintf(dy, "];\n");
}
void printGenomeOutputStructureToDyString(struct genomeOutputStructure *genomeOut, struct dyString *dy, char *genomeNameId)
/* Print a genomeOutputStructure to a dyString. The structure here is:
* trackData[genome] = [{track 1 obj}, {track2 obj}, {track3 obj}, ... ]
* trackData[track1] = [{search hit text}, {subtrack1 obj}, {subtrack2 obj}, ... ]
*
* if track1, track2, track3 are container tracks, then the recursive function
* tdbOutputStructureToDystring creates the above trackData[track1] = [{}] for
* each of the containers, otherwise a single child of the genome is sufficient */
{
struct tdbOutputStructure *tdbOut = NULL;
static struct dyString *tdbArrayDy = NULL; // the dyString for all of the tdb objects
static struct dyString *idString = NULL; // the special id of this track
if (tdbArrayDy == NULL)
tdbArrayDy = dyStringNew(0);
if (idString == NULL)
idString = dyStringNew(0);
dyStringPrintf(dy, "trackData['%s'] = [", genomeNameId);
if (genomeOut->tracks != NULL)
{
tdbOut = genomeOut->tracks;
slReverse(&tdbOut);
while (tdbOut != NULL)
{
dyStringPrintf(idString, "%s", tdbOutputStructureLabelToId(tdbOut));
dyStringPrintf(dy, "\n\t{\n\t'id': '%s',\n\t'parent': '%s',\n\t"
"'li_attr': {'nodetype':'track', configlink: '%s'},\n\t'text': \'%s ",
idString->string, genomeNameId, dyStringContents(tdbOut->configUrl), idString->string);
if (isNotEmpty(dyStringContents(tdbOut->metaTags)))
{
dyStringPrintf(dy, " Metadata: %s",
htmlEncode(dyStringContents(tdbOut->metaTags)));
}
if (isNotEmpty(dyStringContents(tdbOut->descriptionMatch)))
{
dyStringPrintf(dy, " Description: %s",
htmlEncode(dyStringContents(tdbOut->descriptionMatch)));
}
dyStringPrintf(dy, "\'");
// above we took care of both non-heirarchical tracks and the top-level containers,
// now do container children, which also takes care of any deeper heirarchies
if (tdbOut->childCount > 0)
dyStringPrintf(dy, ",\n\t'children': true");
dyStringPrintf(dy, "\n\t},\n");
if (tdbOut->childCount > 0)
printTdbOutputStructureToDyString(tdbOut, tdbArrayDy, idString->string);
tdbOut = tdbOut->next;
dyStringClear(idString);
}
}
dyStringPrintf(dy, "];\n"); // close off genome node
dyStringPrintf(dy, "%s\n", tdbArrayDy->string);
dyStringClear(tdbArrayDy);
}
void printHubOutputStructure(struct hubOutputStructure *hubOut, struct hubEntry *hubInfo)
/* Convert a hubOutputStructure to a jstree-readable string. This function forms the root
* node for each hub search tree, whose children are the hub description match and each individual
* genome node. A simplified structure is:
* trackData['#_hubId'] = [{id:'descriptionMatch',...},{id:'assembly1',...},...]
*
* The id's become new "trackData[id]" entries with their own arrays later if they have
* sub-trees (via printGenomeOutputStructureToDyString() and printTdbOutputStructureToDyString(). */
{
struct dyString *dy = dyStringNew(0);
// The leading '#' tells the javascript this is a 'root' node
dyStringPrintf(dy, "trackData['#_%d'] = [", hubInfo->id);
if (isNotEmpty(dyStringContents(hubOut->descriptionMatch)))
{
dyStringPrintf(dy, "{'id':'%d_descriptionMatchText','parent':'#_%d',"
"'state':{'opened': true},'text': 'Hub Description: "
"%s'},",
hubInfo->id, hubInfo->id, htmlEncode(dyStringContents(hubOut->descriptionMatch)));
}
struct genomeOutputStructure *genomeOut = hubOut->genomes;
struct dyString *genomeDy = dyStringNew(0);
if (genomeOut != NULL)
{
dyStringPrintf(dy, "{'id':'%d_assemblies', 'text':'%d Matching Assembl%s', 'parent':'#_%d', "
"'children':true, 'li_attr': {'state':{'opened': 'false'}}}];\n",
hubInfo->id, hubOut->genomeCount, hubOut->genomeCount == 1 ? "y" : "ies", hubInfo->id);
dyStringPrintf(dy, "trackData['%d_assemblies'] = [", hubInfo->id);
while (genomeOut != NULL)
{
char *assemblyName = htmlEncode(dyStringContents(genomeOut->shortLabel));
char genomeNameId[512];
safef(genomeNameId, sizeof(genomeNameId), "%d_%s", hubInfo->id, assemblyName);
dyStringPrintf(dy, "{'id': '%s', 'parent': '%d_assemblies', 'children': true, "
"'li_attr': {'assemblylink': '%s','nodetype': 'assembly'},"
"'text': \"%s",
genomeNameId, hubInfo->id, dyStringContents(genomeOut->assemblyLink), assemblyName);
if (genomeOut->trackCount > 0)
{
dyStringPrintf(dy, " (%d track%s) ", genomeOut->trackCount,
genomeOut->trackCount == 1 ? "" : "s");
}
if (isNotEmpty(dyStringContents(genomeOut->metaTags)))
{
dyStringPrintf(dy, " %s",
htmlEncode(dyStringContents(genomeOut->metaTags)));
}
if (isNotEmpty(dyStringContents(genomeOut->descriptionMatch)))
{
dyStringPrintf(dy, " Assembly Description: %s",
htmlEncode(dyStringContents(genomeOut->descriptionMatch)));
}
dyStringPrintf(dy, "\"},");
printGenomeOutputStructureToDyString(genomeOut, genomeDy, genomeNameId);
genomeOut = genomeOut->next;
}
}
dyStringPrintf(dy, "];\n");
dyStringPrintf(dy, "%s", genomeDy->string);
jsInline(dy->string);
dyStringClear(dy);
}
static void printOutputForHub(struct hubEntry *hubInfo, struct hubSearchText *hubSearchResult, int count)
/* Given a hub's info and a structure listing the search hits within the hub, first print
* a basic line of hub information with a "connect" button. Then, if the search results
* are non-NULL, write out information about the genomes and tracks from the search hits that
* match the db filter.
* If there are no search results to print, the basic hub lines are combined into a single HTML table
* that is defined outside this function.
* Otherwise, each hub line is printed in its own table followed by a
containing details
* about the search results. */
{
outputPublicTableRow(hubInfo, count);
if (hubSearchResult != NULL)
{
printf("
\n");
struct trackHub *hub = fetchTrackHub(hubInfo);
if (hub != NULL)
{
struct hubOutputStructure *hubOut = buildHubSearchOutputStructure(hub, hubSearchResult);
if (dyStringIsEmpty(hubOut->descriptionMatch) && (hubOut->genomes == NULL))
return; // no detailed search results; hit must have been to hub short label or something
printf("
\n");
printf("", hubInfo->id); // div for the jstree for this hub's search result(s)
printf("