a94b20dd5562fcdc56e25819443447699cba3361
kate
  Sun Nov 15 11:43:53 2015 -0800
Initial code for variable height layout of GTEx gene track

diff --git src/hg/hgTracks/gtexTracks.c src/hg/hgTracks/gtexTracks.c
index 5d8f1da..e64e887 100644
--- src/hg/hgTracks/gtexTracks.c
+++ src/hg/hgTracks/gtexTracks.c
@@ -316,31 +316,31 @@
 {
 #ifdef MULTI_REGION
 int winSize = virtWinBaseCount; // GALT CHANGED OLD winEnd - winStart;
 #else
 int winSize = winEnd - winStart;
 #endif
 
 if (winSize < WIN_MAX_GRAPH)
     return MAX_GRAPH_PADDING;
 else if (winSize < WIN_MED_GRAPH)
     return MED_GRAPH_PADDING;
 else
     return MIN_GRAPH_PADDING;
 }
 
-static int gtexGraphHeight()
+static int gtexMaxGraphHeight()
 {
 #ifdef MULTI_REGION
 int winSize = virtWinBaseCount; // GALT CHANGED OLD winEnd - winStart;
 #else
 int winSize = winEnd - winStart;
 #endif
 if (winSize < WIN_MAX_GRAPH)
     return MAX_GRAPH_HEIGHT;
 else if (winSize < WIN_MED_GRAPH)
     return MED_GRAPH_HEIGHT;
 else
     return MIN_GRAPH_HEIGHT;
 }
 
 static int gtexGraphWidth(struct gtexGeneInfo *geneInfo)
@@ -388,113 +388,139 @@
 return (scaled * (maxHeight-1));
 }
 
 static int valToClippedHeight(double val, double maxVal, int maxView, int maxHeight, 
                                         boolean doLogTransform)
 /* Convert a value from 0 to maxVal to 0 to maxHeight-1, with clipping, or log transform the value */
 {
 double useVal = val;
 double useMax = maxVal;
 if (!doLogTransform)
     {
     useMax = maxView;
     if (val > maxView)
         useVal = maxView;
     }
-return valToHeight(useVal, useMax, gtexGraphHeight(), doLogTransform);
+return valToHeight(useVal, useMax, gtexMaxGraphHeight(), doLogTransform);
 }
 
 static void drawGraphBase(struct hvGfx *hvg, int x, int y, struct gtexGeneInfo *geneInfo)
 /* Draw faint line under graph to delineate extent when bars are missing (tissue w/ 0 expression) */
 {
 Color lightGray = MAKECOLOR_32(0xD1, 0xD1, 0xD1);
 int graphWidth = gtexGraphWidth(geneInfo);
 hvGfxBox(hvg, x, y, graphWidth, 1, lightGray);
 }
 
+static int gtexGeneGraphHeight(struct track *tg, struct gtexGeneInfo *geneInfo, 
+                                boolean doLogTransform, boolean doTop)
+/* Determine height in pixels of graph.  This will be the box for tissue with highest expression
+   If doTop is false, compute height of bottom graph of comparison */
+{
+struct gtexGeneBed *geneBed = geneInfo->geneBed;
+int i;
+double maxExp = 0.0;
+int expCount = geneBed->expCount;
+double expScore;
+for (i=0; i<expCount; i++)
+    {
+    if (doTop)
+        expScore = (geneInfo->medians1 ? geneInfo->medians1[i] : geneBed->expScores[i]);
+    else
+        expScore = geneInfo->medians2[i];
+    maxExp = max(maxExp, expScore);
+    }
+double viewMax = (double)cartUsualIntClosestToHome(cart, tg->tdb, FALSE, 
+                                GTEX_MAX_LIMIT, GTEX_MAX_LIMIT_DEFAULT);
+double maxMedian = ((struct gtexGeneExtras *)tg->extraUiData)->maxMedian;
+return valToClippedHeight(maxExp, maxMedian, viewMax, gtexMaxGraphHeight(), doLogTransform);
+}
+
 static void gtexGeneDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, 
                 double scale, MgFont *font, Color color, enum trackVisibility vis)
 /* Draw tissue expression bar graph over gene model. 
    Optionally, draw a second graph under gene, to compare sample sets */
 {
 struct gtexGeneInfo *geneInfo = (struct gtexGeneInfo *)item;
 struct gtexGeneBed *geneBed = geneInfo->geneBed;
 boolean doLogTransform = cartUsualBooleanClosestToHome(cart, tg->tdb, FALSE, GTEX_LOG_TRANSFORM, 
                                                 GTEX_LOG_TRANSFORM_DEFAULT);
 // Color in dense mode using transcriptClass
 Color statusColor = getTranscriptStatusColor(hvg, geneBed);
 if (vis != tvFull && vis != tvPack)
     {
     bedDrawSimpleAt(tg, geneBed, hvg, xOff, y, scale, font, statusColor, vis);
     return;
     }
 struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData;
 if (extras->isComparison && (tg->visibility == tvFull || tg->visibility == tvPack))
         //&& gtexGraphHeight() != MIN_GRAPH_HEIGHT)
     // compute medians based on configuration (comparisons, and later, filters)
     loadComputedMedians(geneInfo, extras);
 
 int heightPer = tg->heightPer;
 int graphX = gtexGraphX(geneBed);
 if (graphX < 0)
     return;
-int yZero = gtexGraphHeight() + y - 1;  // yZero is bottom of graph
+
+int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, doLogTransform, TRUE);
+int yZero = topGraphHeight + y - 1;  // yZero is bottom of graph
 
 #ifndef MULTI_REGION
 int x1 = xOff + graphX;         // x1 is at left of graph
 int keepX = x1;                 // FIXME:  Too many X's!
 drawGraphBase(hvg, keepX, yZero+1, geneInfo);
 
 int startX = x1;
-int i;
-int expCount = geneBed->expCount;
-double maxMedian = ((struct gtexGeneExtras *)tg->extraUiData)->maxMedian;
 struct rgbColor lineColor = {.r=0};
 int lineColorIx = hvGfxFindColorIx(hvg, lineColor.r, lineColor.g, lineColor.b);
 int barWidth = gtexBarWidth();
 int graphPadding = gtexGraphPadding();
 char *colorScheme = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, GTEX_COLORS, 
                         GTEX_COLORS_DEFAULT);
 Color labelColor = MG_GRAY;
 Color clipColor = MG_MAGENTA;
-double viewMax = (double)cartUsualIntClosestToHome(cart, tg->tdb, FALSE, 
-                                GTEX_MAX_LIMIT, GTEX_MAX_LIMIT_DEFAULT);
 
 // add labels to comparison graphs
 // TODO: generalize
 if (geneInfo->medians2)
     {
     hvGfxText(hvg, x1, yZero - tl.fontHeight, labelColor, font, "F");
     hvGfxText(hvg, x1, yZero + gtexGeneHeight() + gtexGeneMargin(), labelColor, font, "M");
     startX = startX + tl.mWidth+2;
     x1 = startX;
     }
 
 // draw bar graph
 // TODO: share this code with other graph
+double viewMax = (double)cartUsualIntClosestToHome(cart, tg->tdb, FALSE, 
+                                GTEX_MAX_LIMIT, GTEX_MAX_LIMIT_DEFAULT);
+double maxMedian = ((struct gtexGeneExtras *)tg->extraUiData)->maxMedian;
+int i;
+int expCount = geneBed->expCount;
 for (i=0; i<expCount; i++)
     {
     struct rgbColor fillColor = extras->colors[i];
     if (barWidth == 1 && sameString(colorScheme, GTEX_COLORS_GTEX))
         {
         // brighten colors a bit so they'll be more visible at this scale
         fillColor = gtexTissueBrightenColor(fillColor);
         }
     int fillColorIx = hvGfxFindColorIx(hvg, fillColor.r, fillColor.g, fillColor.b);
     double expScore = (geneInfo->medians1 ? geneInfo->medians1[i] : geneBed->expScores[i]);
     int height = valToClippedHeight(expScore, maxMedian, viewMax, 
-                                        gtexGraphHeight(), doLogTransform);
+                                        gtexMaxGraphHeight(), doLogTransform);
     if (graphPadding == 0 || sameString(colorScheme, GTEX_COLORS_GTEX))
         hvGfxBox(hvg, x1, yZero-height+1, barWidth, height, fillColorIx);
     else
         hvGfxOutlinedBox(hvg, x1, yZero-height+1, barWidth, height, fillColorIx, lineColorIx);
     // mark clipped bar with magenta tip
     if (!doLogTransform && expScore > viewMax)
         hvGfxBox(hvg, x1, yZero-height+1, barWidth, 1, clipColor);
     x1 = x1 + barWidth + graphPadding;
     }
 #endif
 
 // draw gene model
 int yGene = yZero + gtexGeneMargin()-1;
 tg->heightPer = gtexGeneHeight()+1;
 struct linkedFeatures *lf = linkedFeaturesFromGenePred(tg, geneInfo->geneModel, FALSE);
@@ -511,31 +537,32 @@
 yZero = yGene + gtexGeneHeight() + 1; // yZero is at top of graph
 drawGraphBase(hvg, keepX, yZero-1, geneInfo);
 
 for (i=0; i<expCount; i++)
     {
     struct rgbColor fillColor = extras->colors[i];
     if (barWidth == 1 && sameString(colorScheme, GTEX_COLORS_GTEX))
         {
         // brighten colors a bit so they'll be more visible at this scale
         struct hslColor hsl = mgRgbToHsl(fillColor);
         hsl.s = min(1000, hsl.s + 300);
         fillColor = mgHslToRgb(hsl);
         }
     int fillColorIx = hvGfxFindColorIx(hvg, fillColor.r, fillColor.g, fillColor.b);
     double expScore = geneInfo->medians2[i];
-    int height = valToClippedHeight(expScore, maxMedian, viewMax, gtexGraphHeight(), doLogTransform);
+    int height = valToClippedHeight(expScore, maxMedian, viewMax, gtexMaxGraphHeight(), 
+                                        doLogTransform);
     if (graphPadding == 0 || sameString(colorScheme, GTEX_COLORS_GTEX))
         hvGfxBox(hvg, x1, yZero, barWidth, height, fillColorIx);
     else
         hvGfxOutlinedBox(hvg, x1, yZero, barWidth, height, fillColorIx, lineColorIx);
     if (!doLogTransform && expScore > viewMax)
         hvGfxBox(hvg, x1, yZero + height, barWidth, 1, clipColor);
     x1 = x1 + barWidth + graphPadding;
     }
 #endif
 }
 
 #ifdef MULTI_REGION
 static int gtexGeneNonPropPixelWidth(struct track *tg, void *item)
 /* Return end chromosome coordinate of item, including graph */
 {
@@ -564,31 +591,31 @@
         //&& gtexGraphHeight() != MIN_GRAPH_HEIGHT)
     // compute medians based on configuration (comparisons, and later, filters)
     loadComputedMedians(geneInfo, extras);
 int i;
 int expCount = geneBed->expCount;
 double maxMedian = ((struct gtexGeneExtras *)tg->extraUiData)->maxMedian;
 struct rgbColor lineColor = {.r=0};
 int lineColorIx = hvGfxFindColorIx(hvg, lineColor.r, lineColor.g, lineColor.b);
 // GALT REMOVE int heightPer = tg->heightPer;
 
 int graphX = gtexGraphX(geneBed);
 if (graphX < 0)
     return;
 int x1 = xOff + graphX; // x1 is at left of graph
 int startX = x1;
-int yZero = gtexGraphHeight() + y - 1; // yZero is at bottom of graph
+int yZero = gtexMaxGraphHeight() + y - 1; // yZero is at bottom of graph
 
 // draw faint line under graph to delineate extent when bars are missing (tissue w/ 0 expression)
 // TODO: skip missing bars
 Color lightGray = MAKECOLOR_32(0xD1, 0xD1, 0xD1);
 int graphWidth = gtexGraphWidth(geneInfo);
 hvGfxBox(hvg, x1, yZero+1, graphWidth, 1, lightGray);
 
 int barWidth = gtexBarWidth();
 int graphPadding = gtexGraphPadding();
 
 char *colorScheme = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, GTEX_COLORS,
                         GTEX_COLORS_DEFAULT);
 Color labelColor = MG_GRAY;
 
 if (geneInfo->medians2)
@@ -599,31 +626,31 @@
     hvGfxText(hvg, x1, yZero + gtexGeneHeight() + gtexGeneMargin(), labelColor, font, "M");
     startX = startX + tl.mWidth + 2;
     x1 = startX;
     }
 for (i=0; i<expCount; i++)
     {
     struct rgbColor fillColor = extras->colors[i];
     if (barWidth == 1 && sameString(colorScheme, GTEX_COLORS_GTEX))
         {
         // brighten colors a bit so they'll be more visible at this scale
         fillColor = gtexTissueBrightenColor(fillColor);
         }
     int fillColorIx = hvGfxFindColorIx(hvg, fillColor.r, fillColor.g, fillColor.b);
 
     double expScore = (geneInfo->medians1 ? geneInfo->medians1[i] : geneBed->expScores[i]);
-    int height = valToHeight(expScore, maxMedian, gtexGraphHeight(), doLogTransform);
+    int height = valToHeight(expScore, maxMedian, gtexMaxGraphHeight(), doLogTransform);
     if (graphPadding == 0 || sameString(colorScheme, GTEX_COLORS_GTEX))
         hvGfxBox(hvg, x1, yZero-height, barWidth, height, fillColorIx);
     else
         hvGfxOutlinedBox(hvg, x1, yZero-height, barWidth, height, fillColorIx, lineColorIx);
     x1 = x1 + barWidth + graphPadding;
     }
 
 // mark gene extent
 int yGene = yZero + gtexGeneMargin() - 1;
 
 /* GALT NOT DONE HERE NOW
 // draw gene model
 tg->heightPer = gtexGeneHeight()+1;
 struct linkedFeatures *lf = linkedFeaturesFromGenePred(tg, geneInfo->geneModel, FALSE);
 lf->filterColor = statusColor;
@@ -635,146 +662,196 @@
 // draw comparison graph (upside down)
 x1 = startX;
 yZero = yGene + gtexGeneHeight(); // yZero is at top of graph
 for (i=0; i<expCount; i++)
     {
     struct rgbColor fillColor = extras->colors[i];
     if (barWidth == 1 && sameString(colorScheme, GTEX_COLORS_GTEX))
         {
         // brighten colors a bit so they'll be more visible at this scale
         struct hslColor hsl = mgRgbToHsl(fillColor);
         hsl.s = min(1000, hsl.s + 300);
         fillColor = mgHslToRgb(hsl);
         }
     int fillColorIx = hvGfxFindColorIx(hvg, fillColor.r, fillColor.g, fillColor.b);
     double expScore = geneInfo->medians2[i];
-    int height = valToHeight(expScore, maxMedian, gtexGraphHeight(), doLogTransform);
+    int height = valToHeight(expScore, maxMedian, gtexMaxGraphHeight(), doLogTransform);
     if (graphPadding == 0 || sameString(colorScheme, GTEX_COLORS_GTEX))
         hvGfxBox(hvg, x1, yZero, barWidth, height, fillColorIx);
     else
         hvGfxOutlinedBox(hvg, x1, yZero, barWidth, height, fillColorIx, lineColorIx);
     x1 = x1 + barWidth + graphPadding;
     }
 }
 #endif
 
+static int gtexGeneItemHeight(struct track *tg, void *item)
+{
+if ((item == NULL) || (tg->visibility == tvSquish) || (tg->visibility == tvDense))
+    return 0;
+boolean doLogTransform = cartUsualBooleanClosestToHome(cart, tg->tdb, FALSE, GTEX_LOG_TRANSFORM, 
+                                                GTEX_LOG_TRANSFORM_DEFAULT);
+struct gtexGeneInfo *geneInfo = (struct gtexGeneInfo *)item;
+int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, doLogTransform, TRUE);
+int bottomGraphHeight = 0;
+boolean isComparison = ((struct gtexGeneExtras *)tg->extraUiData)->isComparison;
+if (isComparison)
+    bottomGraphHeight = gtexGeneGraphHeight(tg, geneInfo, doLogTransform, FALSE);
+int height = topGraphHeight + bottomGraphHeight + gtexGeneMargin() + gtexGeneHeight();
+return height;
+}
+
+static void gtexGeneDrawItemsFull(struct track *tg, int seqStart, int seqEnd,
+                                      struct hvGfx *hvg, int xOff, int yOff, int width,
+                                      MgFont *font, Color color, enum trackVisibility vis)
+/* Draw GTEx gene graphs in full mode.  Special handling as they are variable height */
+{
+double scale = scaleForWindow(width, seqStart, seqEnd);
+struct slList *item;
+int y = yOff + 1;
+for (item = tg->items; item != NULL; item = item->next)
+    {
+    tg->drawItemAt(tg, item, hvg, xOff, y, scale, font, color, vis);
+    genericDrawNextItem(tg, item, hvg, xOff, y, scale, color, vis);
+    int height = gtexGeneItemHeight(tg, item);
+    y += height;
+    }
+}
+
+void gtexGeneDrawItems(struct track *tg, int seqStart, int seqEnd, 
+                        struct hvGfx *hvg, int xOff, int yOff, int width, 
+                        MgFont *font, Color color, enum trackVisibility vis)
+/* Draw GTEx gene graphs, which are of variable height so require custom layout in full
+ * and pack modes */
+{
+if (vis == tvDense || vis == tvSquish)
+    genericDrawItems(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis);
+else if (vis == tvFull)
+    gtexGeneDrawItemsFull(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis);
+else if (vis == tvPack)
+    genericDrawItems(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis);
+}
+
 static void gtexGeneMapItem(struct track *tg, struct hvGfx *hvg, void *item, char *itemName, 
                         char *mapItemName, int start, int end, int x, int y, int width, int height)
 /* Create a map box for each tissue (bar in the graph) or a single map for squish/dense modes */
 {
 if (tg->visibility == tvDense || tg->visibility == tvSquish)
     {
     genericMapItem(tg, hvg, item, itemName, itemName, start, end, x, y, width, height);
     return;
     }
 struct gtexTissue *tissues = getTissues();
 struct gtexTissue *tissue = NULL;
 struct gtexGeneInfo *geneInfo = item;
 struct gtexGeneBed *geneBed = geneInfo->geneBed;
 int barWidth = gtexBarWidth();
 int padding = gtexGraphPadding();
 double maxMedian = ((struct gtexGeneExtras *)tg->extraUiData)->maxMedian;
 
 int graphX = gtexGraphX(geneBed);
 if (graphX < 0)
     return;
 // x1 is at left of graph
 int x1 = insideX + graphX;
 
 if (geneInfo->medians2)
     {
     // skip over labels in comparison graphs
     x1 = x1 + tl.mWidth+ 2;
     }
 int i = 0;
-int yZero = gtexGraphHeight() + y - 1;
+
 boolean doLogTransform = cartUsualBooleanClosestToHome(cart, tg->tdb, FALSE, GTEX_LOG_TRANSFORM, 
                                                 GTEX_LOG_TRANSFORM_DEFAULT);
+int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, doLogTransform, TRUE);
+int yZero = topGraphHeight + y - 1;  // yZero is bottom of graph
+
 double viewMax = (double)cartUsualIntClosestToHome(cart, tg->tdb, FALSE, 
                                 GTEX_MAX_LIMIT, GTEX_MAX_LIMIT_DEFAULT);
 for (tissue = tissues; tissue != NULL; tissue = tissue->next, i++)
     {
     int height = valToClippedHeight(geneBed->expScores[i], maxMedian, viewMax, 
-                                        gtexGraphHeight(), doLogTransform);
+                                        gtexMaxGraphHeight(), doLogTransform);
     mapBoxHc(hvg, start, end, x1, yZero-height, barWidth, height, tg->track, mapItemName, tissue->description);
     // add map box to comparison graph
     if (geneInfo->medians2)
         {
         double expScore = geneInfo->medians2[i];
-        int height = valToClippedHeight(expScore, maxMedian, viewMax, gtexGraphHeight(), doLogTransform);
+        int height = valToClippedHeight(expScore, maxMedian, viewMax, gtexMaxGraphHeight(), doLogTransform);
         int y = yZero + gtexGeneHeight() + gtexGeneMargin();
         mapBoxHc(hvg, start, end, x1, y, barWidth, height, tg->track, mapItemName, tissue->description);
         }
     x1 = x1 + barWidth + padding;
     }
 }
 
 static char *gtexGeneItemName(struct track *tg, void *item)
 /* Return gene name */
 {
 struct gtexGeneInfo *geneInfo = (struct gtexGeneInfo *)item;
 struct gtexGeneBed *geneBed = geneInfo->geneBed;
 return geneBed->name;
 }
 
-static int gtexGeneItemHeight(struct track *tg, void *item)
+static int gtexGeneTotalHeight(struct track *tg, enum trackVisibility vis)
+/* Figure out total height of track. Set in track and also return it */
 {
-if ((item == NULL) || (tg->visibility == tvSquish) || (tg->visibility == tvDense))
-    return 0;
-int extra = 0;
-if (((struct gtexGeneExtras *)tg->extraUiData)->isComparison)
-    extra = gtexGraphHeight() + 2;
-return gtexGraphHeight() + gtexGeneMargin() + gtexGeneHeight() + extra;
+int height = 0;
+struct gtexGeneInfo *item;
+if (tg->visibility == tvSquish || tg->visibility == tvDense)
+    {
+    height = tgFixedTotalHeightOptionalOverflow(tg, vis, tl.fontHeight+1, tl.fontHeight, FALSE);
     }
-
-static int gtexTotalHeight(struct track *tg, enum trackVisibility vis)
-/* Figure out total height of track */
+else if (tg->visibility == tvFull)
     {
-int height;
-int extra = 0;
-if (((struct gtexGeneExtras *)tg->extraUiData)->isComparison)
-    extra = gtexGraphHeight() + 2;
-if (tg->visibility == tvSquish || tg->visibility == tvDense)
-    height = 10;
+    for (item = tg->items; item != NULL; item = item->next)
+        height += gtexGeneItemHeight(tg, item);
+    }
 else
-    height = gtexGraphHeight() + gtexGeneMargin() + gtexGeneHeight() + extra;
-return tgFixedTotalHeightOptionalOverflow(tg, vis, height, height, FALSE);
+    {
+    for (item = tg->items; item != NULL; item = item->next)
+        height += gtexGeneItemHeight(tg, item);
+    }
+tg->height = height;
+return height;
 }
 
 static int gtexGeneItemStart(struct track *tg, void *item)
 /* Return end chromosome coordinate of item, including graph */
 {
 struct gtexGeneInfo *geneInfo = (struct gtexGeneInfo *)item;
 struct gtexGeneBed *geneBed = geneInfo->geneBed;
 return geneBed->chromStart;
 }
 
 static int gtexGeneItemEnd(struct track *tg, void *item)
 /* Return end chromosome coordinate of item, including graph */
 {
 struct gtexGeneInfo *geneInfo = (struct gtexGeneInfo *)item;
 struct gtexGeneBed *geneBed = geneInfo->geneBed;
 double scale = scaleForWindow(insideWidth, winStart, winEnd);
 int graphWidth = gtexGraphWidth(geneInfo);
 return max(geneBed->chromEnd, max(winStart, geneBed->chromStart) + graphWidth/scale);
 }
 
 void gtexGeneMethods(struct track *tg)
 {
+tg->drawItems = gtexGeneDrawItems;
 tg->drawItemAt = gtexGeneDrawAt;
 tg->loadItems = gtexGeneLoadItems;
 //tg->freeItems = gtexGeneFreeItems;
 tg->mapItem = gtexGeneMapItem;
 tg->itemName = gtexGeneItemName;
 tg->mapItemName = gtexGeneItemName;
 tg->itemHeight = gtexGeneItemHeight;
 tg->itemStart = gtexGeneItemStart;
 tg->itemEnd = gtexGeneItemEnd;
-tg->totalHeight = gtexTotalHeight;
+tg->totalHeight = gtexGeneTotalHeight;
 #ifdef MULTI_REGION
 tg->nonPropDrawItemAt = gtexGeneNonPropDrawAt;
 tg->nonPropPixelWidth = gtexGeneNonPropPixelWidth;
 #endif
 }