[yelp/yelp-3-0] [src/yelp.c] Basic DBus-enabled libyelp-based Yelp shell



commit 258d9bcc9c7e41cf53cef3c915bce2e1cd010cb3
Author: Shaun McCance <shaunm gnome org>
Date:   Wed Mar 10 23:22:23 2010 -0600

    [src/yelp.c] Basic DBus-enabled libyelp-based Yelp shell
    
    Nothing shiny yet.  Just managing the application API with DBus and
    getting basic windows loaded using YelpView.  Trying to keep it very
    simple, and with as little as possible done at startup.

 autogen.sh             |    2 +-
 configure.in           |    4 +-
 src/Makefile.am        |  132 +++++++----------------
 src/yelp-application.c |  270 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/yelp-application.h |   58 ++++++++++
 src/yelp-dbus.xml      |   10 ++
 src/yelp.c             |   49 +++++++++
 7 files changed, 430 insertions(+), 95 deletions(-)
---
diff --git a/autogen.sh b/autogen.sh
index 13db1cc..0cc89c3 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -9,7 +9,7 @@ PKG_NAME=Yelp
 REQUIRED_AUTOMAKE_VERSION=1.9
 export REQUIRED_AUTOMAKE_VERSION
 
-if ! test -f $srcdir/src/yelp-main.c; then
+if ! test -f $srcdir/src/yelp.c; then
   echo "**Error**: Directory '$srcdir' does not look like the yelp source directory"
   exit 1
 fi
diff --git a/configure.in b/configure.in
index cf58ecf..b119a2c 100644
--- a/configure.in
+++ b/configure.in
@@ -51,9 +51,7 @@ AM_GLIB_DEFINE_LOCALEDIR([GNOMELOCALEDIR])
 PKG_CHECK_MODULES(YELP,
 [
 	gio-2.0
-	gio-2.0
 	gio-unix-2.0
-	yelp-xsl
 	gtk+-unix-print-2.0
 	gtk+-2.0 >= 2.16.0
 	libxml-2.0 >= 2.6.5
@@ -62,7 +60,9 @@ PKG_CHECK_MODULES(YELP,
 	libstartup-notification-1.0 >= 0.8
 	dbus-glib-1
 	rarian >= 0.7.0
+	unique-1.0
 	webkit-1.0 >= 1.1.15
+	yelp-xsl
 ])
 
 AC_SUBST([YELP_CFLAGS])
diff --git a/src/Makefile.am b/src/Makefile.am
index 5cc96de..251e2cb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,30 +1,33 @@
 bin_PROGRAMS = yelp
 
-yelp_SOURCES =							\
-	yelp-base.c		yelp-base.h			\
-	yelp-bookmarks.c 	yelp-bookmarks.h		\
-	yelp-error.c		yelp-error.h			\
-	yelp-html.c		yelp-html.h			\
-	yelp-io-channel.c	yelp-io-channel.h		\
-	yelp-settings.c		yelp-settings.h			\
-	yelp-utils.c		yelp-utils.h			\
-	yelp-window.c 		yelp-window.h			\
-	yelp-marshal.c		yelp-marshal.h			\
-	yelp-main.c						\
-	yelp-page.c		yelp-page.h			\
-	yelp-transform.c	yelp-transform.h		\
-	yelp-document.h		yelp-document.c			\
-	yelp-toc.h		yelp-toc.c			\
-	yelp-docbook.h		yelp-docbook.c			\
-	yelp-db-print.c		yelp-db-print.h			\
-	yelp-mallard.h		yelp-mallard.c			\
-	yelp-man-parser.c 	yelp-man-parser.h		\
-	yelp-man.c 		yelp-man.h			\
-	yelp-info.c 		yelp-info.h			\
-	yelp-info-parser.c 	yelp-info-parser.h		\
-	gtkentryaction.c	gtkentryaction.h		\
-	yelp-search.c		yelp-search.h			\
-	yelp-search-parser.c 	yelp-search-parser.h
+yelp_SOURCES =						\
+	yelp-application.c	yelp-application.h	\
+	yelp.c
+
+#	yelp-base.c		yelp-base.h			\
+#	yelp-bookmarks.c 	yelp-bookmarks.h		\
+#	yelp-error.c		yelp-error.h			\
+#	yelp-html.c		yelp-html.h			\
+#	yelp-io-channel.c	yelp-io-channel.h		\
+#	yelp-settings.c		yelp-settings.h			\
+#	yelp-utils.c		yelp-utils.h			\
+#	yelp-window.c 		yelp-window.h			\
+#	yelp-marshal.c		yelp-marshal.h			\
+#	yelp-main.c						\
+#	yelp-page.c		yelp-page.h			\
+#	yelp-transform.c	yelp-transform.h		\
+#	yelp-document.h		yelp-document.c			\
+#	yelp-toc.h		yelp-toc.c			\
+#	yelp-docbook.h		yelp-docbook.c			\
+#	yelp-db-print.c		yelp-db-print.h			\
+#	yelp-mallard.h		yelp-mallard.c			\
+#	yelp-man-parser.c 	yelp-man-parser.h		\
+#	yelp-man.c 		yelp-man.h			\
+#	yelp-info.c 		yelp-info.h			\
+#	yelp-info-parser.c 	yelp-info-parser.h		\
+#	gtkentryaction.c	gtkentryaction.h		\
+#	yelp-search.c		yelp-search.h			\
+#	yelp-search-parser.c 	yelp-search-parser.h
 
 
 YELP_DEFINES =								\
@@ -81,76 +84,19 @@ yelp_SOURCES += eggsmclient-osx.c
 endif
 endif
 
-check_PROGRAMS =		\
-	test-document		\
-	test-man-parser		\
-	test-page		\
-	test-transform		\
-	test-resolver
-
-test_document_SOURCES =					\
-	yelp-debug.c		yelp-debug.h		\
-	yelp-docbook.c		yelp-docbook.h		\
-	yelp-document.c		yelp-document.h		\
-	yelp-error.c		yelp-error.h		\
-	yelp-io-channel.c	yelp-io-channel.h	\
-	yelp-mallard.c		yelp-mallard.h		\
-	yelp-man.c		yelp-man.h		\
-	yelp-man-parser.c	yelp-man-parser.h	\
-	yelp-page.c		yelp-page.h		\
-	yelp-toc.c		yelp-toc.h		\
-	yelp-transform.c	yelp-transform.h	\
-	test-document.c
-test_document_CFLAGS = $(YELP_CFLAGS) $(AM_CFLAGS) $(YELP_DEFINES)
-test_document_LDADD = $(YELP_LIBS) $(Z_LIBS) $(BZ_LIBS) $(LZMADEC_LIBS)
-test_document_LDFLAGS = $(AM_LDFLAGS)
-
-test_man_parser_SOURCES =					\
-	yelp-debug.c		yelp-debug.h			\
-	yelp-error.c		yelp-error.h			\
-	yelp-io-channel.c	yelp-io-channel.h		\
-	yelp-man-parser.c	yelp-man-parser.h		\
-	test-man-parser.c
-test_man_parser_CPPFLAGS = $(YELP_DEFINES) $(AM_CPPFLAGS)
-test_man_parser_CFLAGS = $(YELP_CFLAGS) $(AM_CFLAGS)
-test_man_parser_LDADD = $(YELP_LIBS) $(Z_LIBS) $(BZ_LIBS) $(LZMADEC_LIBS)
-test_man_parser_LDFLAGS = $(AM_LDFLAGS)
-
-test_page_SOURCES =					\
-	yelp-debug.c		yelp-debug.h		\
-	yelp-document.c		yelp-document.h		\
-	yelp-error.c		yelp-error.h		\
-	yelp-page.c		yelp-page.h		\
-	test-page.c
-test_page_CFLAGS = $(YELP_CFLAGS) $(AM_CFLAGS) $(YELP_DEFINES)
-test_page_LDADD = $(YELP_LIBS)
-test_page_LDFLAGS = $(AM_LDFLAGS)
-
-test_transform_SOURCES =				\
-	yelp-debug.c		yelp-debug.h		\
-	yelp-error.c		yelp-error.h		\
-	yelp-transform.c	yelp-transform.h	\
-	test-transform.c
-test_transform_CFLAGS = $(YELP_CFLAGS) $(AM_CFLAGS) $(YELP_DEFINES)
-test_transform_LDADD = $(YELP_LIBS)
-test_transform_LDFLAGS = $(AM_LDFLAGS)
-
-test_resolver_SOURCES =				\
-	yelp-debug.c		yelp-debug.h		\
-	yelp-error.c		yelp-error.h		\
-	yelp-utils.c		yelp-utils.h		\
-	test-resolver.c
-test_resolver_CFLAGS = $(YELP_CFLAGS) $(AM_CFLAGS) $(YELP_DEFINES)
-test_resolver_LDADD = $(YELP_LIBS)
-test_resolver_LDFLAGS = $(AM_LDFLAGS)
-
- INTLTOOL_SERVER_RULE@
-
-BUILT_SOURCES = yelp-marshal.h stamp-yelp-marshal.h yelp-marshal.c server-bindings.h \
-		client-bindings.h
+BUILT_SOURCES =			\
+	yelp-dbus.h		\
+	yelp-marshal.h		\
+	stamp-yelp-marshal.h	\
+	yelp-marshal.c		\
+	server-bindings.h	\
+	client-bindings.h
 
 noinst_HEADERS = $(BUILT_SOURCES)
 
+yelp-dbus.h: yelp-dbus.xml
+	dbus-binding-tool --prefix=yelp --mode=glib-server $<> $@
+
 server-bindings.h:  yelp-infos.xml
 	dbus-binding-tool --prefix=server_object --mode=glib-server $< > $@
 
@@ -179,6 +125,8 @@ MAINTAINERCLEANFILES = $(BUILT_SOURCES)
 
 EXTRA_DIST = yelp-marshal.list yelp-infos.xml yelp-print.c yelp-print.h
 
+
+
 install-exec-hook:
 	rm -f $(DESTDIR)$(bindir)/gnome-help && \
 	$(LN_S) yelp $(DESTDIR)$(bindir)/gnome-help
diff --git a/src/yelp-application.c b/src/yelp-application.c
new file mode 100644
index 0000000..46ccd72
--- /dev/null
+++ b/src/yelp-application.c
@@ -0,0 +1,270 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2010 Shaun McCance <shaunm gnome org>
+ *
+ * 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: Shaun McCance <shaunm gnome org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <dbus/dbus-glib-bindings.h>
+#include <dbus/dbus-glib.h>
+#include <gtk/gtk.h>
+
+#include "yelp-application.h"
+#include "yelp-dbus.h"
+#include "yelp-view.h"
+
+typedef struct _YelpApplicationLoad YelpApplicationLoad;
+struct _YelpApplicationLoad {
+    YelpApplication *app;
+    guint timestamp;
+};
+
+static void          yelp_application_init             (YelpApplication       *app);
+static void          yelp_application_class_init       (YelpApplicationClass  *klass);
+static void          yelp_application_dispose          (GObject               *object);
+static void          yelp_application_finalize         (GObject               *object);
+
+static GtkWidget *   application_new_window            (YelpApplication       *app);
+static void          application_uri_resolved          (YelpUri               *uri,
+                                                        YelpApplicationLoad   *data);
+
+G_DEFINE_TYPE (YelpApplication, yelp_application, G_TYPE_OBJECT);
+#define GET_PRIV(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_APPLICATION, YelpApplicationPrivate))
+
+typedef struct _YelpApplicationPrivate YelpApplicationPrivate;
+struct _YelpApplicationPrivate {
+    DBusGConnection *connection;
+
+    GSList *windows;
+
+    GHashTable *windows_by_document;
+};
+
+static void
+yelp_application_init (YelpApplication *app)
+{
+    YelpApplicationPrivate *priv = GET_PRIV (app);
+
+    priv->windows_by_document = g_hash_table_new_full (g_str_hash,
+                                                       g_str_equal,
+                                                       g_free,
+                                                       NULL);
+}
+
+static void
+yelp_application_class_init (YelpApplicationClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->dispose = yelp_application_dispose;
+    object_class->finalize = yelp_application_finalize;
+
+    dbus_g_object_type_install_info (YELP_TYPE_APPLICATION,
+                                     &dbus_glib_yelp_object_info);
+
+    g_type_class_add_private (klass, sizeof (YelpApplicationPrivate));
+}
+
+static void
+yelp_application_dispose (GObject *object)
+{
+    YelpApplicationPrivate *priv = GET_PRIV (object);
+
+    g_object_unref (priv->connection);
+
+    g_hash_table_destroy (priv->windows_by_document);
+
+    G_OBJECT_CLASS (yelp_application_parent_class)->dispose (object);
+}
+
+static void
+yelp_application_finalize (GObject *object)
+{
+    G_OBJECT_CLASS (yelp_application_parent_class)->finalize (object);
+}
+
+
+/******************************************************************************/
+
+YelpApplication *
+yelp_application_new (void)
+{
+    YelpApplication *app;
+
+    app = (YelpApplication *) g_object_new (YELP_TYPE_APPLICATION, NULL);
+
+    return app;
+}
+
+gint
+yelp_application_run (YelpApplication  *app,
+                      GOptionContext   *context,
+                      gint              argc,
+                      gchar           **argv)
+{
+    GError *error = NULL;
+    DBusGProxy *proxy;
+    guint request;
+    YelpApplicationPrivate *priv = GET_PRIV (app);
+    gchar *uri;
+
+    priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+    if (priv->connection == NULL) {
+        g_warning ("Unable to connect to dbus: %s", error->message);
+        g_error_free (error);
+        return 1;
+    }
+
+    /* FIXME: canonicalize relative URI */
+    if (argc > 1)
+        uri = argv[1];
+    else
+        uri = "ghelp:user-guide";
+
+    proxy = dbus_g_proxy_new_for_name (priv->connection,
+                                       DBUS_SERVICE_DBUS,
+                                       DBUS_PATH_DBUS,
+                                       DBUS_INTERFACE_DBUS);
+
+    if (!org_freedesktop_DBus_request_name (proxy,
+                                            "org.gnome.Yelp",
+                                            0, &request,
+                                            &error)) {
+        g_warning ("Unable to register service: %s", error->message);
+        g_error_free (error);
+        g_object_unref (proxy);
+        return 1;
+    }
+
+    g_object_unref (proxy);
+
+    if (request == DBUS_REQUEST_NAME_REPLY_EXISTS ||
+        request == DBUS_REQUEST_NAME_REPLY_IN_QUEUE) {
+        gchar *newuri;
+
+        newuri = g_strdup (uri);
+
+        proxy = dbus_g_proxy_new_for_name (priv->connection,
+                                           "org.gnome.Yelp",
+                                           "/org/gnome/Yelp",
+                                           "org.gnome.Yelp");
+        if (!dbus_g_proxy_call (proxy, "LoadUri", &error,
+                                G_TYPE_STRING, newuri,
+                                G_TYPE_UINT, GDK_CURRENT_TIME,
+                                G_TYPE_INVALID, G_TYPE_INVALID)) {
+            g_warning ("Unable to notify existing process: %s\n", error->message);
+            g_error_free (error);
+        }
+
+        g_free (newuri);
+        g_object_unref (proxy);
+        return 1;
+    }
+
+    dbus_g_connection_register_g_object (priv->connection,
+                                         "/org/gnome/Yelp",
+                                         G_OBJECT (app));
+
+    yelp_application_load_uri (app, uri, GDK_CURRENT_TIME, NULL);
+
+    gtk_main ();
+
+    return 0;
+}
+
+gboolean
+yelp_application_load_uri (YelpApplication  *app,
+                           const gchar      *uri,
+                           guint             timestamp,
+                           GError          **error)
+{
+    YelpApplicationLoad *data;
+    YelpUri *yuri;
+
+    data = g_new (YelpApplicationLoad, 1);
+    data->app = app;
+    data->timestamp = timestamp;
+    
+    yuri = yelp_uri_new (uri);
+    
+    g_signal_connect (yuri, "resolved",
+                      G_CALLBACK (application_uri_resolved),
+                      data);
+    yelp_uri_resolve (yuri);
+
+    return TRUE;
+}
+
+static GtkWidget *
+application_new_window (YelpApplication *app)
+{
+    GtkWidget *window, *scroll, *view;
+    YelpApplicationPrivate *priv = GET_PRIV (app);
+    
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_UTILITY);
+    gtk_window_set_default_size (GTK_WINDOW (window), 520, 580);
+    priv->windows = g_slist_prepend (priv->windows, window);
+
+    scroll = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
+                                    GTK_POLICY_AUTOMATIC,
+                                    GTK_POLICY_AUTOMATIC);
+    gtk_container_add (GTK_CONTAINER (window), scroll);
+
+    view = yelp_view_new ();
+    gtk_container_add (GTK_CONTAINER (scroll), view);
+
+    g_object_set_data (G_OBJECT (window), "view", view);
+
+    return window;
+}
+
+static void
+application_uri_resolved (YelpUri             *uri,
+                          YelpApplicationLoad *data)
+{
+    GtkWidget *window;
+    YelpView *view;
+    gchar *doc_uri;
+    YelpApplicationPrivate *priv = GET_PRIV (data->app);
+
+    doc_uri = yelp_uri_get_document_uri (uri);
+
+    window = g_hash_table_lookup (priv->windows_by_document, doc_uri);
+
+    if (window == NULL) {
+        window = application_new_window (data->app);
+        g_hash_table_insert (priv->windows_by_document, doc_uri, window);
+    }
+    else {
+        g_free (doc_uri);
+    }
+
+    view = g_object_get_data (G_OBJECT (window), "view");
+    yelp_view_load_uri (YELP_VIEW (view), uri);
+
+    gtk_widget_show_all (window);
+    gtk_window_present_with_time (GTK_WINDOW (window), data->timestamp);
+
+    g_free (data);
+}
diff --git a/src/yelp-application.h b/src/yelp-application.h
new file mode 100644
index 0000000..6e5d141
--- /dev/null
+++ b/src/yelp-application.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2010 Shaun McCance  <shaunm gnome org>
+ *
+ * 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: Shaun McCance  <shaunm gnome org>
+ */
+
+#ifndef __YELP_APPLICATION_H__
+#define __YELP_APPLICATION_H__
+
+#include <unique/unique.h>
+
+#define YELP_TYPE_APPLICATION            (yelp_application_get_type ())
+#define YELP_APPLICATION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), YELP_TYPE_APPLICATION, YelpApplication))
+#define YELP_APPLICATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), YELP_TYPE_APPLICATION, YelpApplicationClass))
+#define YELP_IS_APPLICATION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), YELP_TYPE_APPLICATION))
+#define YELP_IS_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), YELP_TYPE_APPLICATION))
+
+typedef struct _YelpApplication       YelpApplication;
+typedef struct _YelpApplicationClass  YelpApplicationClass;
+
+struct _YelpApplication
+{
+    GObject       parent;
+};
+
+struct _YelpApplicationClass
+{
+    GObjectClass  parent_class;
+};
+
+GType             yelp_application_get_type    (void);
+YelpApplication*  yelp_application_new         (void);
+gint              yelp_application_run         (YelpApplication  *app,
+                                                GOptionContext   *context,
+                                                gint              argc,
+                                                gchar           **argv);
+gboolean          yelp_application_load_uri    (YelpApplication  *app,
+                                                const gchar      *uri,
+                                                guint             timestamp,
+                                                GError          **error);
+
+#endif /* __YELP_APPLICATION_H__ */
diff --git a/src/yelp-dbus.xml b/src/yelp-dbus.xml
new file mode 100644
index 0000000..124bfe7
--- /dev/null
+++ b/src/yelp-dbus.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<node name="/org/gnome/Yelp">
+  <interface name="org.gnome.Yelp">
+    <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="yelp_application"/>
+    <method name="LoadUri">
+      <arg type="s" name="Uri" direction="in"/>
+      <arg type="u" name="Timestamp" direction="in"/>
+    </method>
+  </interface>
+</node>
diff --git a/src/yelp.c b/src/yelp.c
new file mode 100644
index 0000000..ce20a3a
--- /dev/null
+++ b/src/yelp.c
@@ -0,0 +1,49 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2010 Shaun McCance  <shaunm gnome org>
+ *
+ * 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: Shaun McCance  <shaunm gnome org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "yelp-application.h"
+
+int
+main (int argc, char **argv) 
+{
+    GOptionContext *context;
+    YelpApplication *app;
+
+    g_thread_init (NULL);
+
+    g_set_application_name (N_("Help"));
+
+    context = g_option_context_new (NULL);
+    g_option_context_add_group (context, gtk_get_option_group (TRUE));
+    g_option_context_parse (context, &argc, &argv, NULL);
+
+    app = yelp_application_new ();
+
+    return yelp_application_run (app, context, argc, argv);
+}



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