[gnome-software/wip/rancell/paid] Allow multiple prices



commit 99eb7890432b703b23c0cc61e437457be88dbd60
Author: Robert Ancell <robert ancell canonical com>
Date:   Fri Apr 29 12:19:46 2016 +0200

    Allow multiple prices

 po/POTFILES.in         |    1 +
 src/Makefile.am        |    3 +
 src/gs-app-row.c       |   12 ++-
 src/gs-app.c           |   83 ++++---------------
 src/gs-app.h           |    8 +-
 src/gs-price.c         |  209 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/gs-price.h         |   50 ++++++++++++
 src/gs-shell-details.c |   14 ++-
 src/gs-utils.c         |   26 ------
 src/gs-utils.h         |    3 -
 10 files changed, 300 insertions(+), 109 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5235b00..cb5fc34 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -24,6 +24,7 @@ src/gs-main.c
 src/gs-page.c
 src/gs-plugin-loader.c
 src/gs-popular-tile.c
+src/gs-price.c
 src/gs-purchase-dialog.c
 [type: gettext/glade]src/gs-purchase-dialog.ui
 src/gs-review-dialog.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 16f5af6..7f15b02 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -89,6 +89,7 @@ noinst_PROGRAMS =                                     \
 gnome_software_cmd_SOURCES =                           \
        gs-app.c                                        \
        gs-app-list.c                                   \
+       gs-price.c                                      \
        gs-review.c                                     \
        gs-cmd.c                                        \
        gs-debug.c                                      \
@@ -158,6 +159,8 @@ gnome_software_SOURCES =                            \
        gs-plugin.c                                     \
        gs-plugin.h                                     \
        gs-plugin-private.h                             \
+       gs-price.c                                      \
+       gs-price.h                                      \
        gs-progress-button.c                            \
        gs-progress-button.h                            \
        gs-purchase-dialog.c                            \
diff --git a/src/gs-app-row.c b/src/gs-app-row.c
index d2201d6..8272063 100644
--- a/src/gs-app-row.c
+++ b/src/gs-app-row.c
@@ -30,6 +30,7 @@
 #include "gs-progress-button.h"
 #include "gs-utils.h"
 #include "gs-folders.h"
+#include "gs-price.h"
 
 typedef struct
 {
@@ -120,6 +121,7 @@ gs_app_row_refresh (GsAppRow *app_row)
        GsAppRowPrivate *priv = gs_app_row_get_instance_private (app_row);
        GtkStyleContext *context;
        GString *str = NULL;
+       GPtrArray *prices;
 
        if (priv->app == NULL)
                return;
@@ -217,10 +219,12 @@ gs_app_row_refresh (GsAppRow *app_row)
                                     gs_app_get_version_ui (priv->app));
        }
 
-       if (gs_app_get_price (priv->app) > 0) {
-               g_autofree gchar *price;
-               price = gs_format_price (gs_app_get_currency (priv->app), gs_app_get_price (priv->app));
-               gtk_label_set_label (GTK_LABEL (priv->price_label), price);
+       prices = gs_app_get_prices (priv->app);
+       if (prices->len > 0) {
+               GsPrice *price = g_ptr_array_index (prices, 0);
+               g_autofree gchar *text = NULL;
+               text = gs_price_to_string (price);
+               gtk_label_set_label (GTK_LABEL (priv->price_label), text);
                gtk_widget_show (priv->price_label);
        } else {
                gtk_widget_hide (priv->price_label);
diff --git a/src/gs-app.c b/src/gs-app.c
index 3a34345..638dd62 100644
--- a/src/gs-app.c
+++ b/src/gs-app.c
@@ -49,6 +49,7 @@
 
 #include "gs-app.h"
 #include "gs-utils.h"
+#include "gs-price.h"
 
 struct _GsApp
 {
@@ -85,8 +86,7 @@ struct _GsApp
        AsUrgencyKind            update_urgency;
        gchar                   *management_plugin;
        guint                    match_value;
-       guint                    price;
-       gchar                   *currency;
+       GPtrArray               *prices; /* of GsPrice */
        gboolean                 owned;
        gint                     rating;
        GArray                  *review_ratings;
@@ -120,8 +120,6 @@ enum {
        PROP_VERSION,
        PROP_SUMMARY,
        PROP_DESCRIPTION,
-       PROP_PRICE,
-       PROP_CURRENCY,
        PROP_OWNED,
        PROP_RATING,
        PROP_KIND,
@@ -310,10 +308,12 @@ gs_app_to_string (GsApp *app)
                gs_app_kv_lpad (str, "origin", app->origin);
        if (app->origin_ui != NULL && app->origin_ui[0] != '\0')
                gs_app_kv_lpad (str, "origin-ui", app->origin_ui);
-       if (app->price > 0) {
-               gs_app_kv_printf (str, "price", "%u", app->price);
-               if (app->currency != NULL)
-                       gs_app_kv_printf (str, "currency", "%s", app->currency);
+       for (i = 0; i < app->prices->len; i++) {
+               GsPrice *price = g_ptr_array_index (app->prices, i);
+               g_autofree gchar *key = NULL;
+               key = g_strdup_printf ("price-%02i", i);
+               gs_app_kv_printf (str, key, "%u %s",
+                                 gs_price_get_amount (price), gs_price_get_currency (price));
        }
        if (app->rating != -1)
                gs_app_kv_printf (str, "rating", "%i", app->rating);
@@ -1760,45 +1760,23 @@ gs_app_set_management_plugin (GsApp *app, const gchar *management_plugin)
 }
 
 /**
- * gs_app_get_price:
- */
-guint
-gs_app_get_price (GsApp *app)
-{
-       g_return_val_if_fail (GS_IS_APP (app), 0);
-       return app->price;
-}
-
-/**
- * gs_app_set_price:
- */
-void
-gs_app_set_price (GsApp *app, guint price)
-{
-       g_return_if_fail (GS_IS_APP (app));
-       app->price = price;
-       gs_app_queue_notify (app, "price");
-}
-
-/**
- * gs_app_get_currency:
+ * gs_app_get_prices:
  */
-const gchar *
-gs_app_get_currency (GsApp *app)
+GPtrArray *
+gs_app_get_prices (GsApp *app)
 {
        g_return_val_if_fail (GS_IS_APP (app), NULL);
-       return app->currency;
+       return app->prices;
 }
 
 /**
- * gs_app_set_currency:
+ * gs_app_add_price:
  */
 void
-gs_app_set_currency (GsApp *app, const gchar *currency)
+gs_app_add_price (GsApp *app, guint amount, const gchar *currency)
 {
        g_return_if_fail (GS_IS_APP (app));
-       app->currency = currency;
-       gs_app_queue_notify (app, "currency");
+       g_ptr_array_add (app->reviews, gs_price_new (amount, currency));
 }
 
 /**
@@ -2420,12 +2398,6 @@ gs_app_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *
        case PROP_DESCRIPTION:
                g_value_set_string (value, app->description);
                break;
-       case PROP_PRICE:
-               g_value_set_uint (value, app->price);
-               break;
-       case PROP_CURRENCY:
-               g_value_set_string (value, app->currency);
-               break;
        case PROP_OWNED:
                g_value_set_boolean (value, app->owned);
                break;
@@ -2483,12 +2455,6 @@ gs_app_set_property (GObject *object, guint prop_id, const GValue *value, GParam
                                        GS_APP_QUALITY_UNKNOWN,
                                        g_value_get_string (value));
                break;
-       case PROP_PRICE:
-               gs_app_set_price (app, g_value_get_uint (value));
-               break;
-       case PROP_CURRENCY:
-               gs_app_set_currency (app, g_value_get_string (value));
-               break;
        case PROP_OWNED:
                gs_app_set_owned (app, g_value_get_boolean (value));
                break;
@@ -2533,6 +2499,7 @@ gs_app_dispose (GObject *object)
        g_clear_pointer (&app->history, g_ptr_array_unref);
        g_clear_pointer (&app->related, g_ptr_array_unref);
        g_clear_pointer (&app->screenshots, g_ptr_array_unref);
+       g_clear_pointer (&app->prices, g_ptr_array_unref);
        g_clear_pointer (&app->reviews, g_ptr_array_unref);
 
        G_OBJECT_CLASS (gs_app_parent_class)->dispose (object);
@@ -2566,7 +2533,6 @@ gs_app_finalize (GObject *object)
        g_free (app->update_version_ui);
        g_free (app->update_details);
        g_free (app->management_plugin);
-       g_free (app->currency);
        g_hash_table_unref (app->metadata);
        g_hash_table_unref (app->addons_hash);
        g_hash_table_unref (app->related_hash);
@@ -2634,22 +2600,6 @@ gs_app_class_init (GsAppClass *klass)
        g_object_class_install_property (object_class, PROP_DESCRIPTION, pspec);
 
        /**
-        * GsApp:price:
-        */
-       pspec = g_param_spec_uint ("price", NULL, NULL,
-                                  0, G_MAXUINT, 0,
-                                  G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
-       g_object_class_install_property (object_class, PROP_PRICE, pspec);
-
-       /**
-        * GsApp:currency:
-        */
-       pspec = g_param_spec_string ("currency", NULL, NULL,
-                                    NULL,
-                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
-       g_object_class_install_property (object_class, PROP_CURRENCY, pspec);
-
-       /**
         * GsApp:owned:
         */
        pspec = g_param_spec_boolean ("owned", NULL, NULL,
@@ -2724,6 +2674,7 @@ gs_app_init (GsApp *app)
        app->related = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
        app->history = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
        app->screenshots = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+       app->prices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
        app->reviews = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
        app->metadata = g_hash_table_new_full (g_str_hash,
                                                g_str_equal,
diff --git a/src/gs-app.h b/src/gs-app.h
index d87d7cf..71452f4 100644
--- a/src/gs-app.h
+++ b/src/gs-app.h
@@ -195,11 +195,9 @@ const gchar        *gs_app_get_metadata_item       (GsApp          *app,
 void            gs_app_set_metadata            (GsApp          *app,
                                                 const gchar    *key,
                                                 const gchar    *value);
-guint           gs_app_get_price               (GsApp          *app);
-void            gs_app_set_price               (GsApp          *app,
-                                                guint           price);
-const gchar    *gs_app_get_currency            (GsApp          *app);
-void            gs_app_set_currency            (GsApp          *app,
+GPtrArray      *gs_app_get_prices              (GsApp          *app);
+void            gs_app_add_price               (GsApp          *app,
+                                                guint           amount,
                                                 const gchar    *currency);
 gboolean        gs_app_get_owned               (GsApp          *app);
 void            gs_app_set_owned               (GsApp          *app,
diff --git a/src/gs-price.c b/src/gs-price.c
new file mode 100644
index 0000000..f9bc392
--- /dev/null
+++ b/src/gs-price.c
@@ -0,0 +1,209 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Canonical Ltd.
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "gs-price.h"
+
+struct _GsPrice
+{
+       GObject                  parent_instance;
+
+       gint                     amount;
+       gchar                   *currency;
+};
+
+enum {
+       PROP_0,
+       PROP_AMOUNT,
+       PROP_CURRENCY,
+       PROP_LAST
+};
+
+G_DEFINE_TYPE (GsPrice, gs_price, G_TYPE_OBJECT)
+
+/**
+ * gs_price_get_amount:
+ */
+guint
+gs_price_get_amount (GsPrice *price)
+{
+       g_return_val_if_fail (GS_IS_PRICE (price), 0);
+       return price->amount;
+}
+
+/**
+ * gs_price_set_amount:
+ */
+void
+gs_price_set_amount (GsPrice *price, guint amount)
+{
+       g_return_if_fail (GS_IS_PRICE (price));
+       price->amount = amount;
+}
+
+/**
+ * gs_price_get_currency:
+ */
+const gchar *
+gs_price_get_currency (GsPrice *price)
+{
+       g_return_val_if_fail (GS_IS_PRICE (price), NULL);
+       return price->currency;
+}
+
+/**
+ * gs_price_set_currency:
+ */
+void
+gs_price_set_currency (GsPrice *price, const gchar *currency)
+{
+       g_return_if_fail (GS_IS_PRICE (price));
+       g_free (price->currency);
+       price->currency = g_strdup (currency);
+}
+
+/**
+ * gs_price_to_string:
+ */
+gchar *
+gs_price_to_string (GsPrice *price)
+{
+       g_return_val_if_fail (GS_IS_PRICE (price), NULL);
+  
+       if (g_strcmp0 (price->currency, "AUD") == 0) {
+               return g_strdup_printf (_("A$%u"), price->amount);
+       } else if (g_strcmp0 (price->currency, "CAD") == 0) {
+               return g_strdup_printf (_("C$%u"), price->amount);
+       } else if (g_strcmp0 (price->currency, "CNY") == 0) {
+               return g_strdup_printf (_("CN¥%u"), price->amount);
+       } else if (g_strcmp0 (price->currency, "EUR") == 0) {
+               return g_strdup_printf (_("€%u"), price->amount);
+       } else if (g_strcmp0 (price->currency, "GBP") == 0) {
+               return g_strdup_printf (_("£%u"), price->amount);
+       } else if (g_strcmp0 (price->currency, "JPY") == 0) {
+               return g_strdup_printf (_("¥%u"), price->amount);
+       } else if (g_strcmp0 (price->currency, "NZD") == 0) {
+               return g_strdup_printf (_("NZ$%u"), price->amount);
+       } else if (g_strcmp0 (price->currency, "RUB") == 0) {
+               return g_strdup_printf (_("₽%u"), price->amount);
+       } else if (g_strcmp0 (price->currency, "USD") == 0) {
+               return g_strdup_printf (_("US$%u"), price->amount);
+       } else {
+               return g_strdup_printf (_("%s %u"), price->currency, price->amount);
+       }
+}
+
+static void
+gs_price_get_property (GObject *object, guint prop_id,
+                       GValue *value, GParamSpec *pspec)
+{
+       GsPrice *price = GS_PRICE (object);
+
+       switch (prop_id) {
+       case PROP_AMOUNT:
+               g_value_set_uint (value, price->amount);
+               break;
+       case PROP_CURRENCY:
+               g_value_set_string (value, price->currency);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+gs_price_set_property (GObject *object, guint prop_id,
+                       const GValue *value, GParamSpec *pspec)
+{
+       GsPrice *price = GS_PRICE (object);
+
+       switch (prop_id) {
+       case PROP_AMOUNT:
+               gs_price_set_amount (price, g_value_get_uint (value));
+               break;
+       case PROP_CURRENCY:
+               gs_price_set_currency (price, g_value_get_string (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+gs_price_finalize (GObject *object)
+{
+       GsPrice *price = GS_PRICE (object);
+
+       g_free (price->currency);
+
+       G_OBJECT_CLASS (gs_price_parent_class)->finalize (object);
+}
+
+static void
+gs_price_class_init (GsPriceClass *klass)
+{
+       GParamSpec *pspec;
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       object_class->finalize = gs_price_finalize;
+       object_class->get_property = gs_price_get_property;
+       object_class->set_property = gs_price_set_property;
+
+       /**
+        * GsApp:amount:
+        */
+       pspec = g_param_spec_uint ("amount", NULL, NULL,
+                                 0, G_MAXUINT, 0,
+                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+       g_object_class_install_property (object_class, PROP_AMOUNT, pspec);
+
+       /**
+        * GsApp:currency:
+        */
+       pspec = g_param_spec_string ("currency", NULL, NULL,
+                                    NULL,
+                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+       g_object_class_install_property (object_class, PROP_CURRENCY, pspec);
+}
+
+static void
+gs_price_init (GsPrice *price)
+{
+}
+
+/**
+ * gs_price_new:
+ *
+ * Return value: a new #GsPrice object.
+ **/
+GsPrice *
+gs_price_new (guint amount, const gchar *currency)
+{
+       GsPrice *price;
+       price = g_object_new (GS_TYPE_PRICE, NULL);
+       return GS_PRICE (price);
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-price.h b/src/gs-price.h
new file mode 100644
index 0000000..a43a9cd
--- /dev/null
+++ b/src/gs-price.h
@@ -0,0 +1,50 @@
+ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Canonical Ltd.
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GS_PRICE_H
+#define __GS_PRICE_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_PRICE (gs_price_get_type ())
+
+G_DECLARE_FINAL_TYPE (GsPrice, gs_price, GS, PRICE, GObject)
+
+GsPrice                *gs_price_new                           (guint amount,
+                                                        const gchar *currency);
+
+guint           gs_price_get_amount                    (GsPrice        *price);
+void            gs_price_set_amount                    (GsPrice        *price,
+                                                        guint           amount);
+
+const gchar    *gs_price_get_currency                  (GsPrice        *price);
+void            gs_price_set_currency                  (GsPrice        *price,
+                                                        const gchar    *currency);
+
+gchar          *gs_price_to_string                     (GsPrice        *price);
+
+G_END_DECLS
+
+#endif /* __GS_PRICE_H */
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-shell-details.c b/src/gs-shell-details.c
index 2cbe276..6093a62 100644
--- a/src/gs-shell-details.c
+++ b/src/gs-shell-details.c
@@ -37,6 +37,7 @@
 #include "gs-review-histogram.h"
 #include "gs-review-dialog.h"
 #include "gs-review-row.h"
+#include "gs-price.h"
 
 static void gs_shell_details_refresh_all (GsShellDetails *self);
 
@@ -219,6 +220,7 @@ gs_shell_details_switch_to (GsPage *page, gboolean scroll_up)
        GtkWidget *widget;
        GtkStyleContext *sc;
        GtkAdjustment *adj;
+       GPtrArray *prices;
 
        if (gs_shell_get_mode (self->shell) != GS_SHELL_MODE_DETAILS) {
                g_warning ("Called switch_to(details) when in mode %s",
@@ -254,10 +256,12 @@ gs_shell_details_switch_to (GsPage *page, gboolean scroll_up)
                gtk_style_context_add_class (gtk_widget_get_style_context (self->button_install), 
"suggested-action");
                /* TRANSLATORS: button text in the header when an application
                 * can be installed */
-               if (gs_app_get_price (self->app) > 0) {
-                       g_autofree gchar *price = NULL;
-                       price = gs_format_price (gs_app_get_currency (self->app), gs_app_get_price 
(self->app));
-                       gtk_button_set_label (GTK_BUTTON (self->button_install), price);
+               prices = gs_app_get_prices (self->app);
+               if (prices->len > 0) {
+                       GsPrice *price = g_ptr_array_index (prices, 0);
+                       g_autofree gchar *text = NULL;
+                       text = gs_price_to_string (price);
+                       gtk_button_set_label (GTK_BUTTON (self->button_install), text);
                } else {
                        gtk_button_set_label (GTK_BUTTON (self->button_install), _("_Install"));
                }
@@ -1455,7 +1459,7 @@ gs_shell_details_app_install_button_cb (GtkWidget *widget, GsShellDetails *self)
        GList *l;
        g_autoptr(GList) addons = NULL;
 
-       if (gs_app_get_price (self->app) > 0 && !gs_app_get_owned (self->app)) {
+       if (gs_app_get_prices (self->app)->len > 0 && !gs_app_get_owned (self->app)) {
                gs_page_purchase_app (GS_PAGE (self), self->app);
                return;
        }
diff --git a/src/gs-utils.c b/src/gs-utils.c
index a027c8e..c6a94a9 100644
--- a/src/gs-utils.c
+++ b/src/gs-utils.c
@@ -898,30 +898,4 @@ gs_utils_widget_set_custom_css (GsApp *app, GtkWidget *widget, const gchar *meta
                                g_object_unref);
 }
 
-gchar *
-gs_format_price (const gchar *currency, guint price)
-{
-       if (strcmp (currency, "AUD") == 0) {
-               return g_strdup_printf (_("A$%u"), price);
-       } else if (strcmp (currency, "CAD") == 0) {
-               return g_strdup_printf (_("C$%u"), price);
-       } else if (strcmp (currency, "CNY") == 0) {
-               return g_strdup_printf (_("CN¥%u"), price);
-       } else if (strcmp (currency, "EUR") == 0) {
-               return g_strdup_printf (_("€%u"), price);
-       } else if (strcmp (currency, "GBP") == 0) {
-               return g_strdup_printf (_("£%u"), price);
-       } else if (strcmp (currency, "JPY") == 0) {
-               return g_strdup_printf (_("¥%u"), price);
-       } else if (strcmp (currency, "NZD") == 0) {
-               return g_strdup_printf (_("NZ$%u"), price);
-       } else if (strcmp (currency, "RUB") == 0) {
-               return g_strdup_printf (_("₽%u"), price);
-       } else if (strcmp (currency, "USD") == 0) {
-               return g_strdup_printf (_("US$%u"), price);
-       } else {
-               return g_strdup_printf (_("%s %u"), currency, price);
-       }
-}
-
 /* vim: set noexpandtab: */
diff --git a/src/gs-utils.h b/src/gs-utils.h
index 1143d16..e407bd0 100644
--- a/src/gs-utils.h
+++ b/src/gs-utils.h
@@ -73,9 +73,6 @@ void           gs_utils_widget_set_custom_css (GsApp          *app,
                                                 GtkWidget      *widget,
                                                 const gchar    *metadata_css);
 
-gchar          *gs_format_price                (const gchar    *currency,
-                                                guint           price);
-
 G_END_DECLS
 
 #endif /* __GS_UTILS_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]