c46be5cebadbe532ca7f7fc2a5cde930554c7ae7
braney
  Tue May 2 11:20:34 2017 -0700
first check in of hgComposite code.

diff --git src/hg/hgComposite/hgComposite.c src/hg/hgComposite/hgComposite.c
new file mode 100644
index 0000000..bfe17c0
--- /dev/null
+++ src/hg/hgComposite/hgComposite.c
@@ -0,0 +1,846 @@
+/* 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 "cartTrackDb.h"
+#include "trashDir.h"
+#include "customComposite.h"
+
+#define hgCompEditPrefix    "hgCompositeEdit_"
+#define hgsAddTrack hgCompEditPrefix "addTrack"
+#define hgsChangeGroup hgCompEditPrefix "changeGroup"
+#define hgsCurrentGroup hgCompEditPrefix "currentGroup"
+#define hgsCurrentComposite hgCompEditPrefix "currentComposite"
+#define hgsNewCompositeName hgCompEditPrefix "newCompositeName"
+#define hgsNewCompositeShortLabel hgCompEditPrefix "newCompositeShortLabel"
+#define hgsNewCompositeLongLabel hgCompEditPrefix "newCompositeLongLabel"
+//#define hgCompositePrefix    "hgComposite_"
+#define hgDoNewComposite      hgCompEditPrefix    "doNewComposite"
+
+struct track
+{
+struct track *next;
+char *name;
+char *shortLabel;
+};
+
+struct composite
+{
+struct composite *next;
+char *name;
+char *shortLabel;
+char *longLabel;
+struct track *trackList;
+};
+
+
+/* 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. */
+struct grp *fullGroupList = NULL;	/* List of all groups. */
+
+// Null terminated list of CGI Variables we don't want to save permanently:
+char *excludeVars[] = {"Submit", "submit", "hgva_startQuery", hgsAddTrack,  hgsNewCompositeName, hgsNewCompositeShortLabel, hgsNewCompositeLongLabel, hgsChangeGroup, NULL};
+
+void nbSpaces(int count)
+/* Print some non-breaking spaces. */
+{
+int i;
+for (i=0; i<count; ++i)
+    printf("&nbsp;");
+}
+
+void addSomeCss()
+/*#*** This should go in a .css file of course. */
+{
+printf("<style>\n"
+	"div.sectionLite { border-width: 1px; border-color: #"HG_COL_BORDER"; border-style: solid;"
+	"  background-color: #FFFFFF; padding-left: 10px; padding-right: 10px; "
+	"  padding-top: 8px; padding-bottom: 5px; margin-top: 5px; margin-bottom: 5px }\n"
+	".sectionLiteHeader { font-weight: bold; font-size:larger; color:#000000;"
+	"  text-align:left; vertical-align:bottom; white-space:nowrap; }\n"
+	"div.sectionLiteHeader.noReorderRemove { padding-bottom:5px; }\n"
+	"div.sourceFilter { padding-top: 5px; padding-bottom: 5px }\n"
+	"</style>\n");
+}
+
+
+INLINE void startCollapsibleSection(char *sectionSuffix, char *title, boolean onByDefault)
+// Wrap shared args to jsBeginCollapsibleSectionFontSize
+{
+jsBeginCollapsibleSectionFontSize(cart, "hgva", sectionSuffix, title, onByDefault, "1.1em");
+}
+
+INLINE void startSmallCollapsibleSection(char *sectionSuffix, char *title, boolean onByDefault)
+// Wrap shared args to jsBeginCollapsibleSectionFontSize
+{
+jsBeginCollapsibleSectionFontSize(cart, "hgva", sectionSuffix, title, onByDefault, "0.9em");
+}
+
+#define endCollapsibleSection jsEndCollapsibleSection
+
+
+static struct dyString *onChangeStart()
+/* Start up a javascript onChange command */
+{
+struct dyString *dy = jsOnChangeStart();
+return dy;
+}
+
+
+static char *onChangeClade()
+/* Return javascript executed when they change clade. */
+{
+struct dyString *dy = onChangeStart();
+jsDropDownCarryOver(dy, "clade");
+dyStringAppend(dy, " document.hiddenForm.org.value=0;");
+dyStringAppend(dy, " document.hiddenForm.db.value=0;");
+return jsOnChangeEnd(&dy);
+}
+
+static char *onChangeOrg()
+/* Return javascript executed when they change organism. */
+{
+struct dyString *dy = onChangeStart();
+jsDropDownCarryOver(dy, "clade");
+jsDropDownCarryOver(dy, "org");
+dyStringAppend(dy, " document.hiddenForm.db.value=0;");
+return jsOnChangeEnd(&dy);
+}
+
+static char *onChangeDb()
+/* Return javascript executed when they change database. */
+{
+struct dyString *dy = onChangeStart();
+jsDropDownCarryOver(dy, "clade");
+jsDropDownCarryOver(dy, "db");
+return jsOnChangeEnd(&dy);
+}
+
+INLINE void printOption(char *val, char *selectedVal, char *label)
+/* For rolling our own select without having to build conditional arrays/lists. */
+{
+printf("<OPTION VALUE='%s'%s>%s\n", val, (sameString(selectedVal, val) ? " SELECTED" : ""), label);
+}
+
+
+static struct composite *getCompositeList(char *db, char *hubName, struct hash *nameHash)
+{
+struct composite *compositeList = NULL;
+
+if (hubName != NULL)
+    {
+    // read hub to find names of composites and add them to compositeList
+    struct trackDb *tdbList = trackDbFromRa(hubName, NULL);
+    struct trackDb *tdb, *tdbNext;
+    struct composite *composite = NULL;
+    struct track *track = NULL;
+
+    for(tdb = tdbList; tdb; tdb = tdbNext)
+        {
+        printf("adding %s\n", tdb->track);
+        hashAdd(nameHash, tdb->track, tdb);
+        tdbNext = tdb->next;
+        trackDbFieldsFromSettings(tdb);
+        if (trackDbSetting(tdb, "compositeTrack"))
+            {
+            AllocVar(composite);
+            slAddHead(&compositeList, composite);
+            composite->name = tdb->track;
+            composite->shortLabel = tdb->shortLabel;
+            }
+        else
+            {
+            if (composite == NULL)
+                errAbort("track not in composite");
+            AllocVar(track);
+            track->name = tdb->track;
+            track->shortLabel = tdb->shortLabel;
+            slAddHead(&composite->trackList, track);
+            }
+        }
+    }
+
+return compositeList;
+}
+
+static char *getSqlBigWig(char *db, struct trackDb *tdb)
+{
+struct sqlConnection *conn = hAllocConn(db);
+
+char buffer[4096];
+
+safef(buffer, sizeof buffer, "NOSQLINJ select fileName from %s", tdb->table);
+return sqlQuickString(conn, buffer);
+}
+
+static int snakePalette2[] =
+{
+0x1f77b4, 0xaec7e8, 0xff7f0e, 0xffbb78, 0x2ca02c, 0x98df8a, 0xd62728, 0xff9896, 0x9467bd, 0xc5b0d5, 0x8c564b, 0xc49c94, 0xe377c2, 0xf7b6d2, 0x7f7f7f, 0xc7c7c7, 0xbcbd22, 0xdbdb8d, 0x17becf, 0x9edae5
+};
+
+
+void outTdb(char *db, FILE *f, char *name,  struct trackDb *tdb, char *parent, unsigned int color)
+{
+char *dataUrl = NULL;
+char *bigDataUrl = trackDbSetting(tdb, "bigDataUrl");
+if (bigDataUrl == NULL)
+    {
+    if (startsWith("bigWig", tdb->type))
+        dataUrl = getSqlBigWig(db, tdb);
+    }
+struct hashCookie cookie = hashFirst(tdb->settingsHash);
+struct hashEl *hel;
+fprintf(f, "\ttrack %s\n", name);
+while ((hel = hashNext(&cookie)) != NULL)
+    {
+    if (differentString(hel->name, "parent") && differentString(hel->name, "polished")&& differentString(hel->name, "color")&& differentString(hel->name, "track"))
+        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 composite *composite)
+{
+char *parent = composite->name;
+char *shortLabel = composite->name;
+char *longLabel = composite->name;
+fprintf(f,"track %s\n\
+shortLabel %s\n\
+compositeTrack on\n\
+aggregate none\n\
+longLabel %s\n\
+#container multiWig\n\
+type wig \n\
+visibility full\n\n", parent, shortLabel, longLabel);
+}
+
+static struct trackDb *findTrack(char *name, struct trackDb *fullTrackList)
+{
+struct trackDb *tdb;
+for (tdb = fullTrackList; tdb != NULL; tdb = tdb->next)
+    {
+    if (sameString(name, tdb->track))
+        return tdb;            
+    }
+errAbort("cannot find track");
+return NULL;
+}
+
+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");
+    trashDirDateFile(&hubTn, "brTest", "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 void outputCompositeHub(char *db, char *hubName, struct trackDb *fullTrackList, struct composite *compositeList, struct hash *nameHash)
+static void outputCompositeHub(char *db, char *hubName,  struct composite *compositeList, struct hash *nameHash)
+{
+// Do we already have a hub?
+chmod(hubName, 0666);
+FILE *f = mustOpen(hubName, "w");
+
+outHubHeader(f, db, hubName);
+int useColor = 0;
+struct composite *composite;
+for(composite = compositeList; composite; composite = composite->next)
+    {
+    outComposite(f, composite);
+    struct trackDb *tdb;
+    struct track *track;
+    for (track = composite->trackList; track; track = track->next)
+        {
+        tdb = hashMustFindVal(nameHash, track->name);
+        //tdb = findTrack(track->name, fullTrackList);
+
+        outTdb(db, f, track->name,tdb, composite->name, snakePalette2[useColor]);
+        useColor++;
+        if (useColor == (sizeof snakePalette2 / sizeof(int)))
+            useColor = 0;
+        }
+    }
+fclose(f);
+}
+
+
+void topLabelSpansStart(char *label)
+{
+printf("<span style='display: inline-block; padding-right: 5px;'>"
+       "<span style='display: block;'>%s</span>\n"
+       "<span style='display: block; padding-bottom: 5px;'>\n", label);
+}
+
+void topLabelSpansEnd()
+{
+printf("</span></span>");
+}
+
+
+void printCtAndHubButtons()
+/* Print a div with buttons for hgCustom and hgHubConnect */
+{
+boolean hasCustomTracks = customTracksExist(cart, NULL);
+puts("<div style='padding-top: 5px; padding-bottom: 5px'>");
+hOnClickButton("prtCtHub_CtBut", "document.customTrackForm.submit(); return false;",
+	       hasCustomTracks ? CT_MANAGE_BUTTON_LABEL : CT_ADD_BUTTON_LABEL);
+printf(" ");
+if (hubConnectTableExists())
+    hOnClickButton("prtCtHub_TrkHub", "document.trackHubForm.submit(); return false;", "track hubs");
+nbSpaces(3);
+printf("To reset <B>all</B> user cart settings (including custom tracks), \n"
+       "<A HREF=\"cartReset?destination=%s\">click here</A>.\n",
+       cgiScriptName());
+puts("</div>");
+}
+
+void hgGatewayCladeGenomeDb()
+/* Make a row of labels and row of buttons like hgGateway, but not using tables. */
+{
+boolean gotClade = hGotClade();
+if (gotClade)
+    {
+    topLabelSpansStart("clade");
+    printCladeListHtml(genome, "change", onChangeClade());
+    topLabelSpansEnd();
+    }
+topLabelSpansStart("genome");
+if (gotClade)
+    printGenomeListForCladeHtml(database, "change", onChangeOrg());
+else
+    printGenomeListHtml(database, "change", onChangeOrg());
+topLabelSpansEnd();
+topLabelSpansStart("assembly");
+printAssemblyListHtml(database, "change", onChangeDb());
+topLabelSpansEnd();
+puts("<BR>");
+topLabelSpansEnd();
+topLabelSpansStart("");
+printf("</span>\n");
+topLabelSpansEnd();
+puts("<BR>");
+}
+
+void printAssemblySection()
+/* Print assembly-selection stuff.
+ * Redrawing the whole page when the assembly changes seems fine to me. */
+{
+//#*** ---------- More copied verbatim, from hgTables/mainPage.c: -----------
+/* Hidden form - for benefit of javascript. */
+    {
+    static char *saveVars[] = {
+      "clade", "org", "db", };
+    jsCreateHiddenForm(cart, cgiScriptName(), saveVars, ArraySize(saveVars));
+    }
+
+hPrintf("<FORM ACTION='%s' NAME='changeGroupForm'>", cgiScriptName());
+cartSaveSession(cart);
+cgiMakeHiddenVar(hgsCurrentGroup, "");
+hPrintf("</FORM>\n");
+
+hPrintf("<FORM ACTION='%s' NAME='changeCompositeForm'>", cgiScriptName());
+cartSaveSession(cart);
+cgiMakeHiddenVar(hgsCurrentComposite, "");
+hPrintf("</FORM>\n");
+
+hPrintf("<FORM ACTION='%s' NAME='makeNewCompositeForm'>", cgiScriptName());
+cartSaveSession(cart);
+cgiMakeHiddenVar(hgsNewCompositeName, "");
+cgiMakeHiddenVar(hgsNewCompositeShortLabel, "");
+cgiMakeHiddenVar(hgsNewCompositeLongLabel, "");
+hPrintf("</FORM>\n");
+
+hPrintf("<FORM ACTION='%s' NAME='addTrackForm'>", cgiScriptName());
+cartSaveSession(cart);
+cgiMakeHiddenVar(hgsAddTrack, "");
+hPrintf("</FORM>\n");
+
+/* Hidden form for jumping to custom tracks CGI. */
+hPrintf("<FORM ACTION='%s' NAME='customTrackForm'>", hgCustomName());
+cartSaveSession(cart);
+hPrintf("</FORM>\n");
+
+/* Hidden form for jumping to track hub manager CGI. */
+hPrintf("<FORM ACTION='%s' NAME='trackHubForm'>", hgHubConnectName());
+cartSaveSession(cart);
+hPrintf("</FORM>\n");
+
+printf("<FORM ACTION=\"%s\" NAME=\"mainForm\" ID=\"mainForm\" METHOD=%s>\n",
+	cgiScriptName(), cartUsualString(cart, "formMethod", "GET"));
+cartSaveSession(cart);
+
+//#*** ------------------ end verbatim ---------------
+
+printf("<div class='sectionLiteHeader noReorderRemove'>"
+       "Select Genome Assembly</div>\n");
+
+/* Print clade, genome and assembly line. */
+hgGatewayCladeGenomeDb();
+
+}
+
+static void printCompositeList(struct composite *compositeList, struct composite *currentComposite)
+{
+if (compositeList == NULL)
+    return;
+
+printf("<H4>My Composites</H4>\n");
+
+int count = slCount(compositeList);
+char *labels[count];
+char *names[count];
+count = 0;
+for(; compositeList; compositeList = compositeList->next)
+    {
+    labels[count] = compositeList->shortLabel;
+    names[count] = compositeList->name;
+    count++;
+    }
+cgiMakeDropListFull("compositeList", labels, names, count,
+                    currentComposite->name,
+                    "change", 
+                    "var e = document.getElementById('compositeList'); \
+                    var strUser = e.options[e.selectedIndex].value; \
+                    document.changeCompositeForm.elements['"hgsCurrentComposite"'].value = strUser; \
+                    document.changeCompositeForm.submit();");
+                    //document.addTrackForm.elements['hgComp_track'] = strUser;");
+
+}
+
+
+static void makeAddComposite()
+{
+printf("<BR>");
+printf("<BR>");
+printf("<H3>Make New Composite</H3>");
+printf("name ");
+cgiMakeTextVar(hgsNewCompositeName, "", 29);
+printf("short label ");
+cgiMakeTextVar(hgsNewCompositeShortLabel, "", 29);
+printf("long label ");
+cgiMakeTextVar(hgsNewCompositeLongLabel, "", 29);
+hOnClickButton("selVar_MakeNewComposite", 
+                    "var e = document.getElementById('"hgsNewCompositeName"'); \
+                    document.makeNewCompositeForm.elements['"hgsNewCompositeName"'].value = e.value; \
+                    var e = document.getElementById('"hgsNewCompositeShortLabel"'); \
+                    document.makeNewCompositeForm.elements['"hgsNewCompositeShortLabel"'].value = e.value; \
+                    var e = document.getElementById('"hgsNewCompositeLongLabel"'); \
+                    document.makeNewCompositeForm.elements['"hgsNewCompositeLongLabel"'].value = e.value; \
+document.makeNewCompositeForm.submit(); return false;", "submit");
+printf("<BR>");
+}
+
+static void printTrackList(struct composite *composite)
+{
+printf("<div class='sectionLiteHeader noReorderRemove'>"
+       "Tracks in Composite</div>\n");
+printf("<BR>");
+printf("<div style=\"max-width:1024px\">");
+printf("<table id=\"sessionTable\" class=\"sessionTable stripe hover row-border compact\" borderwidth=0>\n");
+printf("<thead><tr>");
+printf("<TH><TD><B>Name</B></TD></TH>");
+printf("</tr></thead><tbody>");
+
+struct track *track;
+if (composite)
+    for(track = composite->trackList; track; track = track->next)
+        {
+        printf("<TR><TD>%s</TD></TR>\n",track->shortLabel);
+        }
+//printf("<TR><TD>track1</TD></TR>");
+//printf("<TR><TD>track2</TD></TR>");
+printf("</table>");
+}
+
+
+static boolean trackCanBeAdded(struct trackDb *tdb)
+{
+return  (tdb->subtracks == NULL) && !startsWith("wigMaf",tdb->type) &&  (startsWith("wig",tdb->type) || startsWith("bigWig",tdb->type)) ;
+}
+
+static void availableTracks(char *db, struct grp *groupList, struct trackDb *fullTrackList)
+{
+printf("<H4>Available tracks in %s</H4>", db);
+
+char *curGroupName = cartOptionalString(cart, hgsCurrentGroup);
+printf("<BR>groups: ");
+char **labels, **names;
+int count = slCount(groupList);
+AllocArray(labels, count);
+AllocArray(names, count);
+count = 0;
+struct grp *grp;
+for(grp = groupList; grp; grp = grp->next)
+    {
+    labels[count] = grp->label;
+    names[count] = grp->name;
+    count++;
+    }
+cgiMakeDropListFull("availGroups", labels, names, count,
+                    curGroupName,
+                    "change", 
+    "var e = document.getElementById('availGroups'); \
+    var strUser = e.options[e.selectedIndex].value; \
+    document.changeGroupForm.elements['"hgsCurrentGroup"'].value =  strUser;  \
+    document.changeGroupForm.submit();");
+
+struct grp *curGroup;
+if (curGroupName == NULL)
+    curGroup = groupList;
+else
+    {
+    for(curGroup = groupList; curGroup; curGroup = curGroup->next)
+        {
+        if (sameString(curGroupName, curGroup->name))
+            break;
+        }
+    if (curGroup == NULL)
+        errAbort("cannot find current group");
+    }
+
+struct trackDb *tdb;
+count = 0;
+for(tdb = fullTrackList; tdb; tdb = tdb->next)
+    {
+    if (sameString(tdb->grp, curGroup->name))
+        count++;
+    }
+
+//char **labels, **names;
+AllocArray(labels, count);
+AllocArray(names, count);
+count = 0;
+for(tdb = fullTrackList; tdb; tdb = tdb->next)
+    {
+    if (sameString(tdb->grp, curGroup->name))
+        {
+        labels[count] = tdb->shortLabel;
+        names[count] = tdb->track;
+        count++;
+        }
+    }
+
+printf("track:");
+cgiMakeDropListFull("availTracks", labels, names, count,
+                    *names, 
+                    "change", 
+                    "var e = document.getElementById('availTracks'); \
+                    var strUser = e.options[e.selectedIndex].value; \
+                    document.addTrackForm.elements['"hgsAddTrack"'].value = strUser;");
+                    //document.addTrackForm.elements['hgComp_track'] = strUser;");
+hOnClickButton("addTrack", 
+    "var e = document.getElementById('availTracks'); \
+    var strUser = e.options[e.selectedIndex].value;  \
+    document.addTrackForm.elements['"hgsAddTrack"'].value =  strUser;  \
+    document.addTrackForm.submit();"
+, "add track");
+
+printf("<BR>");
+printf("<BR>");
+printf("<BR>");
+hOnClickButton("selVar_AddAllVis", "document.trackHubForm.submit(); return false;", "Add All Visibile Wiggles");
+}
+
+void doMainPage(char *db, struct grp *groupList,  struct trackDb *fullTrackList, struct composite *currentComposite, struct composite *compositeList)
+/* Print out initial HTML of control page. */
+{
+//struct composite *currentComposite = compositeList;
+jsInit();
+webIncludeResourceFile("jquery-ui.css");
+webIncludeResourceFile("ui.dropdownchecklist.css");
+boolean alreadyAgreed = cartUsualBoolean(cart, "hgva_agreedToDisclaimer", FALSE);
+jsInlineF(
+    "$(document).ready(function() { hgva.disclaimer.init(%s, hgva.userClickedAgree); });\n"
+    , alreadyAgreed ? "true" : "false");
+addSomeCss();
+printAssemblySection();
+
+puts("<BR>");
+printCtAndHubButtons();
+
+//struct hashEl *hel = cartFindPrefix(cart, hgCompEditPrefix);
+//if (hel != NULL)
+    {
+ //   printf("printing EditCom\n");
+  ///  printEditComposite();
+    }
+
+printf("</FORMk");
+puts("<BR>");
+makeAddComposite();
+puts("<BR>");
+printCompositeList(compositeList, currentComposite);
+puts("<BR>");
+printTrackList(currentComposite);
+puts("<BR>");
+availableTracks(db, groupList, fullTrackList);
+puts("<BR>");
+
+// Make wrapper table for collapsible sections:
+//selectVariants();
+//char *geneTrack = selectGenes();
+//if (geneTrack != NULL)
+    {
+    //selectRegulatory();
+    //selectAnnotations(geneTrack);
+    //selectFilters();
+    //selectOutput();
+    //submitAndDisclaimer();
+    }
+
+printf("</FORM>");
+jsReloadOnBackButton(cart);
+
+webNewSection("Using the Composite Builder");
+webIncludeHelpFileSubst("hgCompositeHelpText", cart, FALSE);
+jsIncludeFile("jquery-ui.js", NULL);
+jsIncludeFile("hgVarAnnogrator.js", NULL);
+jsIncludeFile("ui.dropdownchecklist.js", NULL);
+jsIncludeFile("ddcl.js", NULL);
+}
+
+
+
+
+
+
+void doUi(char *db, struct grp *groupList, struct trackDb *fullTrackList,struct composite *currentComposite, struct composite *compositeList) 
+/* Set up globals and make web page */
+{
+cartWebStart(cart, db, "Composite Editor");
+doMainPage(database, groupList, fullTrackList, currentComposite, compositeList);
+cartWebEnd();
+/* Save variables. */
+//cartCheckout(&cart);
+}
+
+static struct hash *addWigs(struct trackDb **wigList, struct trackDb *list)
+{
+struct hash *hash = newHash(4);
+if (list == NULL)
+    return hash;
+
+struct trackDb *tdb, *tdbNext;
+for(tdb = list; tdb; tdb = tdbNext)
+    {
+    tdbNext = tdb->next;
+    addWigs(wigList, tdb->subtracks);
+
+    if (trackCanBeAdded(tdb))
+        {
+        slAddHead(wigList, tdb);
+        hashStore(hash, tdb->grp);
+        }
+    }
+
+return hash;
+}
+
+char *makeUnique(struct hash *nameHash, struct trackDb *tdb)
+{
+if (hashLookup(nameHash, tdb->track) == NULL)
+    {
+    printf("adding %s\n", tdb->track);
+    hashAdd(nameHash, tdb->track, tdb);
+    return tdb->track;
+    }
+
+unsigned count = 0;
+char buffer[4096];
+
+for(;; count++)
+    {
+    safef(buffer, sizeof buffer, "%s%d", tdb->track, count);
+    if (hashLookup(nameHash, buffer) == NULL)
+        {
+        printf("adding %s\n", buffer);
+        hashAdd(nameHash, buffer, tdb);
+        return cloneString(buffer);
+        }
+    }
+
+return NULL;
+}
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+long enteredMainTime = clock1000();
+if (hIsPrivateHost())
+    pushCarefulMemHandler(LIMIT_2or6GB);
+
+cgiSpoof(&argc, argv);
+htmlPushEarlyHandlers(); /* Make errors legible during initialization. */
+oldVars = hashNew(10);
+cart = cartAndCookie(hUserCookie(), excludeVars, oldVars);
+
+/* Set up global variables. */
+getDbAndGenome(cart, &database, &genome, oldVars);
+initGenbankTableNames(database);
+
+int timeout = cartUsualInt(cart, "udcTimeout", 300);
+if (udcCacheTimeout() < timeout)
+    udcSetCacheTimeout(timeout);
+knetUdcInstall();
+
+struct trackDb *fullTrackList = NULL;	/* List of all tracks in database. */
+struct trackDb *wigTracks = NULL;	/* List of all wig tracks */
+cartTrackDbInit(cart, &fullTrackList, &fullGroupList, TRUE);
+struct hash *groupHash = addWigs(&wigTracks, fullTrackList);
+struct grp *grp, *grpNext,  *groupList = NULL;
+
+for(grp = fullGroupList; grp; grp = grpNext)
+    {
+    grpNext = grp->next;
+    if (hashLookup(groupHash, grp->name) != NULL)
+        slAddHead(&groupList, grp);
+    }
+
+slReverse(&groupList);
+
+/*
+struct grp *grpList;
+struct trackDb *tdbList = hubCollectTracks(database, &grpList);
+addWigs(&wigTracks, tdbList);
+*/
+
+char *hubName = getHubName(database);
+struct hash *nameHash = newHash(5);
+struct composite *compositeList = getCompositeList(database, hubName, nameHash);
+
+struct composite *currentComposite = NULL;
+char *currentCompositeName = cartOptionalString(cart, hgsCurrentComposite);
+printf("currentcomposite name %s\n", currentCompositeName);
+
+if (currentCompositeName != NULL)
+    {
+    for (currentComposite = compositeList; currentComposite; currentComposite = currentComposite->next)
+        if (sameString(currentComposite->name, currentCompositeName))
+            break;
+    }
+
+if (currentComposite == NULL)
+    currentComposite = compositeList;
+
+char *newCompositeName = cartOptionalString(cart, hgsNewCompositeName);
+if (newCompositeName != NULL)
+    {
+    if (isEmpty(newCompositeName))
+        warn("Composite name must not be empty string");
+    else
+        {
+        struct composite *composite;
+        AllocVar(composite);
+        slAddHead(&compositeList, composite);
+        currentComposite = composite;
+
+        composite->name = cloneString(newCompositeName);
+        char *newCompositeShortLabel = cartOptionalString(cart, hgsNewCompositeShortLabel);
+        if (isEmpty(newCompositeShortLabel))
+            composite->shortLabel = composite->name;
+        else
+            composite->shortLabel = cloneString(newCompositeShortLabel);
+        char *newCompositeLongLabel = cartOptionalString(cart, hgsNewCompositeLongLabel);
+        if (isEmpty(newCompositeLongLabel))
+            composite->longLabel = composite->name;
+        else
+            composite->longLabel = cloneString(newCompositeLongLabel);
+
+        }
+    }
+
+if (currentCompositeName == NULL)
+    currentComposite = compositeList;
+
+char *newTrackName = cartOptionalString(cart, hgsAddTrack);
+if (newTrackName != NULL)
+    {
+    if (currentComposite == NULL)
+        warn("cannot add track without specifying a composite");
+    else
+        {
+        struct trackDb *tdb = findTrack(newTrackName, wigTracks);
+
+        struct track *track;
+        AllocVar(track);
+        track->name = makeUnique(nameHash,  tdb);
+        track->shortLabel = tdb->shortLabel;
+        slAddHead(&currentComposite->trackList, track);
+        }
+    }
+
+//struct trackDb *fullTrackList = getFullTrackList(cart);
+doUi(database, groupList, wigTracks, currentComposite, compositeList);
+
+outputCompositeHub(database, hubName,  compositeList, nameHash);
+cartCheckout(&cart);
+cgiExitTime("hgComposite", enteredMainTime);
+return 0;
+}