6175649026c35358cc0871c3f2cdf39328736885
markd
  Sun Oct 30 20:44:31 2022 -0700
initial implementation of all gencode transcript rank filters, not GUI yet

diff --git src/hg/hgc/gencodeClick.c src/hg/hgc/gencodeClick.c
index 948f754..1360248 100644
--- src/hg/hgc/gencodeClick.c
+++ src/hg/hgc/gencodeClick.c
@@ -1,123 +1,131 @@
 /* gencodeClick - click handling for GENCODE tracks */
 
 /* Copyright (C) 2014 The Regents of the University of California 
  * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
 #include "common.h"
 #include "hgc.h"
 #include "gencodeClick.h"
+#include "gencodeTracksCommon.h"
 #include "ccdsClick.h"
 #include "genePred.h"
 #include "genePredReader.h"
 #include "ensFace.h"
 #include "htmshell.h"
 #include "jksql.h"
 #include "regexHelper.h"
 #include "encode/wgEncodeGencodeAttrs.h"
 #include "encode/wgEncodeGencodeGeneSource.h"
 #include "encode/wgEncodeGencodePdb.h"
 #include "encode/wgEncodeGencodePubMed.h"
 #include "encode/wgEncodeGencodeRefSeq.h"
 #include "encode/wgEncodeGencodeTag.h"
 #include "encode/wgEncodeGencodeTranscriptSource.h"
 #include "encode/wgEncodeGencodeTranscriptSupport.h"
 #include "encode/wgEncodeGencodeExonSupport.h"
 #include "encode/wgEncodeGencodeUniProt.h"
 #include "encode/wgEncodeGencodeEntrezGene.h"
 #include "encode/wgEncodeGencodeAnnotationRemark.h"
 #include "encode/wgEncodeGencodeTranscriptionSupportLevel.h"
+#include "encode/wgEncodeGencodeGeneSymbol.h"
 
 /*
  * General notes:
  *  - this will be integrated into hgGene at some point, however this was
  *    done as part of hgc for timing reasons and to allow more time to design
  *    the hgGene part.
  *  - Tables below will output at least one row even if no data is available.
  *    
  */
 
 /* Various URLs and URL templates.  At one time, these were in the ra file,
  * but that didn't prove that helpful and end up requiring updated the ra
  * files for every GENCODE version if a URL was added or changed. */
 //FIXME: clean up RA files when CGIs no longer need them
 static char *ensemblTranscriptIdUrl = "http://www.ensembl.org/%s/Transcript/Summary?db=core;t=%s";
 static char *ensemblGeneIdUrl = "http://www.ensembl.org/%s/Gene/Summary?db=core;t=%s";
 static char *ensemblProteinIdUrl = "http://www.ensembl.org/%s/Transcript/ProteinSummary?db=core;t=%s";
 static char *ensemblSupportingEvidUrl = "http://www.ensembl.org/%s/Transcript/SupportingEvidence?db=core;t=%s";
 
 static char *ensemblH37TranscriptIdUrl = "http://grch37.ensembl.org/%s/Transcript/Summary?db=core;t=%s";
 static char *ensemblH37GeneIdUrl = "http://grch37.ensembl.org/%s/Gene/Summary?db=core;t=%s";
 static char *ensemblH37ProteinIdUrl = "http://grch37.ensembl.org/%s/Transcript/ProteinSummary?db=core;t=%s";
 static char *ensemblH37SupportingEvidUrl = "http://grch37.ensembl.org/%s/Transcript/SupportingEvidence?db=core;t=%s";
 
 static char *gencodeBiotypesUrl = "http://www.gencodegenes.org/pages/biotypes.html";
 static char *gencodeTagsUrl = "http://www.gencodegenes.org/pages/tags.html";
 
 static char *yalePseudoUrl = "http://tables.pseudogene.org/%s";
-static char *hgncUrl = " https://www.genenames.org/data/gene-symbol-report/#!/symbol/%s";
-static char *geneCardsUrl = "http://www.genecards.org/cgi-bin/carddisp.pl?gene=%s";
 static char *apprisHomeUrl = "https://appris.bioinfo.cnio.es/#/";
 static char *apprisGeneUrl = "https://appris.bioinfo.cnio.es/#/database/id/%s/%s?sc=ensembl";
 
-static char* UNKNOWN = "unknown";
-
-static char *getBaseAcc(char *acc, char *accBuf, int accBufSize)
-/* get the accession with version number dropped. */
-{
-safecpy(accBuf, accBufSize, acc);
-char *dot = strchr(accBuf, '.');
-if (dot != NULL)
-    *dot = '\0';
-return accBuf;
-}
+// species-specific
+static char *hgncByIdUrl = "https://www.genenames.org/data/gene-symbol-report/#!/hgnc_id/%s";
+static char *hgncBySymUrl = " https://www.genenames.org/data/gene-symbol-report/#!/symbol/%s";
+static char *geneCardsUrl = "http://www.genecards.org/cgi-bin/carddisp.pl?gene=%s";
+static char *mgiBySymUrl = "http://www.informatics.jax.org/quicksearch/summary?queryType=exactPhrase&query=%s";
+static char *mgiByIdUrl = "http://www.informatics.jax.org/accession/%s";
 
-static char* getGencodeVersion(struct trackDb *tdb)
-/* get the GENCODE version */
-{
-return trackDbRequiredSetting(tdb, "wgEncodeGencodeVersion");
-}
+static char* UNKNOWN = "unknown";
 
-static char *getGencodeTable(struct trackDb *tdb, char *tableBase)
-/* Return the table name with the version attached.  This just leaks the memory
- * and lets exit() clean up.  It is tiny */
+static boolean isGrcHuman()
+/* is this a GRC human assembly? */
 {
-char table[64];
-safef(table, sizeof(table), "%sV%s", tableBase, getGencodeVersion(tdb));
-return cloneString(table);
+if (startsWith("hg", database))
+    return TRUE;
+else if (startsWith("mm", database))
+    return FALSE;
+else
+    errAbort("BUG: gencodeClick on wrong database: %s", database);
+    return FALSE;
 }
 
 static bool haveGencodeTable(struct sqlConnection *conn, struct trackDb *tdb, char *tableBase)
 /* determine if a gencode table exists; it might be option or not in older releases */
 {
-return sqlTableExists(conn, getGencodeTable(tdb, tableBase));
+return sqlTableExists(conn, gencodeGetTableName(tdb, tableBase));
 }
 
 static boolean isGrcH37Native(struct trackDb *tdb)
 /* Is this GENCODE GRCh37 native build, which requires a different Ensembl site. */
 {
 // check for non-lifted GENCODE on GRCh37/hg19
 if (sameString(database, "hg19"))
-    return stringIn("lift37", getGencodeVersion(tdb)) == NULL;
+    return stringIn("lift37", gencodeGetVersion(tdb)) == NULL;
 else
     return FALSE;
 }
 
-static boolean isFakeGeneSymbol(char* sym)
-/* is this a static gene symbol? */
+static boolean isRealGeneSymbol(char* geneName, boolean haveGeneSymbolSource,
+                                struct wgEncodeGencodeGeneSymbol *geneSymbolSource)
+/* Attempt to determine if this is a gene symbol assigned by HGNC/MGI or a
+ * generate one.  newer versions of GENCODE have wgEncodeGencodeGeneSymbol,
+ * which has the definitions.  With older version of GENCODE guess a guess
+ * is make by trying to match older clone-based names ones.
+ */
 {
-static const char *regexp = "^AC[0-9]+\\.[0-9]+$";
-return regexMatch(sym, regexp);
+if (haveGeneSymbolSource)
+    {
+    return geneSymbolSource != NULL;
+    }
+else
+    {
+    // 'A' followed by one or more letters, then followed by numbers and a '.',
+    // followed by an incrementing gene number.
+    static const char *regexp = "^A[A-Z]+[0-9]+\\.[0-9]+$1)";
+    return regexMatch(geneName, regexp);
+    }
 }
 
 static int transAnnoCmp(const void *va, const void *vb)
 /* Compare genePreds, sorting to keep select gene first.  The only cases
  * that annotations will be duplicated is if they are in the PAR and thus
  * on different chroms. */
 {
 const struct genePred *a = *((struct genePred **)va);
 const struct genePred *b = *((struct genePred **)vb);
 if (sameString(a->name, seqName))
     return -1;
 else if (sameString(b->name, seqName))
     return 1;
 else
     return strcmp(a->name, b->name);
@@ -134,66 +142,66 @@
  * first.  Should only have one or two. */
 {
 // must check chrom due to PAR
 char where[256];
 sqlSafef(where, sizeof(where), "(chrom = \"%s\") and (name = \"%s\")", seqName, gencodeId);
 struct genePred *transAnno = genePredReaderLoadQuery(conn, tdb->track, where);
 slSort(&transAnno, transAnnoCmp);
 return transAnno;
 }
 
 static struct wgEncodeGencodeAttrs *transAttrsLoad(struct trackDb *tdb, struct sqlConnection *conn, char *gencodeId)
 /* load the gencode attributes */
 {
 char query[1024];
 sqlSafef(query, sizeof(query), "select * from %s where transcriptId = \"%s\"",
-         getGencodeTable(tdb, "wgEncodeGencodeAttrs"), gencodeId);
+         gencodeGetTableName(tdb, "wgEncodeGencodeAttrs"), gencodeId);
 struct sqlResult *sr = sqlGetResult(conn, query);
 char **row = sqlNextRow(sr);
 if (row == NULL)
     errAbort("gencode transcript %s not found in %s", gencodeId,
-             getGencodeTable(tdb, "wgEncodeGencodeAttrs"));
+             gencodeGetTableName(tdb, "wgEncodeGencodeAttrs"));
 // older version don't have proteinId column.
 struct wgEncodeGencodeAttrs *transAttrs = wgEncodeGencodeAttrsLoad(row, sqlCountColumns(sr));
 sqlFreeResult(&sr);
 return transAttrs;
 }
 
 static void getGeneBounds(struct trackDb *tdb, struct sqlConnection *conn, struct genePred *transAnno,
                           int *geneChromStart, int *geneChromEnd)
 /* find bounds for the gene */
 {
 // must check chrom due to PAR
 char where[256];
 sqlSafef(where, sizeof(where), "(chrom = \"%s\") and (name2 = \"%s\")", seqName, transAnno->name2);
 struct genePred *geneAnnos = genePredReaderLoadQuery(conn, tdb->track, where);
 struct genePred *geneAnno;
 *geneChromStart = transAnno->txStart;
 *geneChromEnd = transAnno->txEnd;
 for (geneAnno = geneAnnos; geneAnno != NULL; geneAnno = geneAnno->next)
     {
     *geneChromStart = min(*geneChromStart, geneAnno->txStart);
     *geneChromEnd = max(*geneChromEnd, transAnno->txEnd);
     }
 genePredFreeList(&geneAnnos);
 }
 
 static void *metaDataLoad(struct trackDb *tdb, struct sqlConnection *conn, char *gencodeId, char *tableBase, char *keyCol, unsigned queryOpts, sqlLoadFunc loadFunc)
 /* load autoSql objects for gencode meta data. */
 {
 return sqlQueryObjs(conn, loadFunc, queryOpts, "select * from %s where %s = \"%s\"",
-                    getGencodeTable(tdb, tableBase), keyCol, gencodeId);
+                    gencodeGetTableName(tdb, tableBase), keyCol, gencodeId);
 }
 
 static int uniProtDatasetCmp(const void *va, const void *vb)
 /* Compare wgEncodeGencodeUniProt by dateset */
 {
 const struct wgEncodeGencodeUniProt *a = *((struct wgEncodeGencodeUniProt **)va);
 const struct wgEncodeGencodeUniProt *b = *((struct wgEncodeGencodeUniProt **)vb);
 return a->dataset - b->dataset;
 }
 
 static char *getMethodDesc(char *source)
 /* return the annotation method name based gene or transcript source */
 {
 // sometimes backmap doesn't get every entry method entry mapped.  Until that
 // is fixed, allow it to be missing
@@ -291,53 +299,53 @@
 {
 printf("<td>");
 prEnsIdAnchor(id, urlTemplate);
 }
 
 static void prApprisTdAnchor(char *id, char *label, char *urlTemplate)
 /* print a gene or transcript link to APPRIS */
 {
 // under bar separated, lower case species name.
 char *speciesArg = hScientificName(database);
 toLowerN(speciesArg, strlen(speciesArg));
 subChar(speciesArg, ' ', '_');
 
 char accBuf[64];
 printf("<td><a href=\"");
-printf(urlTemplate, speciesArg, getBaseAcc(id, accBuf, sizeof(accBuf)));
+printf(urlTemplate, speciesArg, gencodeBaseAcc(id, accBuf, sizeof(accBuf)));
 printf("\" target=_blank>%s</a>", label);
 
 freeMem(speciesArg);
 }
 
 static void writePosLink(char *chrom, int chromStart, int chromEnd)
 /* write link to a genomic position */
 {
 printf("<a href=\"%s&db=%s&position=%s%%3A%d-%d\">%s:%d-%d</A>",
        hgTracksPathAndSettings(), database,
        chrom, chromStart, chromEnd, chrom, chromStart+1, chromEnd);
 }
 
 static bool geneHasApprisTranscripts(struct trackDb *tdb, struct sqlConnection *conn, struct wgEncodeGencodeAttrs *transAttrs)
 /* check if any transcript in a gene has an APPRIS tags */
 {
 char query[1024];
 sqlSafef(query, sizeof(query),
       "%s tag where tag.tag like 'appris%%' and transcriptId in "
       "(select transcriptId from %s where geneId='%s')",
-      getGencodeTable(tdb, "wgEncodeGencodeTag"),
-      getGencodeTable(tdb, "wgEncodeGencodeAttrs"),
+      gencodeGetTableName(tdb, "wgEncodeGencodeTag"),
+      gencodeGetTableName(tdb, "wgEncodeGencodeAttrs"),
       transAttrs->geneId);
 return sqlRowCount(conn, query) > 0;
 }
 
 static char* findApprisTag(struct wgEncodeGencodeTag *tags)
 /* search list for APPRIS tag or NULL */
 {
 struct wgEncodeGencodeTag *tag;
 for (tag = tags; tag != NULL; tag = tag->next)
     {
     if (startsWith("appris_", tag->tag))
         return tag->tag;
     }
 return NULL;
 }
@@ -366,35 +374,82 @@
 char *geneLabel = ((apprisTag != NULL) || geneHasApprisTranscripts(tdb, conn, transAttrs)) ? transAttrs->geneName : NULL;
 
 // APPRIS gene and transcript now go to the same location
 printf("<tr><th><a href=\"%s\" target=_blank>APPRIS</a>\n", apprisHomeUrl);
 if (transLabel != NULL)
     prApprisTdAnchor(transAttrs->geneId, transLabel, apprisGeneUrl);
 else
     printf("<td>&nbsp;");
 if (geneLabel != NULL)
     prApprisTdAnchor(transAttrs->geneId, geneLabel, apprisGeneUrl);
 else
     printf("<td>&nbsp;");
 printf("</tr>\n");
 }
 
+
+static void writeHumanGeneLinkout(struct wgEncodeGencodeAttrs *transAttrs,
+                                  boolean haveGeneSymbolSource, struct wgEncodeGencodeGeneSymbol *geneSymbolSource)
+/* Write external gene database links for human if they appear to be a real
+ * gene symbol Getting it wrong is not a disaster, as the target database will
+ * just report not found.
+ */
+{
+boolean isReal = isRealGeneSymbol(transAttrs->geneName, haveGeneSymbolSource, geneSymbolSource);
+printf("<tr><th>HGNC gene information<td colspan=2>");
+if (isReal)
+    {
+    if (haveGeneSymbolSource)
+        prExtIdAnchor(geneSymbolSource->geneId, hgncByIdUrl);
+    else
+        prExtIdAnchor(transAttrs->geneName, hgncBySymUrl);
+
+    }
+printf("</tr>\n");
+
+printf("<tr><th>GeneCards<td colspan=2>");
+if (isReal)
+    prExtIdAnchor(transAttrs->geneName, geneCardsUrl);
+printf("</tr>\n");
+}
+
+static void writeMouseGeneLinkout(struct wgEncodeGencodeAttrs *transAttrs,
+                                  boolean haveGeneSymbolSource, struct wgEncodeGencodeGeneSymbol *geneSymbolSource)
+/* Write external gene database links for mouse if they appear to be a real
+ * gene symbol Getting it wrong is not a disaster, as the target database will
+ * just report not found.
+ */
+{
+boolean isReal = isRealGeneSymbol(transAttrs->geneName, haveGeneSymbolSource, geneSymbolSource);
+printf("<tr><th>MGI gene information<td colspan=2>");
+if (isReal)
+    {
+    if (haveGeneSymbolSource)
+        prExtIdAnchor(geneSymbolSource->geneId, mgiByIdUrl);
+    else
+        prExtIdAnchor(transAttrs->geneName, mgiBySymUrl);
+    }
+printf("</tr>\n");
+
+}
+
 static void writeBasicInfoHtml(struct sqlConnection *conn, struct trackDb *tdb, char *gencodeId, struct genePred *transAnno,
                                struct wgEncodeGencodeAttrs *transAttrs,
                                int geneChromStart, int geneChromEnd,
                                struct wgEncodeGencodeGeneSource *geneSource, struct wgEncodeGencodeTranscriptSource *transcriptSource,
-                               struct wgEncodeGencodeTag *tags, bool haveTsl, struct wgEncodeGencodeTranscriptionSupportLevel *tsl)
+                               struct wgEncodeGencodeTag *tags, bool haveTsl, struct wgEncodeGencodeTranscriptionSupportLevel *tsl,
+                               boolean haveGeneSymbolSource, struct wgEncodeGencodeGeneSymbol *geneSymbolSource)
 /* write basic HTML info for all genes */
 {
 // basic gene and transcript information
 printf("<table class=\"hgcCcds\" style=\"white-space: nowrap;\"><thead>\n");
 printf("<tr><th><th>Transcript<th>Gene</tr>\n");
 printf("</thead><tbody>\n");
 
 printf("<tr><th>GENCODE id");
 prTdEnsIdAnchor(transAttrs->transcriptId,
                 (isGrcH37Native(tdb) ? ensemblH37TranscriptIdUrl: ensemblTranscriptIdUrl));
 prTdEnsIdAnchor(transAttrs->geneId,
                 (isGrcH37Native(tdb) ? ensemblH37GeneIdUrl : ensemblGeneIdUrl));
 printf("</tr>\n");
 
 if (transAttrs->proteinId != NULL)
@@ -425,49 +480,46 @@
 printf("<tr><th>Strand<td>%s<td></tr>\n", transAnno->strand);
 
 printf("<tr><th><a href=\"%s\" target = _blank>Biotype</a><td>%s<td>%s</tr>\n", gencodeBiotypesUrl, transAttrs->transcriptType, transAttrs->geneType);
 
 printf("<tr><th>Annotation Level<td>%s (%d)<td></tr>\n", getLevelDesc(transAttrs->level), transAttrs->level);
 
 char *transSrcDesc = (transcriptSource != NULL) ? getMethodDesc(transcriptSource->source) : UNKNOWN;
 char *geneSrcDesc = (geneSource != NULL) ? getMethodDesc(geneSource->source) : UNKNOWN;
 printf("<tr><th>Annotation Method<td>%s<td>%s</tr>\n", transSrcDesc, geneSrcDesc);
 
 if (haveTsl)
     {
     char *tslDesc = getSupportLevelDesc(tsl);
     printf("<tr><th><a href=\"#tsl\">Transcription Support Level</a><td><a href=\"#%s\">%s</a><td></tr>\n", tslDesc, tslDesc);
     }
-printf("<tr><th>HGNC gene symbol<td colspan=2>");
-if (!isFakeGeneSymbol(transAttrs->geneName))
-    prExtIdAnchor(transAttrs->geneName, hgncUrl);
-printf("</tr>\n");
+
+if (isGrcHuman())
+    writeHumanGeneLinkout(transAttrs, haveGeneSymbolSource, geneSymbolSource);
+else
+    writeMouseGeneLinkout(transAttrs, haveGeneSymbolSource, geneSymbolSource);
+
 
 printf("<tr><th>CCDS<td>");
 if (!isEmpty(transAttrs->ccdsId))
     {
     printf("<a href=\"");
     printCcdsExtUrl(transAttrs->ccdsId);
     printf("\" target=_blank>%s</a>", transAttrs->ccdsId);
     }
 printf("<td></tr>\n");
 
-printf("<tr><th>GeneCards<td colspan=2>");
-if (!isFakeGeneSymbol(transAttrs->geneName))
-    prExtIdAnchor(transAttrs->geneName, geneCardsUrl);
-printf("</tr>\n");
-
 if (isProteinCodingTrans(transAttrs))
     writeAprrisRow(conn, tdb, transAttrs, tags);
 
 // FIXME: add sequence here??
 printf("</tbody></table>\n");
 }
 
 static void writeSequenceHtml(struct trackDb *tdb, char *gencodeId, struct genePred *transAnno)
 /* write links to get sequences */
 {
 printf("<table class=\"hgcCcds\"><thead>\n");
 printf("<tr><th colspan=\"2\">Sequences</tr>\n");
 printf("</thead><tbody>\n");
 if (transAnno->cdsStart < transAnno->cdsEnd)
     {
@@ -849,71 +901,75 @@
 struct wgEncodeGencodePdb *pdbs = metaDataLoad(tdb, conn, gencodeId, "wgEncodeGencodePdb", "transcriptId", sqlQueryMulti, (sqlLoadFunc)wgEncodeGencodePdbLoad);
 struct wgEncodeGencodePubMed *pubMeds = metaDataLoad(tdb, conn, gencodeId, "wgEncodeGencodePubMed", "transcriptId", sqlQueryMulti, (sqlLoadFunc)wgEncodeGencodePubMedLoad);
 bool haveEntrezGene = haveGencodeTable(conn, tdb, "wgEncodeGencodeEntrezGene");
 struct wgEncodeGencodeEntrezGene *entrezGenes = haveEntrezGene ? metaDataLoad(tdb, conn, gencodeId, "wgEncodeGencodeEntrezGene", "transcriptId", sqlQueryMulti, (sqlLoadFunc)wgEncodeGencodeEntrezGeneLoad) : NULL;
 struct wgEncodeGencodeRefSeq *refSeqs = metaDataLoad(tdb, conn, gencodeId, "wgEncodeGencodeRefSeq", "transcriptId", sqlQueryMulti, (sqlLoadFunc)wgEncodeGencodeRefSeqLoad);
 struct wgEncodeGencodeTag *tags = metaDataLoad(tdb, conn, gencodeId, "wgEncodeGencodeTag", "transcriptId", sqlQueryMulti, (sqlLoadFunc)wgEncodeGencodeTagLoad);
 struct wgEncodeGencodeTranscriptSupport *transcriptSupports = metaDataLoad(tdb, conn, gencodeId, "wgEncodeGencodeTranscriptSupport", "transcriptId", sqlQueryMulti, (sqlLoadFunc)wgEncodeGencodeTranscriptSupportLoad);
 struct wgEncodeGencodeExonSupport *exonSupports = NULL;
 // exonSupports not available in back mapped GENCODE releases
 if (haveGencodeTable(conn, tdb, "wgEncodeGencodeExonSupport"))
     exonSupports = metaDataLoad(tdb, conn, gencodeId, "wgEncodeGencodeExonSupport", "transcriptId", sqlQueryMulti, (sqlLoadFunc)wgEncodeGencodeExonSupportLoad);
 struct wgEncodeGencodeUniProt *uniProts = metaDataLoad(tdb, conn, gencodeId, "wgEncodeGencodeUniProt", "transcriptId", sqlQueryMulti, (sqlLoadFunc)wgEncodeGencodeUniProtLoad);
 slSort(&uniProts, uniProtDatasetCmp);
 bool haveTsl = haveGencodeTable(conn, tdb, "wgEncodeGencodeTranscriptionSupportLevel");
 struct wgEncodeGencodeTranscriptionSupportLevel *tsl = haveTsl ? metaDataLoad(tdb, conn, gencodeId, "wgEncodeGencodeTranscriptionSupportLevel", "transcriptId", 0, (sqlLoadFunc)wgEncodeGencodeTranscriptionSupportLevelLoad) : NULL;
+boolean haveGeneSymbolSource = haveGencodeTable(conn, tdb, "wgEncodeGencodeGeneSymbol");
+struct wgEncodeGencodeGeneSymbol *geneSymbolSource = haveGeneSymbolSource ? metaDataLoad(tdb, conn, gencodeId, "wgEncodeGencodeGeneSymbol", "transcriptId", 0, (sqlLoadFunc)wgEncodeGencodeGeneSymbolLoad) : NULL;
     
 int geneChromStart, geneChromEnd;
 getGeneBounds(tdb, conn, transAnno, &geneChromStart, &geneChromEnd);
 
 char title[256];
-safef(title, sizeof(title), "GENCODE V%s Transcript Annotation", getGencodeVersion(tdb));
+safef(title, sizeof(title), "GENCODE V%s Transcript Annotation", gencodeGetVersion(tdb));
 char header[256];
 safef(header, sizeof(header), "%s %s", title, gencodeId);
 if (!isEmpty(transAttrs->geneName))
     safef(header, sizeof(header), "%s %s (%s)", title, gencodeId, transAttrs->geneName);
 else
     safef(header, sizeof(header), "%s %s", title, gencodeId);
 cartWebStart(cart, database, "%s", header);
 printf("<H2>%s</H2>\n", header);
 
-writeBasicInfoHtml(conn, tdb, gencodeId, transAnno, transAttrs, geneChromStart, geneChromEnd, geneSource, transcriptSource, tags, haveTsl, tsl);
+writeBasicInfoHtml(conn, tdb, gencodeId, transAnno, transAttrs, geneChromStart, geneChromEnd, geneSource, transcriptSource, tags,
+                   haveTsl, tsl, haveGeneSymbolSource, geneSymbolSource);
 writeTagLinkHtml(tags);
 writeSequenceHtml(tdb, gencodeId, transAnno);
 if (haveRemarks)
     writeAnnotationRemarkHtml(remarks);
 if (isProteinCodingTrans(transAttrs))
     writePdbLinkHtml(pdbs);
 writePubMedLinkHtml(pubMeds);
 if (haveEntrezGene)
     writeEntrezGeneLinkHtml(entrezGenes);
 writeRefSeqLinkHtml(refSeqs);
 if (isProteinCodingTrans(transAttrs))
     writeUniProtLinkHtml(uniProts);
 writeSupportingEvidenceLinkHtml(tdb, gencodeId, transcriptSupports, exonSupports);
 
 wgEncodeGencodeAttrsFree(&transAttrs);
 wgEncodeGencodeAnnotationRemarkFreeList(&remarks);
 wgEncodeGencodeGeneSourceFreeList(&geneSource);
 wgEncodeGencodeTranscriptSourceFreeList(&transcriptSource);
 wgEncodeGencodePdbFreeList(&pdbs);
 wgEncodeGencodePubMedFreeList(&pubMeds);
 wgEncodeGencodeEntrezGeneFreeList(&entrezGenes);
 wgEncodeGencodeRefSeqFreeList(&refSeqs);
 wgEncodeGencodeTranscriptSupportFreeList(&transcriptSupports);
 wgEncodeGencodeExonSupportFreeList(&exonSupports);
 wgEncodeGencodeUniProtFreeList(&uniProts);
+wgEncodeGencodeGeneSymbolFreeList(&geneSymbolSource);
 wgEncodeGencodeTranscriptionSupportLevelFreeList(&tsl);
 }
 
 static void doGencodeGene2WayPseudo(struct trackDb *tdb, char *gencodeId, struct sqlConnection *conn, struct genePred *pseudoAnno)
 /* Process click on a GENCODE two-way pseudogene annotation track. */
 {
 char header[256];
 safef(header, sizeof(header), "GENCODE 2-way consensus pseudogene %s", gencodeId);
 cartWebStart(cart, database, "%s", header);
 printf("<H2>%s</H2>\n", header);
 printf("<b>Yale id:</b> ");
 prExtIdAnchor(gencodeId, yalePseudoUrl);
 printf("<br>");
 printPos(pseudoAnno->chrom, pseudoAnno->txStart, pseudoAnno->txEnd, pseudoAnno->strand, FALSE, NULL);
 }