53a520d17d725ceacf50f5eecead0c75470ce48a braney Sat Jul 29 16:13:58 2017 -0700 adding hgCollection, a tool to build custom collections of tracks diff --git src/hg/hgCollection/hgCollection.c src/hg/hgCollection/hgCollection.c new file mode 100644 index 0000000..ac765cf --- /dev/null +++ src/hg/hgCollection/hgCollection.c @@ -0,0 +1,821 @@ +/* hgVai - Variant Annotation Integrator. */ + +/* Copyright (C) 2014 The Regents of the University of California + * See README in this or parent directory for licensing information. */ +#include "common.h" +#include "linefile.h" +#include "hash.h" +#include "options.h" +#include "jksql.h" +#include "htmshell.h" +#include "web.h" +#include "cheapcgi.h" +#include "cart.h" +#include "cartTrackDb.h" +#include "genbank.h" +#include "hgConfig.h" +#include "hgHgvs.h" +#include "hui.h" +#include "grp.h" +#include "hCommon.h" +#include "hgFind.h" +#include "hPrint.h" +#include "jsHelper.h" +#include "memalloc.h" +#include "textOut.h" +#include "trackHub.h" +#include "hubConnect.h" +#include "twoBit.h" +#include "gpFx.h" +#include "bigGenePred.h" +#include "udc.h" +#include "knetUdc.h" +#include "md5.h" +#include "regexHelper.h" +#include "hAnno.h" +#include "trashDir.h" +#include "api.h" +#include "customComposite.h" + +//#include "libifyMe.h" + + +/* Global Variables */ +struct cart *cart; /* CGI and other variables */ +struct hash *oldVars = NULL; /* The cart before new cgi stuff added. */ +char *genome = NULL; /* Name of genome - mouse, human, etc. */ +char *database = NULL; /* Current genome database - hg17, mm5, etc. */ +char *regionType = NULL; /* genome, ENCODE pilot regions, or specific position range. */ +struct grp *fullGroupList = NULL; /* List of all groups. */ +struct trackDb *fullTrackList = NULL; /* List of all tracks in database. */ + struct pipeline *compressPipeline = (struct pipeline *)NULL; + + +// Null terminated list of CGI Variables we don't want to save permanently: +char *excludeVars[] = {"Submit", "submit", "hgva_startQuery", NULL,}; + +struct track +{ +struct track *next; +struct track *trackList; +struct trackDb *tdb; +char *name; +char *shortLabel; +char *longLabel; +char *visibility; +}; + +static char *getString(char **input) +{ +char *ptr = *input; + +if (*ptr != '"') + errAbort("string must start with \""); +ptr++; +char *ret = ptr; +for(; *ptr != '"'; ptr++) + ; +*ptr = 0; +ptr++; + +if (*ptr == ',') + ptr++; + +*input = ptr; + +return ret; +} + +char *makeUnique(struct hash *nameHash, char *name) +// Make the name of this track unique. +{ +char *skipHub = trackHubSkipHubName(name); +if (hashLookup(nameHash, skipHub) == NULL) + { + hashStore(nameHash, name); + return skipHub; + } + +unsigned count = 0; +char buffer[4096]; + +for(;; count++) + { + safef(buffer, sizeof buffer, "%s%d", skipHub, count); + if (hashLookup(nameHash, buffer) == NULL) + { + hashStore(nameHash, buffer); + return cloneString(buffer); + } + } + +return NULL; +} + +static boolean trackCanBeAdded(struct trackDb *tdb) +{ +return (tdb->subtracks == NULL) && !startsWith("wigMaf",tdb->type) && (startsWith("wig",tdb->type) || startsWith("bigWig",tdb->type)) ; +} + +static void printGroup(char *parent, struct trackDb *tdb, boolean folder, boolean user) +{ +printf("<tr data-tt-parent-id='%s' data-tt-id='%s' %s><td><span class='%s'>%s</span></td>", parent, trackHubSkipHubName(tdb->track), user ? "class='user'" : "", folder ? "folder" : "file", tdb->shortLabel ); +printf("<td>%s</td></tr>\n", tdb->longLabel); + + +if (tdb->subtracks) + { + struct trackDb *subTdb; + + for(subTdb = tdb->subtracks; subTdb; subTdb = subTdb->next) + printGroup(trackHubSkipHubName(tdb->track), subTdb, FALSE, user); + } +} + +static void outHubHeader(FILE *f, char *db, char *hubName) +{ +char *hubFile = strrchr(hubName, '/') + 1; + +fprintf(f,"hub hub1\n\ +shortLabel User Composite\n\ +longLabel User Composite\n\ +genomesFile %s\n\ +email braney@soe.ucsc.edu\n\ +descriptionUrl hub.html\n\n", hubFile); +fprintf(f,"genome %s\n\ +trackDb %s\n\n", db, hubFile); +} + + +static char *getHubName(char *db) +{ +struct tempName hubTn; +char buffer[4096]; +safef(buffer, sizeof buffer, "%s-%s", customCompositeCartName, db); +char *hubName = cartOptionalString(cart, buffer); + +if (hubName == NULL) + { + trashDirDateFile(&hubTn, "hgComposite", "hub", ".txt"); + hubName = cloneString(hubTn.forCgi); + cartSetString(cart, buffer, hubName); + FILE *f = mustOpen(hubName, "a"); + outHubHeader(f, db, hubName); + fclose(f); + cartSetString(cart, "hubUrl", hubName); + cartSetString(cart, hgHubConnectRemakeTrackHub, hubName); + } +return hubName; +} + +static bool subtrackEnabledInTdb(struct trackDb *subTdb) +/* Return TRUE unless the subtrack was declared with "subTrack ... off". */ +{ +bool enabled = TRUE; +char *words[2]; +char *setting; +if ((setting = trackDbLocalSetting(subTdb, "parent")) != NULL) + { + if (chopLine(cloneString(setting), words) >= 2) + if (sameString(words[1], "off")) + enabled = FALSE; + } +else + return subTdb->visibility != tvHide; + +return enabled; +} + +bool isSubtrackVisible(struct trackDb *tdb) +/* Has this subtrack not been deselected in hgTrackUi or declared with + * * "subTrack ... off"? -- assumes composite track is visible. */ +{ +boolean overrideComposite = (NULL != cartOptionalString(cart, tdb->track)); +bool enabledInTdb = subtrackEnabledInTdb(tdb); +char option[1024]; +safef(option, sizeof(option), "%s_sel", tdb->track); +boolean enabled = cartUsualBoolean(cart, option, enabledInTdb); +if (overrideComposite) + enabled = TRUE; +return enabled; +} + + +bool isParentVisible( struct trackDb *tdb) +// Are this track's parents visible? +{ +if (tdb->parent == NULL) + return TRUE; + +if (!isParentVisible(tdb->parent)) + return FALSE; + +char *cartVis = cartOptionalString(cart, tdb->parent->track); +boolean vis; +if (cartVis != NULL) + vis = differentString(cartVis, "hide"); +else if (tdbIsSuperTrack(tdb->parent)) + vis = tdb->parent->isShow; +else + vis = tdb->parent->visibility != tvHide; + +return vis; +} + + +void addVisibleTracks() +{ +printf("<tr data-tt-id='visible' ><td><span class='file'>All Visible</td><td>All the tracks visible in hgTracks</td></tr>\n"); +struct trackDb *tdb; +for(tdb = fullTrackList; tdb; tdb = tdb->next) + { + if (isParentVisible(tdb) && isSubtrackVisible(tdb)) + { + printGroup("visible", tdb, FALSE, FALSE); + } + } +} + +static void doHeader() +{ +puts( +"<a name='TRACK_TOP'></a>\n" +" <div class='row gbTrackTitleBanner'>\n" +" <div class='col-md-10'>\n" +); +printf( +" <span class='gbTrackName'>\n" +" My Collections \n" +" </span>" +" <span class='gbTrackTitle'> Build Custom Collections of Tracks </span>\n" ); +puts( +"<!-- Info icon built from stacked fa icons -->\n" +" <a href='#INFO_SECTION' title='Jump to the track description'>\n" +" <span class='gbIconSmall fa-stack'>\n" +" <i class='gbBlueDarkColor fa fa-circle fa-stack-2x'></i>\n" +" <i class='gbWhiteColor fa fa-info fa-stack-1x'></i>\n" +" </span></a>\n" +" <div class='gbButtonGoContainer text-right' title='Save Collections'>\n" +" </div>\n" + +" </div>\n" +" <div class='col-md-2 text-right'>\n" +" <div class='gbButtonGoContainer text-right' title='Go to the Genome Browser'>\n" + +" <div class='gbButtonGo' id='saveCollections' >Save</div>\n" +" <div class='gbButtonGo' id='discardChanges'>Discard Changes</div>\n" +" </div>\n" ); +puts( +" </div>\n" +" </div>\n" +); +} + +static void doTable() +{ +puts( +" <!-- Configuration panel -->\n" +" <div class='row gbSectionBanner'>\n" +" <div class='col-md-8'>All Tracks</div>\n" +" <div class='col-md-4 text-right'>\n"); + +puts( +" <div class='gbButtonGoContainer text-right' title='Make New Collection'>\n" +" <div id='newCollection' class='gbButton'>Make New Collection </div>\n" +" </div>\n" +); +puts( +" </div>\n" +" </div>\n"); + +char *hubName = hubNameFromUrl(getHubName(database)); +printf("<table id='tracks'><tbody>\n"); +struct grp *curGroup; +printf("<tr data-tt-id='collections'><td><span class='file'>My Collections</td>"); +printf("<td>Your collected tracks.</td></tr>\n"); +for(curGroup = fullGroupList; curGroup; curGroup = curGroup->next) + { + if ((hubName != NULL) && sameString(curGroup->name, hubName)) + break; + } +if (curGroup != NULL) + { + // print out all the tracks in this group + struct trackDb *tdb; + for(tdb = fullTrackList; tdb; tdb = tdb->next) + { + if (sameString(tdb->grp, hubName)) + printGroup("collections", tdb, TRUE, TRUE); + } + } +//addVisibleTracks(); +for(curGroup = fullGroupList; curGroup; curGroup = curGroup->next) + { + if ((hubName != NULL) && sameString(curGroup->name, hubName)) + continue; + printf("<tr data-tt-id='%s'><td><span class='file'>%s</span></td><td></td></tr>\n", curGroup->name, curGroup->label ); + struct trackDb *tdb; + for(tdb = fullTrackList; tdb; tdb = tdb->next) + { + if ( sameString(tdb->grp, curGroup->name)) + { + printGroup(curGroup->name, tdb, FALSE, FALSE); + } + } + } +printf("</tbody></table>\n"); +} + +static void doAttributes() +{ +puts( +" <!-- Configuration panel -->\n" +" <div class='row gbSectionBanner'>\n" +" <div class='col-md-8'>Set Attributes</div>\n" +" <div class='col-md-4 text-right'>\n"); +puts( +" <div class='gbButtonGoContainer text-right' title='Save Props'>\n" +" <div id='propsSave' class='gbButton'>Save</div>\n" +" </div>\n" +); +puts( +" <div class='gbButtonGoContainer text-right' title='Discard Changes'>\n" +" <div id='propsDiscard' class='gbButton'>Discard Changes</div>\n" +" </div>\n" +); +puts( +"</div></div>\n"); +// trackDb track options (none at the moment) +puts( +"<div id='TrackDbOptions' style=\"display: none;\">" +"Drag to custom composite to copy to Collections" +"</div>" +); + +// mathwig options +puts( +"<div class='jwInputLabel' id='MathWigOptions' style=\"display: none;\">" +"<label for='name'>Name:</label>" +"<input type='text' name='mathWigName' id='mathWigName' value='' class='text ui-widget-content ui-corner-all'>\n" +"<label for='description'>Description:</label>\n" +"<input type='text' name='mathWigDescription' id='mathWigDescription' value='' class='text ui-widget-content ui-corner-all'>\n" +"<label for='mathWigVis'>Visibility:</label>" +"<SELECT ID='mathWigVis' >\n" +"<OPTION>hide</OPTION>\n" +"<OPTION SELECTED>dense</OPTION>\n" +"<OPTION>squish</OPTION>\n" +"<OPTION>pack</OPTION>\n" +"<OPTION>full</OPTION>\n" +"</SELECT>\n" +"<label for='mathWigFunction'>Function:</label>" +"<SELECT ID='mathWigFunction' >\n" +"<OPTION SELECTED>add</OPTION>\n" +"<OPTION >subtract</OPTION>\n" +"</SELECT>\n" +" <p>Highlight color: <input type='text' id='mathColorInput' value='0xffffff'> <input id='mathColorPicker'>" +"</div>\n" +); + +// custom composite options +puts( +"<div class='jwInputLabel' id='CustomCompositeOptions' style=\"display: none;\">" +"<label for='name'>Name:</label>" +"<input type='text' name='collectionName' id='collectionName' value='' class='text ui-widget-content ui-corner-all'>\n" +"<label for='description'>Description:</label>\n" +"<input type='text' name='collectionDescription' id='collectionDescription' value='' class='text ui-widget-content ui-corner-all'>\n" +"<label for='collectionVis'>Visibility:</label>" +"<SELECT ID='collectionVis' style='width: 70px'>\n" +"<OPTION>hide</OPTION>\n" +"<OPTION SELECTED>dense</OPTION>\n" +"<OPTION>squish</OPTION>\n" +"<OPTION>pack</OPTION>\n" +"<OPTION>full</OPTION>\n" +"</SELECT>\n" +"<input type='button' value='Create MathWig' name='createMathWig' id='createMathWig'>\n" +"</div>\n" +); + +// custom track options +puts( +"<div class='jwInputLabel' id='CustomTrackOptions' style=\"display: none;\">" +"<label for='name'>Name:</label>" +"<input type='text' name='customName' id='customName' value='' class='text ui-widget-content ui-corner-all'>\n" +"<label for='description'>Description:</label>\n" +"<input type='text' name='customDescription' id='customDescription' value='' class='text ui-widget-content ui-corner-all'>\n" +"<label for='customVis'>Visibility:</label>" +"<SELECT ID='customVis' style='width: 70px'>\n" +"<OPTION>hide</OPTION>\n" +"<OPTION SELECTED>dense</OPTION>\n" +"<OPTION>squish</OPTION>\n" +"<OPTION>pack</OPTION>\n" +"<OPTION>full</OPTION>\n" +"</SELECT>\n" +" <p>Highlight color: <input type='text' id='trackColorInput' value='0xffffff'> <input id='trackColorPicker'>" +"</div>\n" + +); + +} + +static void onclickJumpToTop(char *id) +/* CSP-safe click handler arrows that cause scroll to top */ +{ +jsOnEventById("click", id, "$('html,body').scrollTop(0);"); +} + +static void printHelp() +{ +puts( +"<a name='INFO_SECTION'></a>\n" +" <div class='row gbSectionBanner'>\n" +" <div class='col-md-11'>Help</div>\n" +" <div class='col-md-1'>\n" +); +#define DATA_INFO_JUMP_ARROW_ID "hgGtexDataInfo_jumpArrow" +printf( +" <i id='%s' title='Jump to top of page' \n" +" class='gbIconArrow fa fa-lg fa-arrow-circle-up'></i>\n", +DATA_INFO_JUMP_ARROW_ID +); +onclickJumpToTop(DATA_INFO_JUMP_ARROW_ID); +puts( +" </div>\n" +" </div>\n" +); +puts( +" <div class='row gbTrackDescriptionPanel'>\n" +" <div class='gbTrackDescription'>\n"); +puts("<div class='dataInfo'>"); +puts("</div>"); +webIncludeHelpFileSubst("hgCompositeHelp", NULL, FALSE); + +puts("<div class='dataInfo'>"); +puts("</div>"); + +puts( +" </div>\n" +" </div>\n"); + + +puts("<script src=\"//code.jquery.com/jquery-1.9.1.min.js\"></script>"); +puts("<script src=\"//code.jquery.com/ui/1.10.3/jquery-ui.min.js\"></script>"); +jsIncludeFile("jquery.treetable.js", NULL); +jsIncludeFile("utils.js", NULL); +jsIncludeFile("ajax.js", NULL); +jsIncludeFile("hgTracks.js", NULL); +jsIncludeFile("spectrum.min.js", NULL); +jsIncludeFile("hgCollection.js", NULL); +} + +void doMainPage() +/* Print out initial HTML of control page. */ +{ +webStartGbNoBanner(cart, database, "Collections"); +webIncludeResourceFile("jquery.treetable.css"); +webIncludeResourceFile("jquery.treetable.theme.default.css"); +webIncludeResourceFile("gb.css"); +webIncludeResourceFile("jWest.css"); +webIncludeResourceFile("spectrum.min.css"); +webIncludeResourceFile("hgGtexTrackSettings.css"); + +//webIncludeFile("inc/hgCollection.html"); + +printf( +"<form action='%s' name='MAIN_FORM' method=%s>\n\n", + hgTracksName(), cartUsualString(cart, "formMethod", "POST")); + +doHeader(); +puts( +"<!-- Track Configuration Panels -->\n" +" <div class='row'>\n" +" <div class='col-md-6'>\n"); +doTable(); +puts( +" </div>\n" +" <div class='col-md-6'>\n"); +doAttributes(); +puts( +" </div>\n" +" </div>\n" +); +puts( +"</form>"); +printHelp(); + + +} + +static char *getSqlBigWig(struct sqlConnection *conn, char *db, struct trackDb *tdb) +{ +char buffer[4096]; + +safef(buffer, sizeof buffer, "NOSQLINJ select fileName from %s", tdb->table); +return sqlQuickString(conn, buffer); +} + +char *getUrl(struct sqlConnection *conn, char *db, struct track *track, struct hash *nameHash) +{ +struct trackDb *tdb = hashMustFindVal(nameHash, track->name); + +if (tdb == NULL) + errAbort("cannot find trackDb for %s\n", track->name); + +char *bigDataUrl = trackDbSetting(tdb, "bigDataUrl"); +if (bigDataUrl == NULL) + { + if (startsWith("bigWig", tdb->type)) + bigDataUrl = getSqlBigWig(conn, db, tdb); + } +return bigDataUrl; +} + +void outTdb(struct sqlConnection *conn, char *db, FILE *f, char *name, struct trackDb *tdb, char *parent, unsigned int color, struct track *track, struct hash *nameHash, struct hash *collectionNameHash) +{ +char *dataUrl = NULL; +char *bigDataUrl = trackDbSetting(tdb, "bigDataUrl"); + +if (bigDataUrl == NULL) + { + if (startsWith("bigWig", tdb->type)) + dataUrl = getSqlBigWig(conn, db, tdb); + } +struct hashCookie cookie = hashFirst(tdb->settingsHash); +struct hashEl *hel; +fprintf(f, "\ttrack %s\n", makeUnique(collectionNameHash, name)); +while ((hel = hashNext(&cookie)) != NULL) + { + if (sameString(hel->name, "mathDataUrl")) + { +/* + fprintf(f, "\ttrackNames "); + struct mathTrack *mt = (struct mathTrack *)track; + struct track *tr = mt->trackList; + for(; tr; tr = tr->next) + { + fprintf(f, "%s ", tr->name); + } + fprintf(f, "\n"); + + fprintf(f, "\tmathDataUrl "); + tr = mt->trackList; + if ((mt->function == NULL) || sameString(mt->function, "add")) + fprintf(f, "+ "); + else + fprintf(f, "- "); + for(; tr; tr = tr->next) + { + fprintf(f, "%s ", getUrl(conn, db, wigTracks, tr, nameHash)); + } + fprintf(f, "\n"); +*/ + } + else if (differentString(hel->name, "parent") && differentString(hel->name, "polished")&& differentString(hel->name, "color")&& differentString(hel->name, "track")&& differentString(hel->name, "trackNames")&& differentString(hel->name, "superTrack")) + fprintf(f, "\t%s %s\n", hel->name, (char *)hel->val); + } +if (bigDataUrl == NULL) + { + if (dataUrl != NULL) + fprintf(f, "\tbigDataUrl %s\n", dataUrl); + } +fprintf(f, "\tparent %s\n",parent); +fprintf(f, "\tcolor %d,%d,%d\n", (color >> 16) & 0xff,(color >> 8) & 0xff,color & 0xff); +fprintf(f, "\n"); +} + +static void outComposite(FILE *f, struct track *collection) +{ +char *parent = collection->name; +char *shortLabel = collection->shortLabel; +char *longLabel = collection->longLabel; +fprintf(f,"track %s\n\ +shortLabel %s\n\ +compositeTrack on\n\ +aggregate none\n\ +longLabel %s\n\ +%s on\n\ +type wig \n\ +visibility full\n\n", parent, &shortLabel[2], longLabel, CUSTOM_COMPOSITE_SETTING); +} + +static int snakePalette2[] = +{ +0x1f77b4, 0xaec7e8, 0xff7f0e, 0xffbb78, 0x2ca02c, 0x98df8a, 0xd62728, 0xff9896, 0x9467bd, 0xc5b0d5, 0x8c564b, 0xc49c94, 0xe377c2, 0xf7b6d2, 0x7f7f7f, 0xc7c7c7, 0xbcbd22, 0xdbdb8d, 0x17becf, 0x9edae5 +}; + + +static void outMathWig(FILE *f, struct sqlConnection *conn, char *db, struct track *mathWig, struct hash *nameHash) +{ +fprintf(f,"\ttrack %s\n\ +\tshortLabel %s\n\ +\tlongLabel %s\n\ +\ttype mathWig \n\ +\tvisibility full\n", mathWig->name, &mathWig->shortLabel[2], mathWig->longLabel); +fprintf(f,"\tmathDataUrl + "); +struct track *track = mathWig->trackList; +for(; track; track = track->next) + { + fprintf(f, "%s ", getUrl(conn, db, track, nameHash)); + } + +fprintf(f, "\n"); + +} + +void updateHub(char *db, struct track *collectionList, struct hash *nameHash) +{ +char *hubName = getHubName(db); + +chmod(hubName, 0666); +FILE *f = mustOpen(hubName, "w"); +struct hash *collectionNameHash = newHash(6); + +outHubHeader(f, db, hubName); +int useColor = 0; +struct track *collection; +struct sqlConnection *conn = hAllocConn(db); +for(collection = collectionList; collection; collection = collection->next) + { + outComposite(f, collection); + struct trackDb *tdb; + struct track *track; + for (track = collection->trackList; track; track = track->next) + { + if (track->trackList != NULL) + { + outMathWig(f, conn, db, track, nameHash); + } + else + { + tdb = hashMustFindVal(nameHash, track->name); + + outTdb(conn, db, f, track->name,tdb, collection->name, snakePalette2[useColor], track, nameHash, collectionNameHash); + useColor++; + if (useColor == (sizeof snakePalette2 / sizeof(int))) + useColor = 0; + } + } + } +fclose(f); +hFreeConn(&conn); +} + +static struct track *parseJson(char *jsonText) +{ +struct hash *trackHash = newHash(5); +struct track *collectionList = NULL; +struct track *track; +char *ptr = jsonText; +if (*ptr != '[') + errAbort("element didn't start with ["); +ptr++; + +do + { + if (*ptr != '[') + errAbort("element didn't start with ["); + ptr++; + + AllocVar(track); + char *parentName = getString(&ptr); + if (sameString(parentName, "collections")) + slAddHead(&collectionList, track); + else + { + struct track *parent = hashMustFindVal(trackHash, parentName); + slAddHead(&parent->trackList, track); + } + + track->shortLabel = getString(&ptr); + track->longLabel = getString(&ptr); + track->name = getString(&ptr); + track->visibility = getString(&ptr); + hashAdd(trackHash, track->name, track); + if (*ptr != ']') + errAbort("element didn't end with ]"); + ptr++; + if (*ptr == ',') + ptr++; + } while (*ptr != ']'); + +return collectionList; +} + +void doAjax(char *db, char *jsonText, struct hash *nameHash) +{ +struct track *collectionList = parseJson(jsonText); + +updateHub(db, collectionList, nameHash); +} + +static struct hash *buildNameHash(struct trackDb *list) +// TODO; needs to go down one more layer +{ +struct hash *nameHash = newHash(8); +struct trackDb *tdb; +for(tdb = list; tdb; tdb = tdb->next) + { + hashAdd(nameHash, trackHubSkipHubName(tdb->track), tdb); + struct trackDb *subTdb = tdb->subtracks; + for(; subTdb; subTdb = subTdb->next) + { + hashAdd(nameHash, trackHubSkipHubName(subTdb->track), subTdb); + } + } +return nameHash; +} + +static struct trackDb *traverseTree(struct trackDb *oldList, struct hash *groupHash) +{ +struct trackDb *newList = NULL, *tdb, *tdbNext; + +for(tdb = oldList; tdb ; tdb = tdbNext) + { + tdbNext = tdb->next; + if (tdb->subtracks) + { + tdb->subtracks = traverseTree(tdb->subtracks, groupHash); + + if (tdb->subtracks) + { + hashStore(groupHash, tdb->grp); + slAddHead(&newList, tdb); + } + } + else + { + if (trackCanBeAdded(tdb)) + { + hashStore(groupHash, tdb->grp); + slAddHead(&newList, tdb); + } + } + } +slReverse(&newList); + +return newList; +} + +static void pruneTrackList(struct trackDb **fullTrackList, struct grp **fullGroupList) +{ +struct hash *groupHash = newHash(5); + +*fullTrackList = traverseTree(*fullTrackList, groupHash); +struct grp *newGroupList = NULL, *grp, *nextGrp; + +for (grp = *fullGroupList; grp; grp = nextGrp) + { + nextGrp = grp->next; + + if (hashLookup(groupHash, grp->name)) + slAddHead(&newGroupList, grp); + } +slReverse(&newGroupList); +*fullGroupList = newGroupList; +} + +void doMiddle(struct cart *theCart) +/* Set up globals and make web page */ +{ +cart = theCart; +getDbAndGenome(cart, &database, &genome, oldVars); +int timeout = cartUsualInt(cart, "udcTimeout", 300); +if (udcCacheTimeout() < timeout) + udcSetCacheTimeout(timeout); +knetUdcInstall(); +cartTrackDbInit(cart, &fullTrackList, &fullGroupList, TRUE); +pruneTrackList(&fullTrackList, &fullGroupList); +struct hash *nameHash = buildNameHash(fullTrackList); + +char *jsonIn = cgiUsualString("jsonp", NULL); +fprintf(stderr, "BRANEY %s\n", jsonIn); +if (jsonIn != NULL) + { + doAjax(database, jsonIn, nameHash); + apiOut("{\"serverSays\": \"bit me\"}", NULL); + } +else + { + doMainPage(); + } +} + +int main(int argc, char *argv[]) +/* Process command line. */ +{ +long enteredMainTime = clock1000(); + +initGenbankTableNames(database); + +cgiSpoof(&argc, argv); + +boolean isCommandLine = (cgiOptionalString("cgiSpoof") != NULL); +if (!isCommandLine) + htmlPushEarlyHandlers(); /* Make errors legible during initialization. */ +oldVars = hashNew(10); + +cartEmptyShellNoContent(doMiddle, hUserCookie(), excludeVars, oldVars); + +if (! isCommandLine) + cgiExitTime("hgCollection", enteredMainTime); +return 0; +}