]> err.no Git - mapper/commitdiff
Use a dynamicaly sized buffer pixmap
authorKaj-Michael Lang <milang@onion.tal.org>
Tue, 26 Feb 2008 14:53:36 +0000 (16:53 +0200)
committerKaj-Michael Lang <milang@onion.tal.org>
Tue, 26 Feb 2008 14:53:36 +0000 (16:53 +0200)
src/map-download.c
src/map-poi.c
src/map-poi.h
src/map.c
src/map.h
src/track.c

index 77264c5ecfc2e4ff22bda4074844880ada46d8c4..30d9ce0966d9cbe1056b6b64b2e15d3726ec80b8 100644 (file)
@@ -151,7 +151,7 @@ while (_curl_multi && (msg = curl_multi_info_read(_curl_multi, &num_msgs))) {
 }
 
 /* Up to 1 transfer per tile. */
-while (num_transfers < (BUF_WIDTH_TILES * BUF_HEIGHT_TILES) && g_tree_nnodes(pui_tree)) {
+while (num_transfers < (4*4) && g_tree_nnodes(pui_tree)) {
        ProgressUpdateInfo *pui;
        g_tree_foreach(pui_tree, (GTraverseFunc)get_next_pui, &pui);
 
@@ -406,11 +406,9 @@ if (!pui->retries || g_file_test(pui->dest_str, G_FILE_TEST_EXISTS)) {
                guint tilex, tiley, tilex_end, tiley_end;
                for (tilex = pui->tilex << zoom_diff, tilex_end = tilex + (1 << zoom_diff); tilex < tilex_end; tilex++) {
                        for (tiley = pui->tiley << zoom_diff, tiley_end = tiley + (1 << zoom_diff); tiley < tiley_end; tiley++) {
-                               if ((tilex - _base_tilex) < BUF_WIDTH_TILES && (tiley - _base_tiley) < BUF_HEIGHT_TILES) {
-                                       map_render_tile(tilex, tiley, ((tilex - _base_tilex) << TILE_SIZE_P2), ((tiley - _base_tiley) << TILE_SIZE_P2), TRUE);
+                               if (map_render_tile(tilex, tiley, ((tilex - _base_tilex) << TILE_SIZE_P2), ((tiley - _base_tiley) << TILE_SIZE_P2), TRUE)==TRUE) {
                                        map_render_data();
-                                       gtk_widget_queue_draw_area
-                                           (_map_widget,
+                                       gtk_widget_queue_draw_area(_map_widget,
                                             ((tilex - _base_tilex) << TILE_SIZE_P2) - _offsetx,
                                             ((tiley - _base_tiley) << TILE_SIZE_P2) - _offsety,
                                             TILE_SIZE_PIXELS, TILE_SIZE_PIXELS);
index 318f2ee4c6a52b550d5f1d4cfc527176caaf030d..cf5c68aa6eb2de8f6f8669b32e2fd75d4a672ee8 100644 (file)
@@ -191,22 +191,23 @@ return found;
  * This should be done before rendering track data.
  */
 void
-map_render_all_pois(void)
+map_render_all_pois(guint width, guint height)
 {
-guint unitx, unity;
-gdouble lat1, lat2, lon1, lon2;
-gint poix, poiy;
 GdkPixbuf *pixbuf = NULL;
 GtkTreeIter iter;
+guint unitx, unity;
+gint poix, poiy;
+gdouble lat1, lat2, lon1, lon2;
 gboolean valid;
 
 if (_poi_zoom <= _zoom) 
        return;
 
 unitx = x2unit(0);
-unity = y2unit(BUF_HEIGHT_PIXELS);
+unity = y2unit(height);
 unit2latlon(unitx, unity, lat1, lon1);
-unitx = x2unit(BUF_WIDTH_PIXELS);
+
+unitx = x2unit(width);
 unity = y2unit(0);
 unit2latlon(unitx, unity, lat2, lon2);
 
index f16050c30f25e09cd7791de35de2d85dc8bb585d..72922be499bd9ebdf9d4d08602c66127edcf50a3 100644 (file)
@@ -30,7 +30,8 @@ gboolean map_poi_init(GtkWidget *map_widget);
 void map_poi_deinit(void);
 
 void map_render_poi(void);
-gboolean map_poi_find_at_latlon(gdouble lat, gdouble lon, guint *poi_id);
+void map_render_all_pois(guint width, guint height);
 void map_poi_cache_clear(void);
+gboolean map_poi_find_at_latlon(gdouble lat, gdouble lon, guint *poi_id);
 
 #endif
index a276d1a8ad9cdc70d79533f43775ae74061d511f..6ee6c192f6c3ac6445d671fc6726c26a759fee06 100644 (file)
--- a/src/map.c
+++ b/src/map.c
 
 #define DEBUG_MAP_TIME 1
 
+/* Initial size */
+#define BUF_WIDTH_TILES (4)
+#define BUF_HEIGHT_TILES (3)
+#define BUF_WIDTH_PIXELS (1024)
+#define BUF_HEIGHT_PIXELS (768)
+
+static guint buf_width_tiles=BUF_WIDTH_TILES;
+static guint buf_height_tiles=BUF_HEIGHT_TILES;
+static guint buf_width_pixels=BUF_WIDTH_PIXELS;
+static guint buf_height_pixels=BUF_HEIGHT_PIXELS;
+
 /** The "base tile" is the upper-left tile in the pixmap. */
 guint _base_tilex = -5;
 guint _base_tiley = -5;
@@ -104,6 +115,10 @@ static PangoContext *speed_context;
 static PangoLayout *speed_layout;
 static PangoFontDescription *speed_fontdesc;
 
+#ifdef WITH_CAIRO
+cairo_t *ct_pixmap;
+#endif
+
 static gint zoom_timeout_sid=0;
 static gint map_mode=0;
 static gboolean map_data_needs_refresh=FALSE;
@@ -137,6 +152,7 @@ map_new(void)
 {
 GtkWidget *map_widget;
 
+g_debug("MAP: new");
 map_widget=gtk_drawing_area_new();
 g_signal_connect_after(G_OBJECT(map_widget), "realize", G_CALLBACK(map_cb_after_realize), NULL);
 g_signal_connect(G_OBJECT(map_widget), "configure_event", G_CALLBACK(map_cb_configure), NULL);
@@ -149,7 +165,7 @@ map_cb_after_realize(GtkWidget *map_widget, gpointer data)
 {
 GdkColor color;
 
-_map_pixmap=gdk_pixmap_new(map_widget->window, BUF_WIDTH_PIXELS, BUF_HEIGHT_PIXELS, -1);
+g_debug("MAP: after_realize");
 
 scale_context=gtk_widget_get_pango_context(map_widget);
 scale_layout=pango_layout_new(scale_context);
@@ -192,9 +208,32 @@ return TRUE;
 static gboolean 
 map_cb_configure(GtkWidget *widget, GdkEventConfigure *event)
 {
+guint tw, th;
+
+tw=TILE_SIZE_PIXELS*((widget->allocation.width/TILE_SIZE_PIXELS)+2);
+th=TILE_SIZE_PIXELS*((widget->allocation.height/TILE_SIZE_PIXELS)+2);
+
+g_debug("MAP: configure %d %d -> (%d,%d)", widget->allocation.width, widget->allocation.height, tw, th);
+
+if (_map_pixmap==NULL) {
+       g_debug("Initial buffer pixmap");
+       _map_pixmap=gdk_pixmap_new(widget->window, tw, th, -1);
+} else {
+       if (tw>buf_width_pixels || th>buf_height_pixels) {
+               g_debug("Resize buffer pixmap");
+               g_object_unref(_map_pixmap);
+               _map_pixmap=gdk_pixmap_new(widget->window, tw, th, -1);
+               map_force_redraw();
+       }
+}
 
-_screen_width_pixels = _map_widget->allocation.width;
-_screen_height_pixels = _map_widget->allocation.height;
+buf_width_pixels=tw;
+buf_height_pixels=th;
+buf_width_tiles=buf_width_pixels/TILE_SIZE_PIXELS;
+buf_height_tiles=buf_height_pixels/TILE_SIZE_PIXELS;
+
+_screen_width_pixels = widget->allocation.width;
+_screen_height_pixels = widget->allocation.height;
 _screen_grids_halfwidth = pixel2grid(_screen_width_pixels) / 2;
 _screen_grids_halfheight = pixel2grid(_screen_height_pixels) / 2;
 
@@ -360,12 +399,17 @@ if (se==0) {
 return pixbuf;
 }
 
-void
+gboolean
 map_render_tile(guint tilex, guint tiley, guint destx, guint desty, gboolean fast_fail)
 {
 GdkPixbuf *pixbuf=NULL;
 gint zoff;
 
+g_debug("MAP RT: %d %d %d %d (%d, %d)", tilex, tiley, destx, desty, buf_width_tiles, buf_height_tiles);
+
+if (destx > buf_width_pixels || desty > buf_height_pixels)
+       return FALSE;
+
 if (tilex<_world_size_tiles && tiley<_world_size_tiles) {
        /* The tile is possible. */
        for (zoff = (_curr_repo->double_size ? 1 : 0); !pixbuf && (_zoom + zoff) <= MAX_ZOOM && zoff <= TILE_SIZE_P2; zoff += 1) {
@@ -391,9 +435,10 @@ if (tilex<_world_size_tiles && tiley<_world_size_tiles) {
 if (pixbuf) {
        gdk_draw_pixbuf(_map_pixmap, _gc[COLORABLE_MARK], pixbuf, 0, 0, destx, desty, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS, GDK_RGB_DITHER_NONE, 0, 0);
        g_object_unref(pixbuf);
-       return;
+       return TRUE;
 }
 gdk_draw_rectangle(_map_pixmap, _map_widget->style->black_gc, TRUE, destx, desty, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS);
+return TRUE;
 }
 
 void
@@ -406,7 +451,7 @@ if (map_drag_id>0)
 if (_home.valid)
        map_draw_position_icon(&_home);
 if(_show_poi)
-       map_render_all_pois();
+       map_render_all_pois(buf_width_pixels, buf_height_pixels);
 if(_show_tracks>0)
        map_render_paths();
 }
@@ -424,8 +469,8 @@ gulong tms;
 
 g_timer_start(map_timer);
 #endif
-for (new_y = 0; new_y < BUF_HEIGHT_TILES; ++new_y)
-       for (new_x = 0; new_x < BUF_WIDTH_TILES; ++new_x) {
+for (new_y = 0; new_y < buf_height_tiles; ++new_y)
+       for (new_x = 0; new_x < buf_width_tiles; ++new_x) {
                map_render_tile(_base_tilex + new_x,
                                _base_tiley + new_y,
                                new_x * TILE_SIZE_PIXELS,
@@ -511,7 +556,7 @@ if (new_base_tilex != _base_tilex || new_base_tiley != _base_tiley) {
         * new_y, old_x, old_y, iox, and ioy with that in mind. */
        if (new_base_tiley < _base_tiley) {
                /* New is lower than old - start at bottom and go up. */
-               new_y = BUF_HEIGHT_TILES - 1;
+               new_y = buf_height_tiles - 1;
                ioy = -1;
        } else {
                /* New is higher than old - start at top and go down. */
@@ -520,7 +565,7 @@ if (new_base_tilex != _base_tilex || new_base_tiley != _base_tiley) {
        }
        if (new_base_tilex < _base_tilex) {
                /* New is righter than old - start at right and go left. */
-               base_new_x = BUF_WIDTH_TILES - 1;
+               base_new_x = buf_width_tiles - 1;
                iox = -1;
        } else {
                /* New is lefter than old - start at left and go right. */
@@ -533,13 +578,13 @@ if (new_base_tilex != _base_tilex || new_base_tiley != _base_tiley) {
        base_old_x = base_new_x + new_base_tilex - _base_tilex;
        _base_tilex = new_base_tilex;
        _base_tiley = new_base_tiley;
-       for (j = 0; j < BUF_HEIGHT_TILES; ++j, new_y += ioy, old_y += ioy) {
+       for (j = 0; j < buf_height_tiles; ++j, new_y += ioy, old_y += ioy) {
                new_x = base_new_x;
                old_x = base_old_x;
                /* Iterate over the x tile values. */
-               for (k = 0; k < BUF_WIDTH_TILES; ++k, new_x += iox, old_x += iox) {
+               for (k = 0; k < buf_width_tiles; ++k, new_x += iox, old_x += iox) {
                        /* Can we get this grid block from the old buffer?. */
-                       if (old_x >= 0 && old_x < BUF_WIDTH_TILES && old_y >= 0 && old_y < BUF_HEIGHT_TILES) {
+                       if (old_x >= 0 && old_x < buf_width_tiles && old_y >= 0 && old_y < buf_height_tiles) {
                                /* Copy from old buffer to new buffer. */
                                gdk_draw_drawable(_map_pixmap,
                                                  _gc[COLORABLE_MARK],
@@ -690,7 +735,7 @@ latlon2unit(pos->lat, pos->lon, x, y);
 x1=unit2bufx(x);
 y1=unit2bufy(y);
 
-if ((x1 > BUF_WIDTH_PIXELS) || (y1 > BUF_HEIGHT_PIXELS))
+if ((x1 > buf_width_pixels) || (y1 > buf_height_pixels))
        return;
 
 p=gdk_pixbuf_new_from_file(DATADIR "/pixmaps/mapper/home.png", NULL);
@@ -733,41 +778,52 @@ if (_center_mode>0)
  * IT IS AN ERROR FOR BOTH POINTS TO INDICATE A BREAK.
  */
 void
-map_render_segment(GdkGC * gc_norm, GdkGC * gc_alt, guint unitx1, guint unity1, guint unitx2, guint unity2)
+map_render_segment(GdkGC *gc_norm, GdkGC *gc_alt, guint unitx1, guint unity1, guint unitx2, guint unity2)
 {
-       if (!unity1) {
-               guint x2, y2;
-               x2 = unit2bufx(unitx2);
-               y2 = unit2bufy(unity2);
-               /* Make sure this circle will be visible. */
-               if ((x2 < BUF_WIDTH_PIXELS) && (y2 < BUF_HEIGHT_PIXELS))
-                       gdk_draw_arc(_map_pixmap, gc_alt, FALSE,        /* FALSE: not filled. */
-                                    x2 - _draw_width, y2 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0,   /* start at 0 degrees. */
-                                    360 * 64);
-       } else if (!unity2) {
-               guint x1, y1;
-               x1 = unit2bufx(unitx1);
-               y1 = unit2bufy(unity1);
-               /* Make sure this circle will be visible. */
-               if ((x1 < BUF_WIDTH_PIXELS) && ((unsigned)y1 < BUF_HEIGHT_PIXELS))
-                       gdk_draw_arc(_map_pixmap, gc_alt, FALSE,        /* FALSE: not filled. */
-                                    x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0,   /* start at 0 degrees. */
-                                    360 * 64);
-       } else {
-               gint x1, y1, x2, y2;
-               x1 = unit2bufx(unitx1);
-               y1 = unit2bufy(unity1);
-               x2 = unit2bufx(unitx2);
-               y2 = unit2bufy(unity2);
-               /* Make sure this line could possibly be visible. */
-               if (!((x1 > BUF_WIDTH_PIXELS && x2 > BUF_WIDTH_PIXELS)
-                     || (x1 < 0 && x2 < 0)
-                     || (y1 > BUF_HEIGHT_PIXELS && y2 > BUF_HEIGHT_PIXELS)
-                     || (y1 < 0 && y2 < 0)))
-                       gdk_draw_line(_map_pixmap, gc_norm, x1, y1, x2, y2);
+if (!unity1) {
+       guint x2, y2;
+
+       x2 = unit2bufx(unitx2);
+       y2 = unit2bufy(unity2);
+       /* Make sure this circle will be visible. */
+       if ((x2 < buf_width_pixels) && (y2 < buf_height_pixels))
+               gdk_draw_arc(_map_pixmap, gc_alt, FALSE,        /* FALSE: not filled. */
+                    x2 - _draw_width, y2 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0,   /* start at 0 degrees. */
+                    360 * 64);
+} else if (!unity2) {
+       guint x1, y1;
+
+       x1 = unit2bufx(unitx1);
+       y1 = unit2bufy(unity1);
+       /* Make sure this circle will be visible. */
+       if ((x1 < buf_width_pixels) && ((unsigned)y1 < buf_height_pixels))
+               gdk_draw_arc(_map_pixmap, gc_alt, FALSE,        /* FALSE: not filled. */
+                    x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0,   /* start at 0 degrees. */
+                    360 * 64);
+} else {
+       gint x1, y1, x2, y2;
+
+       x1 = unit2bufx(unitx1);
+       y1 = unit2bufy(unity1);
+       x2 = unit2bufx(unitx2);
+       y2 = unit2bufy(unity2);
+       /* Make sure this line could possibly be visible. */
+       if (!((x1 > buf_width_pixels && x2 > buf_width_pixels)
+             || (x1 < 0 && x2 < 0)
+             || (y1 > buf_height_pixels && y2 > buf_height_pixels)
+             || (y1 < 0 && y2 < 0)))
+               gdk_draw_line(_map_pixmap, gc_norm, x1, y1, x2, y2);
        }
 }
 
+void
+map_render_waypoint(guint x1, guint y1, GdkGC ** gc)
+{
+if ((x1 > buf_width_pixels) || (y1 > buf_height_pixels))
+       return;
+gdk_draw_arc(_map_pixmap, gc[1], FALSE,        x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, 360 * 64);
+}
+
 /**
  * Render all track data onto the _map_pixmap.  Note that this does not
  * clear the pixmap of previous track data (use map_force_redraw() for
@@ -778,34 +834,28 @@ map_render_segment(GdkGC * gc_norm, GdkGC * gc_alt, guint unitx1, guint unity1,
 void 
 map_render_path(Path * path, GdkGC ** gc)
 {
-       Point *curr;
-       WayPoint *wcurr;
-
-       /* gc is a pointer to the first GC to use (for plain points).  (gc + 1)
-        * is a pointer to the GC to use for waypoints, and (gc + 2) is a pointer
-        * to the GC to use for breaks. */
-
-       /* else there is a route to draw. */
-       for (curr = path->head, wcurr = path->whead; curr++ != path->tail;) {
-               /* Draw the line from (curr - 1) to (curr). */
-               map_render_segment(gc[0], gc[2],
-                                  curr[-1].unitx, curr[-1].unity, curr->unitx,
-                                  curr->unity);
-
-               /* Now, check if curr is a waypoint. */
-               if (wcurr && wcurr <= path->wtail && wcurr->point == curr) {
-                       guint x1 = unit2bufx(wcurr->point->unitx);
-                       guint y1 = unit2bufy(wcurr->point->unity);
-                       if ((x1 < BUF_WIDTH_PIXELS)
-                           && (y1 < BUF_HEIGHT_PIXELS)) {
-                               gdk_draw_arc(_map_pixmap, gc[1], FALSE, /* FALSE: not filled. */
-                                            x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0,   /* start at 0 degrees. */
-                                            360 * 64);
-                       }
-                       wcurr++;
-               }
+Point *curr;
+WayPoint *wcurr;
+
+/* gc is a pointer to the first GC to use (for plain points).  (gc + 1)
+ * is a pointer to the GC to use for waypoints, and (gc + 2) is a pointer
+ * to the GC to use for breaks. */
+
+/* else there is a route to draw. */
+for (curr = path->head, wcurr = path->whead; curr++ != path->tail;) {
+       /* Draw the line from (curr - 1) to (curr). */
+       map_render_segment(gc[0], gc[2], curr[-1].unitx, curr[-1].unity, curr->unitx, curr->unity);
+
+       /* Now, check if curr is a waypoint. */
+       if (wcurr && wcurr <= path->wtail && wcurr->point == curr) {
+               guint x1 = unit2bufx(wcurr->point->unitx);
+               guint y1 = unit2bufy(wcurr->point->unity);
+
+               map_render_waypoint(x1, y1, _gc[COLORABLE_TRACK_BREAK]);
+               wcurr++;
        }
 }
+}
 
 void 
 map_render_paths(void)
@@ -818,7 +868,7 @@ if ((_show_tracks & ROUTES_MASK) && _route.head != _route.tail) {
                guint x1 = unit2bufx(_next_way->point->unitx);
                guint y1 = unit2bufy(_next_way->point->unity);
 
-               if ((x1 < BUF_WIDTH_PIXELS) && (y1 < BUF_HEIGHT_PIXELS)) {
+               if ((x1 < buf_width_pixels) && (y1 < buf_height_pixels)) {
                        /* Draw the next waypoint as a break. */
                        gdk_draw_arc(_map_pixmap, _gc[COLORABLE_ROUTE_BREAK], FALSE,    /* FALSE: not filled. */
                             x1 - _draw_width, y1 - _draw_width, 4 * _draw_width, 4 * _draw_width, 0,   /* start at 0 degrees. */
index f15df0e23abaf04a9565aa222daed9629fd011b8..9a223b1981b0d30fef270e406f62dac49c3b813a 100644 (file)
--- a/src/map.h
+++ b/src/map.h
 #define TILE_SIZE_PIXELS (256)
 #define TILE_SIZE_P2 (8)
 
-#ifdef WITH_DEVICE_770
-#define BUF_WIDTH_TILES (4)
-#define BUF_HEIGHT_TILES (3)
-#define BUF_WIDTH_PIXELS (1024)
-#define BUF_HEIGHT_PIXELS (768)
-#else
-#define BUF_WIDTH_TILES (8)
-#define BUF_HEIGHT_TILES (8)
-#define BUF_WIDTH_PIXELS (2048)
-#define BUF_HEIGHT_PIXELS (2048)
-#endif
-
 #define WORLD_SIZE_UNITS (2 << (MAX_ZOOM + TILE_SIZE_P2))
 
 #define tile2grid(tile) ((tile) << 3)
@@ -214,8 +202,9 @@ void map_pan(gint delta_unitx, gint delta_unity);
 void map_move_mark(void);
 void map_set_mark(GpsData *gps);
 void map_render_data(void);
+gboolean map_render_tile(guint tilex, guint tiley, guint destx, guint desty, gboolean fast_fail);
 
-void map_render_tile(guint tilex, guint tiley, guint destx, guint desty, gboolean fast_fail);
+void map_render_waypoint(guint x1, guint y1, GdkGC ** gc);
 
 void map_center_unit(guint new_center_unitx, guint new_center_unity);
 void map_center_latlon(gdouble lat, gdouble lon);
index d401ada60394d0ffb3dc61658268287acc1c7e64..ad6317bb152796f27043f8b28507ed64e56df351 100644 (file)
@@ -202,23 +202,17 @@ track_insert_break(void)
 if (_track.tail->unity) {
        guint x1, y1;
 
-/* To mark a "waypoint" in a track, we'll add a (0, 0) point and then
- * another instance of the most recent track point. */
-MACRO_PATH_INCREMENT_TAIL(_track);
-*_track.tail=_point_null;
-MACRO_PATH_INCREMENT_TAIL(_track);
-*_track.tail=_track.tail[-2];
-
-/* Instead of calling map_render_paths(), we'll just add the waypoint ourselves. */
-x1 = unit2bufx(_track.tail->unitx);
-y1 = unit2bufy(_track.tail->unity);
-/* Make sure this circle will be visible. */
-if ((x1 < BUF_WIDTH_PIXELS) && ((unsigned)y1 < BUF_HEIGHT_PIXELS))
-       gdk_draw_arc(_map_pixmap, _gc[COLORABLE_TRACK_BREAK], FALSE,
-               x1 - _draw_width, y1 - _draw_width,
-               2 * _draw_width, 2 * _draw_width, 0,
-               360 * 64);
-       return TRUE;
+       /* To mark a "waypoint" in a track, we'll add a (0, 0) point and then
+        * another instance of the most recent track point. */
+       MACRO_PATH_INCREMENT_TAIL(_track);
+       *_track.tail=_point_null;
+       MACRO_PATH_INCREMENT_TAIL(_track);
+       *_track.tail=_track.tail[-2];
+
+       /* Instead of calling map_render_paths(), we'll just draw the waypoint ourselves. */
+       x1 = unit2bufx(_track.tail->unitx);
+       y1 = unit2bufy(_track.tail->unity);
+       map_render_waypoint(x1, y1, _gc[COLORABLE_TRACK_BREAK]);
 }
 return FALSE;
 }