[libgepub/widget-pagination] Pagination "almost" working with column-width css



commit cf878df4c3ef7e27245c0c778fada5634a1b51bb
Author: Daniel GarcĂ­a Moreno <danigm wadobo com>
Date:   Fri May 19 13:18:18 2017 +0200

    Pagination "almost" working with column-width css

 libgepub/gepub-widget.c |  354 ++++++++++++++++++++++++++++++++++-------------
 libgepub/gepub-widget.h |   17 ++-
 tests/test-gepub.c      |   40 +++---
 3 files changed, 285 insertions(+), 126 deletions(-)
---
diff --git a/libgepub/gepub-widget.c b/libgepub/gepub-widget.c
index f4ef9d0..5f52814 100644
--- a/libgepub/gepub-widget.c
+++ b/libgepub/gepub-widget.c
@@ -28,8 +28,10 @@ struct _GepubWidget {
 
     GepubDoc *doc;
     gboolean paginate;
-    gint page;
-    gint chapter_pages;
+    gint chapter_length; // real chapter length
+    gint chapter_pos; // position in the chapter, a percentage based on chapter_length
+    gint length;
+    gint init_chapter_pos;
 };
 
 struct _GepubWidgetClass {
@@ -40,8 +42,9 @@ enum {
     PROP_0,
     PROP_DOC,
     PROP_PAGINATE,
-    PROP_PAGE,
-    PROP_NPAGES,
+    PROP_CHAPTER,
+    PROP_N_CHAPTERS,
+    PROP_CHAPTER_POS,
     NUM_PROPS
 };
 
@@ -50,6 +53,30 @@ static GParamSpec *properties[NUM_PROPS] = { NULL, };
 G_DEFINE_TYPE (GepubWidget, gepub_widget, WEBKIT_TYPE_WEB_VIEW)
 
 static void
+scroll_to_chapter_pos (GepubWidget *widget) {
+    gchar *script = g_strdup_printf("document.querySelector('body').scrollTo(%d, 0)", widget->chapter_pos);
+    webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (widget), script, NULL, NULL, NULL);
+    g_free(script);
+}
+
+static void
+adjust_chapter_pos (GepubWidget *widget)
+{
+    // integer division to make a page start
+    gint page = widget->chapter_pos / widget->length;
+    gint next = page + 1;
+    gint d1 = widget->chapter_pos - (widget->length * page);
+    gint d2 = (widget->length * next) - widget->chapter_pos;
+
+    if (d1 < d2) {
+        widget->chapter_pos = widget->length * page;
+    } else {
+        widget->chapter_pos = widget->length * next;
+    }
+    scroll_to_chapter_pos (widget);
+}
+
+static void
 pagination_initialize_finished (GObject      *object,
                                 GAsyncResult *result,
                                 gpointer     user_data)
@@ -73,8 +100,20 @@ pagination_initialize_finished (GObject      *object,
         double n;
 
         n = JSValueToNumber (context, value, NULL);
-        widget->chapter_pages = (int)n;
-        g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_NPAGES]);
+        widget->chapter_length = (int)n;
+
+        if (widget->init_chapter_pos) {
+            widget->chapter_pos = widget->init_chapter_pos * widget->chapter_length / 100;
+            if (widget->chapter_pos > (widget->chapter_length - widget->length)) {
+                widget->chapter_pos = (widget->chapter_length - widget->length);
+            }
+            widget->init_chapter_pos = 0;
+        }
+
+        if (widget->chapter_pos) {
+            adjust_chapter_pos (widget);
+        }
+
     } else {
         g_warning ("Error running javascript: unexpected return value");
     }
@@ -82,50 +121,67 @@ pagination_initialize_finished (GObject      *object,
 }
 
 static void
-paginate_cb (WebKitWebView  *web_view,
+get_length_finished (GObject      *object,
+                     GAsyncResult *result,
+                     gpointer     user_data)
+{
+    WebKitJavascriptResult *js_result;
+    JSValueRef              value;
+    JSGlobalContextRef      context;
+    GError                 *error = NULL;
+    GepubWidget            *widget = GEPUB_WIDGET (user_data);
+
+    js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (object), result, &error);
+    if (!js_result) {
+        g_warning ("Error running javascript: %s", error->message);
+        g_error_free (error);
+        return;
+    }
+
+    context = webkit_javascript_result_get_global_context (js_result);
+    value = webkit_javascript_result_get_value (js_result);
+    if (JSValueIsNumber (context, value)) {
+        double n;
+
+        n = JSValueToNumber (context, value, NULL);
+        widget->length = (int)n;
+    } else {
+        g_warning ("Error running javascript: unexpected return value");
+    }
+    webkit_javascript_result_unref (js_result);
+}
+
+static void
+reload_length_cb (GtkWidget *widget,
+                  GdkRectangle *allocation,
+                  gpointer      user_data)
+{
+    GepubWidget *gwidget = GEPUB_WIDGET (widget);
+    WebKitWebView *web_view = WEBKIT_WEB_VIEW (widget);
+
+    webkit_web_view_run_javascript (web_view,
+        "window.innerWidth",
+        NULL, get_length_finished, (gpointer)widget);
+
+    if (gwidget->paginate) {
+        webkit_web_view_run_javascript (web_view,
+                "document.querySelector('body').setAttribute('style', 'overflow: hidden; column-gap: 0px;');"
+                "document.querySelector('body').style.columnWidth = window.innerWidth+'px';"
+                "document.querySelector('body').style.height = window.innerHeight+'px';"
+                "document.querySelector('body').scrollWidth",
+                NULL, pagination_initialize_finished, (gpointer)widget);
+    }
+}
+
+static void
+docready_cb (WebKitWebView  *web_view,
              WebKitLoadEvent load_event,
              gpointer        user_data)
 {
-
     GepubWidget *widget = GEPUB_WIDGET (web_view);
 
     if (load_event == WEBKIT_LOAD_FINISHED) {
-        const gchar *script = "function initialize() { "
-                                  "var d = document.querySelector('body');"
-                                  "var ourH = window.innerHeight - 40; "
-                                  "var ourW = window.innerWidth - 20; "
-                                  "var fullH = d.offsetHeight; "
-                                  "var pageCount = Math.floor(fullH/ourH)+1;"
-                                  "var newW = pageCount * ourW; "
-                                  "d.style.height = ourH+'px';"
-                                  "d.style.width = newW+'px';"
-                                  "d.style.WebkitColumnCount = pageCount;"
-                                  "d.style.WebkitColumnGap = '20px';"
-                                  "d.style.overflow = 'hidden';"
-                                  "window.currentPage = 0; "
-                                  "return pageCount;"
-                              "};"
-                              "function next() { "
-                                  "var ourW = window.innerWidth - 10; "
-                                  "window.currentPage += 1; "
-                                  "window.scroll(ourW * window.currentPage, 0); "
-                              "};"
-                              "function prev() { "
-                                  "var ourW = window.innerWidth - 10; "
-                                  "window.currentPage -= 1; "
-                                  "window.scroll(ourW * window.currentPage, 0); "
-                              "};"
-                              "function nth(index) { "
-                                  "var ourW = window.innerWidth - 10; "
-                                  "window.currentPage = index; "
-                                  "window.scroll(ourW * window.currentPage, 0); "
-                              "};"
-                              "initialize();";
-
-        if (widget->paginate) {
-            webkit_web_view_run_javascript (web_view, "document.querySelector('body').style.margin = 
'20px';", NULL, NULL, NULL);
-            webkit_web_view_run_javascript (web_view, script, NULL, pagination_initialize_finished, 
(gpointer)widget);
-        }
+        reload_length_cb (GTK_WIDGET (widget), NULL, NULL);
     }
 }
 
@@ -177,8 +233,11 @@ gepub_widget_set_property (GObject      *object,
     case PROP_PAGINATE:
         gepub_widget_set_pagination (widget, g_value_get_boolean (value));
         break;
-    case PROP_PAGE:
-        gepub_widget_set_page (widget, g_value_get_int (value));
+    case PROP_CHAPTER:
+        gepub_doc_set_page (widget->doc, g_value_get_int (value));
+        break;
+    case PROP_CHAPTER_POS:
+        gepub_widget_set_pos (widget, g_value_get_float (value));
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -201,11 +260,14 @@ gepub_widget_get_property (GObject    *object,
     case PROP_PAGINATE:
         g_value_set_boolean (value, widget->paginate);
         break;
-    case PROP_PAGE:
-        g_value_set_int (value, gepub_widget_get_page (widget));
+    case PROP_CHAPTER:
+        g_value_set_int (value, gepub_doc_get_page (widget->doc));
         break;
-    case PROP_NPAGES:
-        g_value_set_int (value, gepub_widget_get_n_pages (widget));
+    case PROP_N_CHAPTERS:
+        g_value_set_int (value, gepub_doc_get_n_pages (widget->doc));
+        break;
+    case PROP_CHAPTER_POS:
+        g_value_set_float (value, gepub_widget_get_pos (widget));
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -226,6 +288,11 @@ gepub_widget_finalize (GObject *object)
 static void
 gepub_widget_init (GepubWidget *widget)
 {
+    widget->chapter_length = 0;
+    widget->paginate = FALSE;
+    widget->chapter_pos = 0;
+    widget->length = 0;
+    widget->init_chapter_pos = 0;
 }
 
 static void
@@ -238,7 +305,8 @@ gepub_widget_constructed (GObject *object)
 
     ctx = webkit_web_view_get_context (WEBKIT_WEB_VIEW (widget));
     webkit_web_context_register_uri_scheme (ctx, "epub", resource_callback, widget, NULL);
-    g_signal_connect (widget, "load-changed", G_CALLBACK (paginate_cb), NULL);
+    g_signal_connect (widget, "load-changed", G_CALLBACK (docready_cb), NULL);
+    g_signal_connect (widget, "size-allocate", G_CALLBACK (reload_length_cb), NULL);
 }
 
 static void
@@ -266,20 +334,27 @@ gepub_widget_class_init (GepubWidgetClass *klass)
                               FALSE,
                               G_PARAM_READWRITE);
 
-    properties[PROP_PAGE] =
-        g_param_spec_int ("page",
-                          "Current page",
-                          "Current page in the chapter",
+    properties[PROP_CHAPTER] =
+        g_param_spec_int ("chapter",
+                          "Current chapter",
+                          "Current chapter in the doc",
                           -1, G_MAXINT, 0,
                           G_PARAM_READWRITE);
 
-    properties[PROP_NPAGES] =
-        g_param_spec_int ("chapter_pages",
-                          "Current chapter pages",
-                          "Current chapter number of pages",
+    properties[PROP_N_CHAPTERS] =
+        g_param_spec_int ("nchapters",
+                          "Number of chapters in the doc",
+                          "Number of chapters in the doc",
                           -1, G_MAXINT, 0,
                           G_PARAM_READABLE);
 
+    properties[PROP_CHAPTER_POS] =
+        g_param_spec_float ("chapter_pos",
+                            "Current position in chapter",
+                            "Current position in chapter",
+                            0, 100, 0,
+                            G_PARAM_READWRITE);
+
     g_object_class_install_properties (object_class, NUM_PROPS, properties);
 }
 
@@ -314,6 +389,10 @@ reload_current_chapter (GepubWidget *widget)
 {
     GBytes *current;
 
+    widget->chapter_length = 0;
+    widget->chapter_pos = 0;
+    widget->length = 0;
+
     current = gepub_doc_get_current_with_epub_uris (widget->doc);
     webkit_web_view_load_bytes (WEBKIT_WEB_VIEW (widget),
                                 current,
@@ -372,82 +451,161 @@ gepub_widget_set_pagination (GepubWidget *widget,
 }
 
 /**
- * gepub_widget_page_next:
+ * gepub_widget_get_n_chapters:
  * @widget: a #GepubWidget
  *
- * Change the page to the next
+ * Returns: the number of chapters in the document
  */
-void
-gepub_widget_page_next (GepubWidget *widget)
+gint
+gepub_widget_get_n_chapters (GepubWidget *widget)
 {
-    if (widget->page >= widget->chapter_pages)
-        return;
+    g_return_val_if_fail (GEPUB_IS_DOC (widget->doc), 0);
+    return gepub_doc_get_n_pages (widget->doc);
+}
 
-    webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (widget), "next();", NULL, NULL, NULL);
-    widget->page += 1;
+/**
+ * gepub_widget_get_chapter:
+ * @widget: a #GepubWidget
+ *
+ * Returns: the current chapter in the document
+ */
+gint
+gepub_widget_get_chapter (GepubWidget *widget)
+{
+    g_return_val_if_fail (GEPUB_IS_DOC (widget->doc), 0);
+    return gepub_doc_get_page (widget->doc);
 }
 
 /**
- * gepub_widget_page_prev:
+ * gepub_widget_get_chapter_length:
  * @widget: a #GepubWidget
  *
- * Change the page to the prev
+ * Returns: the current chapter length
+ */
+gint
+gepub_widget_get_chapter_length (GepubWidget *widget)
+{
+    g_return_val_if_fail (GEPUB_IS_DOC (widget->doc), 0);
+    return widget->chapter_length;
+}
+
+/**
+ * gepub_widget_set_chapter:
+ * @widget: a #GepubWidget
+ *
+ * Sets the current chapter in the doc
  */
 void
-gepub_widget_page_prev (GepubWidget *widget)
+gepub_widget_set_chapter (GepubWidget *widget,
+                          gint         index)
 {
-    if (widget->page <= 0)
-        return;
+    g_return_if_fail (GEPUB_IS_DOC (widget->doc));
+    return gepub_doc_set_page (widget->doc, index);
+}
 
-    webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (widget), "prev();", NULL, NULL, NULL);
-    widget->page -= 1;
+/**
+ * gepub_widget_chapter_next:
+ * @widget: a #GepubWidget
+ *
+ * Returns: TRUE on success, FALSE if there's no next chapter
+ */
+gboolean
+gepub_widget_chapter_next (GepubWidget *widget)
+{
+    g_return_val_if_fail (GEPUB_IS_DOC (widget->doc), FALSE);
+    return gepub_doc_go_next (widget->doc);
+}
+
+/**
+ * gepub_widget_chapter_prev:
+ * @widget: a #GepubWidget
+ *
+ * Returns: TRUE on success, FALSE if there's no prev chapter
+ */
+gboolean
+gepub_widget_chapter_prev (GepubWidget *widget)
+{
+    g_return_val_if_fail (GEPUB_IS_DOC (widget->doc), FALSE);
+    return gepub_doc_go_prev (widget->doc);
 }
 
 /**
- * gepub_widget_get_n_pages:
+ * gepub_widget_page_next:
  * @widget: a #GepubWidget
  *
- * Returns: the number of pages in the chapter
+ * Returns: TRUE on success, FALSE if there's no next page
  */
-int
-gepub_widget_get_n_pages (GepubWidget *widget)
+gboolean
+gepub_widget_page_next (GepubWidget *widget)
 {
-    return widget->chapter_pages;
+    g_return_val_if_fail (GEPUB_IS_DOC (widget->doc), FALSE);
+    widget->chapter_pos = widget->chapter_pos + widget->length;
+
+    if (widget->chapter_pos > (widget->chapter_length - widget->length)) {
+        widget->chapter_pos = (widget->chapter_length - widget->length);
+        return gepub_doc_go_next (widget->doc);
+    }
+
+    scroll_to_chapter_pos (widget);
+
+    g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_CHAPTER_POS]);
+    return TRUE;
 }
 
 /**
- * gepub_widget_get_page:
+ * gepub_widget_page_prev:
  * @widget: a #GepubWidget
  *
- * Returns: the current page in the chapter
+ * Returns: TRUE on success, FALSE if there's no next page
  */
-int
-gepub_widget_get_page (GepubWidget *widget)
+gboolean
+gepub_widget_page_prev (GepubWidget *widget)
 {
-    return widget->page;
+    g_return_val_if_fail (GEPUB_IS_DOC (widget->doc), FALSE);
+    widget->chapter_pos = widget->chapter_pos - widget->length;
+
+    if (widget->chapter_pos < 0) {
+        widget->init_chapter_pos = 100;
+        return gepub_doc_go_prev (widget->doc);
+    }
+
+    scroll_to_chapter_pos (widget);
+
+    g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_CHAPTER_POS]);
+    return TRUE;
 }
 
 /**
- * gepub_widget_set_page:
+ * gepub_widget_get_pos:
  * @widget: a #GepubWidget
- * @index: the new page index
  *
- * Sets the widget current page to @index.
+ * Returns: the current position in the chapter
  */
-void
-gepub_widget_set_page (GepubWidget *widget, gint index)
+gfloat
+gepub_widget_get_pos (GepubWidget *widget)
 {
-    gchar *script;
+    g_return_val_if_fail (GEPUB_IS_DOC (widget->doc), 0);
 
-    if (index >= widget->chapter_pages)
-        return;
+    if (!widget->chapter_length) {
+        return 0;
+    }
 
-    if (index < 0)
-        return;
+    return widget->chapter_pos * 100 / (float)(widget->chapter_length);
+}
 
-    script = g_strdup_printf ("nth(%d);", index);
-    webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (widget), script, NULL, NULL, NULL);
-    widget->page = index;
+/**
+ * gepub_widget_set_pos:
+ * @widget: a #GepubWidget
+ *
+ * Sets the current position in the chapter
+ */
+void
+gepub_widget_set_pos (GepubWidget *widget,
+                      gfloat       index)
+{
+    g_return_if_fail (GEPUB_IS_DOC (widget->doc));
+    widget->chapter_pos = index * widget->chapter_length / 100;
+    adjust_chapter_pos (widget);
 
-    g_free (script);
+    g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_CHAPTER_POS]);
 }
diff --git a/libgepub/gepub-widget.h b/libgepub/gepub-widget.h
index d825bd1..67ed53a 100644
--- a/libgepub/gepub-widget.h
+++ b/libgepub/gepub-widget.h
@@ -47,13 +47,20 @@ void              gepub_widget_set_doc                         (GepubWidget *wid
                                                                 GepubDoc    *doc);
 
 void              gepub_widget_set_pagination                  (GepubWidget *widget, gboolean p);
-void              gepub_widget_page_next                       (GepubWidget *widget);
-void              gepub_widget_page_prev                       (GepubWidget *widget);
 
-gint              gepub_widget_get_n_pages                     (GepubWidget *widget);
-gint              gepub_widget_get_page                        (GepubWidget *widget);
-void              gepub_widget_set_page                        (GepubWidget *widget,
+gint              gepub_widget_get_n_chapters                  (GepubWidget *widget);
+gint              gepub_widget_get_chapter                     (GepubWidget *widget);
+gint              gepub_widget_get_chapter_length              (GepubWidget *widget);
+void              gepub_widget_set_chapter                     (GepubWidget *widget,
                                                                 gint         index);
+gboolean          gepub_widget_chapter_next                    (GepubWidget *widget);
+gboolean          gepub_widget_chapter_prev                    (GepubWidget *widget);
+
+gfloat            gepub_widget_get_pos                         (GepubWidget *widget);
+void              gepub_widget_set_pos                         (GepubWidget *widget,
+                                                                gfloat       index);
+gboolean          gepub_widget_page_next                       (GepubWidget *widget);
+gboolean          gepub_widget_page_prev                       (GepubWidget *widget);
 
 G_END_DECLS
 
diff --git a/tests/test-gepub.c b/tests/test-gepub.c
index ace6893..8f6864b 100644
--- a/tests/test-gepub.c
+++ b/tests/test-gepub.c
@@ -23,7 +23,7 @@ GtkWidget *PAGE_LABEL;
 static void
 reload_current_chapter (GepubWidget *widget)
 {
-    gchar *txt = g_strdup_printf ("%d", gepub_widget_get_n_pages (widget));
+    gchar *txt = g_strdup_printf ("%02.2f", gepub_widget_get_pos (widget));
     gtk_label_set_text (GTK_LABEL (PAGE_LABEL), txt);
     g_free (txt);
 }
@@ -87,24 +87,13 @@ button_pressed (GtkButton *button, GepubWidget *widget)
     } else if (!strcmp (gtk_button_get_label (button), "paginated")) {
         gboolean b = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
         gepub_widget_set_pagination (widget, b);
+    } else if (!strcmp (gtk_button_get_label (button), "< page")) {
+        gepub_widget_page_prev (widget);
+    } else if (!strcmp (gtk_button_get_label (button), "page >")) {
+        gepub_widget_page_next (widget);
     }
     update_text (doc);
-    print_replaced_text (doc);
-}
-
-void
-spin_changed (GtkSpinButton *button, GepubWidget *widget)
-{
-    gint value = gtk_spin_button_get_value_as_int (button);
-    gint npages = gepub_widget_get_n_pages (widget);
-
-    printf ("PAGE VALUE: %d - %d\n", value, npages);
-    if (value >= gepub_widget_get_n_pages (widget)) {
-        gtk_spin_button_set_value (button, npages);
-        return;
-    }
-
-    gepub_widget_set_page (widget, value);
+    //print_replaced_text (doc);
 }
 
 void
@@ -273,7 +262,8 @@ main (int argc, char **argv)
     GtkWidget *b_next;
     GtkWidget *b_prev;
 
-    GtkWidget *spin_button;
+    GtkWidget *p_next;
+    GtkWidget *p_prev;
 
     GtkWidget *paginate;
 
@@ -290,7 +280,7 @@ main (int argc, char **argv)
 
     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
     g_signal_connect (window, "destroy", (GCallback)gtk_main_quit, NULL);
-    gtk_widget_set_size_request (GTK_WIDGET (window), 800, 500);
+    gtk_widget_set_size_request (GTK_WIDGET (window), 1200, 800);
     vpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
     gtk_container_add (GTK_CONTAINER (window), vpaned);
 
@@ -322,8 +312,10 @@ main (int argc, char **argv)
     b_next = gtk_button_new_with_label ("chapter >");
     g_signal_connect (b_next, "clicked", (GCallback)button_pressed, GEPUB_WIDGET (widget));
 
-    spin_button = gtk_spin_button_new_with_range (0, G_MAXINT, 1);
-    g_signal_connect (spin_button, "value-changed", (GCallback)spin_changed, GEPUB_WIDGET (widget));
+    p_prev = gtk_button_new_with_label ("< page");
+    g_signal_connect (p_prev, "clicked", (GCallback)button_pressed, GEPUB_WIDGET (widget));
+    p_next = gtk_button_new_with_label ("page >");
+    g_signal_connect (p_next, "clicked", (GCallback)button_pressed, GEPUB_WIDGET (widget));
 
     PAGE_LABEL = gtk_label_new ("0");
 
@@ -336,7 +328,9 @@ main (int argc, char **argv)
     gtk_container_add (GTK_CONTAINER (hbox), b_prev);
     gtk_container_add (GTK_CONTAINER (hbox), b_next);
 
-    gtk_container_add (GTK_CONTAINER (hbox), spin_button);
+    gtk_container_add (GTK_CONTAINER (hbox), p_prev);
+    gtk_container_add (GTK_CONTAINER (hbox), p_next);
+
     gtk_container_add (GTK_CONTAINER (hbox), PAGE_LABEL);
     gtk_container_add (GTK_CONTAINER (hbox), paginate);
 
@@ -349,7 +343,7 @@ main (int argc, char **argv)
     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, 
GTK_POLICY_AUTOMATIC);
     gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 5);
 
-    gtk_widget_set_size_request (GTK_WIDGET (vbox), 400, 500);
+    gtk_widget_set_size_request (GTK_WIDGET (vbox), 600, 500);
     gtk_paned_add1 (GTK_PANED (vpaned), vbox);
     gtk_paned_add2 (GTK_PANED (vpaned), widget);
 


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