From 9f128d951a3ab24341afbb677a2f1dd665b56548 Mon Sep 17 00:00:00 2001 From: Ettore Perazzoli Date: Sun, 13 Aug 2000 05:19:36 +0000 Subject: Add a kludgy and simple interface to the shell views to access the status bar, to report messages and progress. svn path=/trunk/; revision=4796 --- shell/ChangeLog | 37 +++++++ shell/Evolution-ShellView.idl | 18 ++++ shell/Evolution.idl | 1 + shell/Makefile.am | 3 + shell/e-shell-view.c | 188 +++++++++++++++++++++++++++++++---- shell/e-shell.c | 12 ++- shell/evolution-shell-view.c | 226 ++++++++++++++++++++++++++++++++++++++++++ shell/evolution-shell-view.h | 76 ++++++++++++++ 8 files changed, 540 insertions(+), 21 deletions(-) create mode 100644 shell/Evolution-ShellView.idl create mode 100644 shell/evolution-shell-view.c create mode 100644 shell/evolution-shell-view.h diff --git a/shell/ChangeLog b/shell/ChangeLog index b7e9b6fdcd..69bff1ac3d 100644 --- a/shell/ChangeLog +++ b/shell/ChangeLog @@ -1,3 +1,40 @@ +2000-08-13 Ettore Perazzoli + + * e-shell-view.c: New members `progress_bar_timeout_id', + `progress_bar_value' in `EShellViewPrivate'. + (init): Init them. + (destroy): If the timeout id is not zero, remove the associated + timeout. + (progress_bar_timeout_cb): New. + (start_progress_bar): New. + (stop_progress_bar): New. + (shell_view_interface_set_message_cb): If busy, start the progress + bar. Otherwise, stop it. + (shell_view_interface_unset_message_cb): Stop the progress bar. + + * e-shell-view.c (setup_widgets): Enable the progress bar in the + appbar. + + * e-shell-view.c (shell_view_interface_unset_message_cb): New + function, callback for the `EvolutionShellView::unset_message' + signal. + (shell_view_interface_set_message_cb): New function, callback for + the `EvolutionShellView::set_message' signal. + (setup_evolution_shell_view_interface): Connect these signals to a + newly created EvolutionShellView object, add ::add_interface this + object to the control's frame. + + * evolution-shell-view.c: New. + * evolution-shell-view.h: New. + + * Evolution-ShellView.idl: New interface. + +2000-08-10 Ettore Perazzoli + + * e-shell.c (ADDRESSBOOK_COMPONENT_ID): New constant; ID for the + executive summary component. + (setup_components): Activate the executive summary component. + 2000-08-10 Dan Winship * Evolution-ShellComponent.idl: add "in string evolution_homedir" diff --git a/shell/Evolution-ShellView.idl b/shell/Evolution-ShellView.idl new file mode 100644 index 0000000000..f0931dccdd --- /dev/null +++ b/shell/Evolution-ShellView.idl @@ -0,0 +1,18 @@ +/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Interface for the Evolution shell views. + * + * Authors: + * Ettore Perazzoli + * + * Copyright (C) 2000 Helix Code, Inc. + */ + +#include + +module Evolution { + interface ShellView : Bonobo::Unknown { + void set_message (in string message, in boolean busy); + void unset_message (); + }; +}; diff --git a/shell/Evolution.idl b/shell/Evolution.idl index a0eb944008..2463d23b10 100644 --- a/shell/Evolution.idl +++ b/shell/Evolution.idl @@ -13,4 +13,5 @@ #include #include #include +#include #include diff --git a/shell/Makefile.am b/shell/Makefile.am index 3d1ae7e096..e94b6fc4e1 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -23,6 +23,7 @@ IDLS = \ Evolution-Session.idl \ Evolution-Shell.idl \ Evolution-ShellComponent.idl \ + Evolution-ShellView.idl \ Evolution-Storage.idl IDL_GENERATED = \ @@ -52,6 +53,8 @@ libeshell_a_SOURCES = \ evolution-shell-component.h \ evolution-shell-component-client.c \ evolution-shell-component-client.h \ + evolution-shell-view.c \ + evolution-shell-view.h \ evolution-storage.c \ evolution-storage.h diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c index c1c03be756..de62a5a4bf 100644 --- a/shell/e-shell-view.c +++ b/shell/e-shell-view.c @@ -36,6 +36,8 @@ #include "e-util/e-util.h" #include "e-util/e-gui-utils.h" +#include "evolution-shell-view.h" + #include "e-shell-constants.h" #include "e-shell-folder-title-bar.h" #include "e-shell-utils.h" @@ -87,6 +89,12 @@ struct _EShellViewPrivate { /* Status of the shortcut and folder bars. */ EShellViewSubwindowMode shortcut_bar_mode; EShellViewSubwindowMode folder_bar_mode; + + /* Timeout ID for the progress bar. */ + int progress_bar_timeout_id; + + /* Status of the progress bar. */ + int progress_bar_value; }; enum { @@ -360,14 +368,22 @@ static void setup_widgets (EShellView *shell_view) { EShellViewPrivate *priv; + GtkWidget *progress_bar; priv = shell_view->priv; /* The application bar. */ - priv->appbar = gnome_appbar_new (FALSE, TRUE, GNOME_PREFERENCES_NEVER); + priv->appbar = gnome_appbar_new (TRUE, TRUE, GNOME_PREFERENCES_NEVER); gnome_app_set_statusbar (GNOME_APP (shell_view), priv->appbar); + /* The progress bar. */ + + progress_bar = GNOME_APPBAR (GNOME_APP (shell_view)->statusbar)->progress; + + gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (progress_bar), GTK_PROGRESS_LEFT_TO_RIGHT); + gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (progress_bar), GTK_PROGRESS_CONTINUOUS); + /* The shortcut bar. */ priv->shortcut_bar = e_shortcuts_new_view (e_shell_get_shortcuts (priv->shell)); @@ -486,6 +502,9 @@ destroy (GtkObject *object) g_free (priv->uri); + if (priv->progress_bar_timeout_id != 0) + gtk_timeout_remove (priv->progress_bar_timeout_id); + g_free (priv); (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); @@ -553,32 +572,142 @@ init (EShellView *shell_view) priv = g_new (EShellViewPrivate, 1); - priv->shell = NULL; - priv->uih = NULL; - priv->uri = NULL; + priv->shell = NULL; + priv->uih = NULL; + priv->uri = NULL; + + priv->appbar = NULL; + priv->hpaned = NULL; + priv->view_hpaned = NULL; + priv->contents = NULL; + priv->notebook = NULL; - priv->appbar = NULL; - priv->hpaned = NULL; - priv->view_hpaned = NULL; - priv->contents = NULL; - priv->notebook = NULL; + priv->storage_set_title_bar = NULL; + priv->storage_set_view = NULL; + priv->storage_set_view_box = NULL; + priv->shortcut_bar = NULL; - priv->storage_set_title_bar = NULL; - priv->storage_set_view = NULL; - priv->storage_set_view_box = NULL; - priv->shortcut_bar = NULL; + priv->shortcut_bar_mode = E_SHELL_VIEW_SUBWINDOW_HIDDEN; + priv->folder_bar_mode = E_SHELL_VIEW_SUBWINDOW_HIDDEN; - priv->shortcut_bar_mode = E_SHELL_VIEW_SUBWINDOW_HIDDEN; - priv->folder_bar_mode = E_SHELL_VIEW_SUBWINDOW_HIDDEN; + priv->hpaned_position = 0; + priv->view_hpaned_position = 0; - priv->hpaned_position = 0; - priv->view_hpaned_position = 0; + priv->uri_to_control = g_hash_table_new (g_str_hash, g_str_equal); - priv->uri_to_control = g_hash_table_new (g_str_hash, g_str_equal); + priv->progress_bar_timeout_id = 0; + priv->progress_bar_value = 0; shell_view->priv = priv; } + +/* Progress bar handling. */ + +#define PROGRESS_BAR_TIMEOUT 80 + +static int +progress_bar_timeout_cb (void *data) +{ + EShellView *shell_view; + EShellViewPrivate *priv; + GtkWidget *progress_bar; + + shell_view = E_SHELL_VIEW (data); + priv = shell_view->priv; + progress_bar = GNOME_APPBAR (GNOME_APP (shell_view)->statusbar)->progress; + + priv->progress_bar_value = ! priv->progress_bar_value; + gtk_progress_set_value (GTK_PROGRESS (progress_bar), priv->progress_bar_value); + + return TRUE; +} + +static void +start_progress_bar (EShellView *shell_view) +{ + EShellViewPrivate *priv; + GtkWidget *progress_bar; + + priv = shell_view->priv; + progress_bar = GNOME_APPBAR (GNOME_APP (shell_view)->statusbar)->progress; + + if (priv->progress_bar_timeout_id != 0) + return; + + priv->progress_bar_timeout_id = gtk_timeout_add (PROGRESS_BAR_TIMEOUT, + progress_bar_timeout_cb, + shell_view); + + gtk_progress_set_activity_mode (GTK_PROGRESS (progress_bar), TRUE); + gtk_progress_set_value (GTK_PROGRESS (progress_bar), priv->progress_bar_value); +} + +static void +stop_progress_bar (EShellView *shell_view) +{ + EShellViewPrivate *priv; + GtkWidget *progress_bar; + + priv = shell_view->priv; + progress_bar = GNOME_APPBAR (GNOME_APP (shell_view)->statusbar)->progress; + + if (priv->progress_bar_timeout_id != 0) { + gtk_timeout_remove (priv->progress_bar_timeout_id); + priv->progress_bar_timeout_id = 0; + } + + gtk_progress_set_activity_mode (GTK_PROGRESS (progress_bar), FALSE); + gtk_progress_set_value (GTK_PROGRESS (progress_bar), 0); +} + + +/* EvolutionShellView interface callbacks. */ + +static void +shell_view_interface_set_message_cb (EvolutionShellView *shell_view, + const char *message, + gboolean busy, + void *data) +{ + GnomeApp *app; + GnomeAppBar *app_bar; + + g_print ("%s\n", __FUNCTION__); + + app = GNOME_APP (data); + app_bar = GNOME_APPBAR (app->statusbar); + + gtk_progress_set_value (GTK_PROGRESS (app_bar->progress), 1.0); + + if (message != NULL) + gnome_appbar_set_status (app_bar, message); + else + gnome_appbar_set_status (app_bar, ""); + + if (busy) + start_progress_bar (E_SHELL_VIEW (data)); + else + stop_progress_bar (E_SHELL_VIEW (data)); +} + +static void +shell_view_interface_unset_message_cb (EvolutionShellView *shell_view, + void *data) +{ + GnomeApp *app; + GnomeAppBar *app_bar; + + g_print ("%s\n", __FUNCTION__); + + app = GNOME_APP (data); + app_bar = GNOME_APPBAR (app->statusbar); + + gnome_appbar_set_status (app_bar, ""); + + stop_progress_bar (E_SHELL_VIEW (data)); +} + void e_shell_view_construct (EShellView *shell_view, @@ -794,6 +923,27 @@ set_current_notebook_page (EShellView *shell_view, bonobo_control_frame_control_activate (control_frame); } +static void +setup_evolution_shell_view_interface (EShellView *shell_view, + GtkWidget *control) +{ + BonoboControlFrame *control_frame; + EvolutionShellView *shell_view_interface; + + control_frame = bonobo_widget_get_control_frame (BONOBO_WIDGET (control)); + shell_view_interface = evolution_shell_view_new (); + + gtk_signal_connect_while_alive (GTK_OBJECT (shell_view_interface), "set_message", + GTK_SIGNAL_FUNC (shell_view_interface_set_message_cb), + shell_view, GTK_OBJECT (shell_view)); + gtk_signal_connect_while_alive (GTK_OBJECT (shell_view_interface), "unset_message", + GTK_SIGNAL_FUNC (shell_view_interface_unset_message_cb), + shell_view, GTK_OBJECT (shell_view)); + + bonobo_object_add_interface (BONOBO_OBJECT (control_frame), + BONOBO_OBJECT (shell_view_interface)); +} + /* Create a new view for @uri with @control. It assumes a view for @uri does not exist yet. */ static GtkWidget * get_control_for_uri (EShellView *shell_view, @@ -856,6 +1006,8 @@ get_control_for_uri (EShellView *shell_view, corba_uih = bonobo_object_corba_objref (BONOBO_OBJECT (priv->uih)); control = bonobo_widget_new_control_from_objref (corba_control, corba_uih); + setup_evolution_shell_view_interface (shell_view, control); + return control; } diff --git a/shell/e-shell.c b/shell/e-shell.c index 056ab0923c..ab4277b992 100644 --- a/shell/e-shell.c +++ b/shell/e-shell.c @@ -65,12 +65,15 @@ struct _EShellPrivate { /* Constants. */ +/* FIXME: We need a component repository instead. */ + #define SHORTCUTS_FILE_NAME "shortcuts.xml" #define LOCAL_STORAGE_DIRECTORY "local" -#define MAIL_COMPONENT_ID "OAFIID:evolution-shell-component:evolution-mail:d3cb3ed6-a654-4337-8aa0-f443751d6d1b" -#define CALENDAR_COMPONENT_ID "OAFIID:evolution-shell-component:evolution-calendar:2eb9eb63-d305-4918-9c35-faae5db19e51" -#define ADDRESSBOOK_COMPONENT_ID "OAFIID:evolution-shell-component:addressbook:b7a26547-7014-4bb5-98ab-2bcac2bb55ca" +#define MAIL_COMPONENT_ID "OAFIID:evolution-shell-component:evolution-mail:d3cb3ed6-a654-4337-8aa0-f443751d6d1b" +#define CALENDAR_COMPONENT_ID "OAFIID:evolution-shell-component:evolution-calendar:2eb9eb63-d305-4918-9c35-faae5db19e51" +#define ADDRESSBOOK_COMPONENT_ID "OAFIID:evolution-shell-component:addressbook:b7a26547-7014-4bb5-98ab-2bcac2bb55ca" +#define EXECUTIVE_SUMMARY_COMPONENT_ID "OAFIID:evolution-shell-component:evolution-executive-summary:785be7bc-2ed2-4c83-96f3-d6ec8015a5b2" enum { @@ -325,6 +328,9 @@ setup_components (EShell *shell) if (! e_component_registry_register_component (priv->component_registry, ADDRESSBOOK_COMPONENT_ID)) g_warning ("Cannot activate addressbook component -- %s", ADDRESSBOOK_COMPONENT_ID); + + if (! e_component_registry_register_component (priv->component_registry, EXECUTIVE_SUMMARY_COMPONENT_ID)) + g_warning ("Cannot activate executive summary component -- %s", EXECUTIVE_SUMMARY_COMPONENT_ID); } diff --git a/shell/evolution-shell-view.c b/shell/evolution-shell-view.c new file mode 100644 index 0000000000..8ace962f1b --- /dev/null +++ b/shell/evolution-shell-view.c @@ -0,0 +1,226 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* evolution-shell-view.c + * + * Copyright (C) 2000 Helix Code, Inc. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Ettore Perazzoli + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "e-util/e-util.h" + +#include "evolution-shell-view.h" + + +#define PARENT_TYPE bonobo_object_get_type () +static BonoboObjectClass *parent_class = NULL; + +struct _EvolutionShellViewPrivate { + int dummy; +}; + +enum { + SET_MESSAGE, + UNSET_MESSAGE, + LAST_SIGNAL +}; +static int signals[LAST_SIGNAL] = { 0 }; + + +/* CORBA interface implementation. */ + +static POA_Evolution_ShellView__vepv ShellView_vepv; + +static POA_Evolution_ShellView * +create_servant (void) +{ + POA_Evolution_ShellView *servant; + CORBA_Environment ev; + + servant = (POA_Evolution_ShellView *) g_new0 (BonoboObjectServant, 1); + servant->vepv = &ShellView_vepv; + CORBA_exception_init (&ev); + + POA_Evolution_ShellView__init ((PortableServer_Servant) servant, &ev); + if (ev._major != CORBA_NO_EXCEPTION) { + g_free (servant); + CORBA_exception_free (&ev); + return NULL; + } + + CORBA_exception_free (&ev); + + return servant; +} + +static void +impl_ShellView_set_message (PortableServer_Servant servant, + const CORBA_char *message, + const CORBA_boolean busy, + CORBA_Environment *ev) +{ + BonoboObject *bonobo_object; + + bonobo_object = bonobo_object_from_servant (servant); + gtk_signal_emit (GTK_OBJECT (bonobo_object), signals[SET_MESSAGE], message, busy); +} + +static void +impl_ShellView_unset_message (PortableServer_Servant servant, + CORBA_Environment *ev) +{ + BonoboObject *bonobo_object; + + bonobo_object = bonobo_object_from_servant (servant); + gtk_signal_emit (GTK_OBJECT (bonobo_object), signals[UNSET_MESSAGE]); +} + + +/* GtkObject methods. */ +static void +destroy (GtkObject *object) +{ + EvolutionShellView *shell_view; + EvolutionShellViewPrivate *priv; + + shell_view = EVOLUTION_SHELL_VIEW (object); + priv = shell_view->priv; + + g_free (priv); +} + + +static void +corba_class_init (void) +{ + POA_Evolution_ShellView__vepv *vepv; + POA_Evolution_ShellView__epv *epv; + PortableServer_ServantBase__epv *base_epv; + + base_epv = g_new0 (PortableServer_ServantBase__epv, 1); + base_epv->_private = NULL; + base_epv->finalize = NULL; + base_epv->default_POA = NULL; + + epv = g_new0 (POA_Evolution_ShellView__epv, 1); + epv->set_message = impl_ShellView_set_message; + epv->unset_message = impl_ShellView_unset_message; + + vepv = &ShellView_vepv; + vepv->_base_epv = base_epv; + vepv->Bonobo_Unknown_epv = bonobo_object_get_epv (); + vepv->Evolution_ShellView_epv = epv; +} + +static void +class_init (EvolutionShellViewClass *klass) +{ + GtkObjectClass *object_class; + + object_class = GTK_OBJECT_CLASS (klass); + object_class->destroy = destroy; + + signals[SET_MESSAGE] + = gtk_signal_new ("set_message", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (EvolutionShellViewClass, set_message), + gtk_marshal_NONE__POINTER_INT, + GTK_TYPE_NONE, 2, + GTK_TYPE_STRING, + GTK_TYPE_BOOL); + + signals[UNSET_MESSAGE] + = gtk_signal_new ("unset_message", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (EvolutionShellViewClass, unset_message), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); + + parent_class = gtk_type_class (bonobo_object_get_type ()); + + corba_class_init (); +} + +static void +init (EvolutionShellView *shell_view) +{ + EvolutionShellViewPrivate *priv; + + priv = g_new (EvolutionShellViewPrivate, 1); + priv->dummy = 0; + + shell_view->priv = priv; +} + + +/** + * evolution_shell_view_construct: + * @shell_view: + * @corba_object: + * + * Construct @shell_view with the specified @corba_object. + **/ +void +evolution_shell_view_construct (EvolutionShellView *shell_view, + Evolution_ShellView corba_object) +{ + g_return_if_fail (shell_view != NULL); + g_return_if_fail (EVOLUTION_IS_SHELL_VIEW (shell_view)); + + bonobo_object_construct (BONOBO_OBJECT (shell_view), corba_object); +} + +/** + * evolution_shell_view_new: + * + * Create a new EvolutionShellView object. + * + * Return value: The new EvolutionShellView object. + **/ +EvolutionShellView * +evolution_shell_view_new (void) +{ + POA_Evolution_ShellView *servant; + Evolution_ShellView corba_object; + EvolutionShellView *new; + + servant = create_servant (); + if (servant == NULL) + return NULL; + + new = gtk_type_new (evolution_shell_view_get_type ()); + + corba_object = bonobo_object_activate_servant (BONOBO_OBJECT (new), servant); + + evolution_shell_view_construct (new, corba_object); + + return new; +} + + +E_MAKE_TYPE (evolution_shell_view, "EvolutionShellView", EvolutionShellView, class_init, init, PARENT_TYPE) diff --git a/shell/evolution-shell-view.h b/shell/evolution-shell-view.h new file mode 100644 index 0000000000..e12e8be2e1 --- /dev/null +++ b/shell/evolution-shell-view.h @@ -0,0 +1,76 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* evolution-shell-view.h + * + * Copyright (C) 2000 Helix Code, Inc. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Ettore Perazzoli + */ + +#ifndef __EVOLUTION_SHELL_VIEW_H__ +#define __EVOLUTION_SHELL_VIEW_H__ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "Evolution.h" + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +#define EVOLUTION_TYPE_SHELL_VIEW (evolution_shell_view_get_type ()) +#define EVOLUTION_SHELL_VIEW(obj) (GTK_CHECK_CAST ((obj), EVOLUTION_TYPE_SHELL_VIEW, EvolutionShellView)) +#define EVOLUTION_SHELL_VIEW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EVOLUTION_TYPE_SHELL_VIEW, EvolutionShellViewClass)) +#define EVOLUTION_IS_SHELL_VIEW(obj) (GTK_CHECK_TYPE ((obj), EVOLUTION_TYPE_SHELL_VIEW)) +#define EVOLUTION_IS_SHELL_VIEW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), EVOLUTION_TYPE_SHELL_VIEW)) + + +typedef struct _EvolutionShellView EvolutionShellView; +typedef struct _EvolutionShellViewPrivate EvolutionShellViewPrivate; +typedef struct _EvolutionShellViewClass EvolutionShellViewClass; + +struct _EvolutionShellView { + BonoboObject parent; + + EvolutionShellViewPrivate *priv; +}; + +struct _EvolutionShellViewClass { + BonoboObjectClass parent_class; + + /* Signals. */ + + void (* set_message) (EvolutionShellView *shell_view, const char *message, gboolean busy); + void (* unset_message) (EvolutionShellView *shell_view); +}; + + +GtkType evolution_shell_view_get_type (void); +void evolution_shell_view_construct (EvolutionShellView *shell_view, + Evolution_ShellView corba_object); +EvolutionShellView *evolution_shell_view_new (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EVOLUTION_SHELL_VIEW_H__ */ -- cgit v1.2.3