[gimp] app: turn GimpApplicator into a general-purpose "input + aux -> output" thing



commit 69a321ac29eebcc64399c64c2f2e28ad412079b0
Author: Michael Natterer <mitch gimp org>
Date:   Sun Apr 14 22:44:21 2013 +0200

    app: turn GimpApplicator into a general-purpose "input + aux -> output" thing
    
    which means adding a lot of proper API. Input, output and aux can be
    pads or buffers. Make sure it uses the minimum possible graph in all
    cases and doesn't reconfigure nodes unless needed. Port GimpPaintCore
    to the new API.

 app/gegl/gimpapplicator.c | 333 +++++++++++++++++++++++++++++++++-------------
 app/gegl/gimpapplicator.h |  77 ++++++++---
 app/paint/gimppaintcore.c |  76 ++++++-----
 3 files changed, 341 insertions(+), 145 deletions(-)
---
diff --git a/app/gegl/gimpapplicator.c b/app/gegl/gimpapplicator.c
index 9a94073..fee2482 100644
--- a/app/gegl/gimpapplicator.c
+++ b/app/gegl/gimpapplicator.c
@@ -1,6 +1,9 @@
 /* GIMP - The GNU Image Manipulation Program
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  *
+ * gimpapplicator.c
+ * Copyright (C) 2012-2013 Michael Natterer <mitch gimp 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 3 of the License, or
@@ -56,6 +59,7 @@ gimp_applicator_init (GimpApplicator *applicator)
 {
   applicator->opacity    = 1.0;
   applicator->paint_mode = GIMP_NORMAL_MODE;
+  applicator->affect     = GIMP_COMPONENT_ALL;
 }
 
 static void
@@ -101,149 +105,279 @@ gimp_applicator_get_property (GObject    *object,
 }
 
 GimpApplicator *
-gimp_applicator_new (GeglBuffer        *dest_buffer,
-                     GimpComponentMask  affect,
-                     GeglBuffer        *mask_buffer,
-                     gint               mask_offset_x,
-                     gint               mask_offset_y)
+gimp_applicator_new (GeglNode *parent)
 {
   GimpApplicator *applicator;
 
-  g_return_val_if_fail (GEGL_IS_BUFFER (dest_buffer), NULL);
-  g_return_val_if_fail (mask_buffer == NULL || GEGL_IS_BUFFER (mask_buffer),
-                        NULL);
+  g_return_val_if_fail (parent == NULL || GEGL_IS_NODE (parent), NULL);
 
   applicator = g_object_new (GIMP_TYPE_APPLICATOR, NULL);
 
-  applicator->node = gegl_node_new ();
+  if (parent)
+    applicator->node = g_object_ref (parent);
+  else
+    applicator->node = gegl_node_new ();
+
+  applicator->input_node =
+    gegl_node_get_input_proxy  (applicator->node, "input");
+
+  applicator->aux_node =
+    gegl_node_get_input_proxy  (applicator->node, "aux");
+
+  applicator->output_node =
+    gegl_node_get_output_proxy (applicator->node, "output");
 
   applicator->mode_node = gegl_node_new_child (applicator->node,
                                                "operation", "gimp:normal-mode",
                                                NULL);
 
-  applicator->src_node =
+  gimp_gegl_mode_node_set (applicator->mode_node,
+                           applicator->paint_mode,
+                           applicator->opacity,
+                           FALSE);
+
+  gegl_node_connect_to (applicator->input_node, "output",
+                        applicator->mode_node,  "input");
+
+  applicator->apply_offset_node =
     gegl_node_new_child (applicator->node,
-                         "operation", "gegl:buffer-source",
+                         "operation", "gegl:translate",
                          NULL);
 
-  gegl_node_connect_to (applicator->src_node,  "output",
-                        applicator->mode_node, "input");
+  gegl_node_connect_to (applicator->aux_node,          "output",
+                        applicator->apply_offset_node, "input");
+  gegl_node_connect_to (applicator->apply_offset_node, "output",
+                        applicator->mode_node,         "aux");
 
-  applicator->apply_src_node =
+  applicator->mask_node =
     gegl_node_new_child (applicator->node,
                          "operation", "gegl:buffer-source",
                          NULL);
 
-  applicator->apply_offset_node =
+  applicator->mask_offset_node =
     gegl_node_new_child (applicator->node,
                          "operation", "gegl:translate",
                          NULL);
 
-  gegl_node_connect_to (applicator->apply_src_node,    "output",
-                        applicator->apply_offset_node, "input");
-  gegl_node_connect_to (applicator->apply_offset_node, "output",
-                        applicator->mode_node,         "aux");
+  gegl_node_connect_to (applicator->mask_node,        "output",
+                        applicator->mask_offset_node, "input");
+  /* don't connect the the mask offset node to mode's aux2 yet */
 
-  if (mask_buffer)
-    {
-      GeglNode *mask_src;
+  applicator->affect_node =
+    gegl_node_new_child (applicator->node,
+                         "operation", "gimp:mask-components",
+                         "mask",      applicator->affect,
+                         NULL);
 
-      mask_src = gegl_node_new_child (applicator->node,
-                                      "operation", "gegl:buffer-source",
-                                      "buffer",    mask_buffer,
-                                      NULL);
+  gegl_node_connect_to (applicator->input_node,  "output",
+                        applicator->affect_node, "input");
+  gegl_node_connect_to (applicator->mode_node,   "output",
+                        applicator->affect_node, "aux");
+  gegl_node_connect_to (applicator->affect_node, "output",
+                        applicator->output_node, "input");
+
+  return applicator;
+}
+
+void
+gimp_applicator_set_src_buffer (GimpApplicator *applicator,
+                                GeglBuffer     *src_buffer)
+{
+  g_return_if_fail (src_buffer == NULL || GEGL_IS_BUFFER (src_buffer));
 
-      if (mask_offset_x != 0 || mask_offset_y != 0)
+  if (src_buffer == applicator->src_buffer)
+    return;
+
+  if (src_buffer)
+    {
+      if (! applicator->src_node)
         {
-          GeglNode *offset;
-
-          offset = gegl_node_new_child (applicator->node,
-                                        "operation", "gegl:translate",
-                                        "x",         (gdouble) mask_offset_x,
-                                        "y",         (gdouble) mask_offset_y,
-                                        NULL);
-
-          gegl_node_connect_to (mask_src,              "output",
-                                offset,                "input");
-          gegl_node_connect_to (offset,                "output",
-                                applicator->mode_node, "aux2");
+          applicator->src_node =
+            gegl_node_new_child (applicator->node,
+                                 "operation", "gegl:buffer-source",
+                                 "buffer",    src_buffer,
+                                 NULL);
         }
       else
         {
-          gegl_node_connect_to (mask_src,              "output",
-                                applicator->mode_node, "aux2");
+          gegl_node_set (applicator->src_node,
+                         "buffer", src_buffer,
+                         NULL);
+        }
+
+      if (! applicator->src_buffer)
+        {
+          gegl_node_connect_to (applicator->src_node,    "output",
+                                applicator->mode_node,   "input");
+          gegl_node_connect_to (applicator->src_node,    "output",
+                                applicator->affect_node, "input");
         }
     }
+  else if (applicator->src_buffer)
+    {
+      gegl_node_connect_to (applicator->input_node,  "output",
+                            applicator->mode_node,   "input");
+      gegl_node_connect_to (applicator->input_node,  "output",
+                            applicator->affect_node, "input");
+    }
 
-  applicator->dest_node =
-    gegl_node_new_child (applicator->node,
-                         "operation", "gegl:write-buffer",
-                         "buffer",    dest_buffer,
-                         "flush",     FALSE,
+  applicator->src_buffer = src_buffer;
+}
+
+void
+gimp_applicator_set_dest_buffer (GimpApplicator *applicator,
+                                 GeglBuffer     *dest_buffer)
+{
+  g_return_if_fail (dest_buffer == NULL || GEGL_IS_BUFFER (dest_buffer));
+
+  if (dest_buffer == applicator->dest_buffer)
+    return;
+
+  if (dest_buffer)
+    {
+      if (! applicator->dest_node)
+        {
+          applicator->dest_node =
+            gegl_node_new_child (applicator->node,
+                                 "operation", "gegl:write-buffer",
+                                 "buffer",    dest_buffer,
+                                 "flush",     FALSE,
+                                 NULL);
+        }
+      else
+        {
+          gegl_node_set (applicator->dest_node,
+                         "buffer", dest_buffer,
                          NULL);
+        }
+
+      if (! applicator->dest_buffer)
+        {
+          gegl_node_disconnect (applicator->output_node, "input");
 
-  if (affect == GIMP_COMPONENT_ALL)
+          gegl_node_connect_to (applicator->affect_node, "output",
+                                applicator->dest_node,   "input");
+        }
+    }
+  else if (applicator->dest_buffer)
     {
-      gegl_node_connect_to (applicator->mode_node, "output",
-                            applicator->dest_node, "input");
+      gegl_node_disconnect (applicator->dest_node, "input");
+
+      gegl_node_connect_to (applicator->affect_node, "output",
+                            applicator->output_node, "input");
+    }
+
+  applicator->dest_buffer = dest_buffer;
+}
+
+void
+gimp_applicator_set_mask_buffer (GimpApplicator *applicator,
+                                 GeglBuffer     *mask_buffer)
+{
+  if (applicator->mask_buffer == mask_buffer)
+    return;
+
+  gegl_node_set (applicator->mask_node,
+                 "buffer", mask_buffer,
+                 NULL);
+
+  if (mask_buffer)
+    {
+      gegl_node_connect_to (applicator->mask_offset_node, "output",
+                            applicator->mode_node,        "aux2");
     }
   else
     {
-      GeglNode *affect_node;
-
-      affect_node = gegl_node_new_child (applicator->node,
-                                         "operation", "gimp:mask-components",
-                                         "mask",      affect,
-                                         NULL);
-
-      gegl_node_connect_to (applicator->src_node,  "output",
-                            affect_node,           "input");
-      gegl_node_connect_to (applicator->mode_node, "output",
-                            affect_node,           "aux");
-      gegl_node_connect_to (affect_node,           "output",
-                            applicator->dest_node, "input");
+      gegl_node_disconnect (applicator->mode_node, "aux2");
     }
 
-  return applicator;
+  applicator->mask_buffer = mask_buffer;
 }
 
 void
-gimp_applicator_apply (GimpApplicator       *applicator,
-                       GeglBuffer           *src_buffer,
-                       GeglBuffer           *apply_buffer,
-                       gint                  apply_buffer_x,
-                       gint                  apply_buffer_y,
-                       gdouble               opacity,
-                       GimpLayerModeEffects  paint_mode)
+gimp_applicator_set_mask_offset (GimpApplicator *applicator,
+                                 gint            mask_offset_x,
+                                 gint            mask_offset_y)
 {
-  gint width  = gegl_buffer_get_width  (apply_buffer);
-  gint height = gegl_buffer_get_height (apply_buffer);
-
-  if (applicator->src_buffer != src_buffer)
+  if (applicator->mask_offset_x != mask_offset_x ||
+      applicator->mask_offset_y != mask_offset_y)
     {
-      applicator->src_buffer = src_buffer;
+      applicator->mask_offset_x = mask_offset_x;
+      applicator->mask_offset_y = mask_offset_y;
 
-      gegl_node_set (applicator->src_node,
-                     "buffer", src_buffer,
+      gegl_node_set (applicator->mask_offset_node,
+                     "x", (gdouble) mask_offset_x,
+                     "y", (gdouble) mask_offset_y,
                      NULL);
     }
+}
+
+void
+gimp_applicator_set_apply_buffer (GimpApplicator *applicator,
+                                  GeglBuffer     *apply_buffer)
+{
+  g_return_if_fail (apply_buffer == NULL || GEGL_IS_BUFFER (apply_buffer));
 
-  if (applicator->apply_buffer != apply_buffer)
+  if (apply_buffer == applicator->apply_buffer)
+    return;
+
+  if (apply_buffer)
     {
-      applicator->apply_buffer = apply_buffer;
+      if (! applicator->apply_src_node)
+        {
+          applicator->apply_src_node =
+            gegl_node_new_child (applicator->node,
+                                 "operation", "gegl:buffer-source",
+                                 "buffer",    apply_buffer,
+                                 NULL);
+        }
+      else
+        {
+          gegl_node_set (applicator->apply_src_node,
+                         "buffer", apply_buffer,
+                         NULL);
+        }
 
-      gegl_node_set (applicator->apply_src_node,
-                     "buffer", apply_buffer,
-                     NULL);
+      if (! applicator->apply_buffer)
+        {
+          gegl_node_connect_to (applicator->apply_src_node,    "output",
+                                applicator->apply_offset_node, "input");
+        }
+    }
+  else if (applicator->apply_buffer)
+    {
+      gegl_node_connect_to (applicator->aux_node,          "output",
+                            applicator->apply_offset_node, "input");
     }
 
-  gegl_node_set (applicator->apply_offset_node,
-                 "x", (gdouble) apply_buffer_x,
-                 "y", (gdouble) apply_buffer_y,
-                 NULL);
+  applicator->apply_buffer = apply_buffer;
+}
+
+void
+gimp_applicator_set_apply_offset (GimpApplicator *applicator,
+                                  gint            apply_offset_x,
+                                  gint            apply_offset_y)
+{
+  if (applicator->apply_offset_x != apply_offset_x ||
+      applicator->apply_offset_y != apply_offset_y)
+    {
+      applicator->apply_offset_x = apply_offset_x;
+      applicator->apply_offset_y = apply_offset_y;
+
+      gegl_node_set (applicator->apply_offset_node,
+                     "x", (gdouble) apply_offset_x,
+                     "y", (gdouble) apply_offset_y,
+                     NULL);
+    }
+}
 
-  if ((applicator->opacity    != opacity) ||
-      (applicator->paint_mode != paint_mode))
+void
+gimp_applicator_set_mode (GimpApplicator       *applicator,
+                          gdouble               opacity,
+                          GimpLayerModeEffects  paint_mode)
+{
+  if (applicator->opacity    != opacity ||
+      applicator->paint_mode != paint_mode)
     {
       applicator->opacity    = opacity;
       applicator->paint_mode = paint_mode;
@@ -251,9 +385,26 @@ gimp_applicator_apply (GimpApplicator       *applicator,
       gimp_gegl_mode_node_set (applicator->mode_node,
                                paint_mode, opacity, FALSE);
     }
+}
+
+void
+gimp_applicator_set_affect (GimpApplicator    *applicator,
+                            GimpComponentMask  affect)
+{
+  if (applicator->affect != affect)
+    {
+      applicator->affect = affect;
 
-  gegl_node_blit (applicator->dest_node, 1.0,
-                  GEGL_RECTANGLE (apply_buffer_x, apply_buffer_y,
-                                  width, height),
+      gegl_node_set (applicator->affect_node,
+                     "mask", affect,
+                     NULL);
+    }
+}
+
+void
+gimp_applicator_blit (GimpApplicator      *applicator,
+                      const GeglRectangle *rect)
+{
+  gegl_node_blit (applicator->dest_node, 1.0, rect,
                   NULL, NULL, 0, GEGL_BLIT_DEFAULT);
 }
diff --git a/app/gegl/gimpapplicator.h b/app/gegl/gimpapplicator.h
index 7b88609..cf624d9 100644
--- a/app/gegl/gimpapplicator.h
+++ b/app/gegl/gimpapplicator.h
@@ -2,7 +2,7 @@
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  *
  * gimpapplicator.h
- * Copyright (C) 2012 Michael Natterer <mitch gimp org>
+ * Copyright (C) 2012-2013 Michael Natterer <mitch gimp 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
@@ -37,18 +37,36 @@ struct _GimpApplicator
   GObject               parent_instance;
 
   GeglNode             *node;
-  GeglNode             *mode_node;
-  GeglNode             *src_node;
+  GeglNode             *input_node;
+  GeglNode             *aux_node;
+  GeglNode             *output_node;
+
+  GeglBuffer           *apply_buffer;
   GeglNode             *apply_src_node;
+
+  gint                  apply_offset_x;
+  gint                  apply_offset_y;
   GeglNode             *apply_offset_node;
-  GeglNode             *dest_node;
 
-  GeglBuffer           *src_buffer;
-  GeglBuffer           *apply_buffer;
-  gint                  apply_buffer_x;
-  gint                  apply_buffer_y;
   gdouble               opacity;
   GimpLayerModeEffects  paint_mode;
+  GeglNode             *mode_node;
+
+  GimpComponentMask     affect;
+  GeglNode             *affect_node;
+
+  GeglBuffer           *src_buffer;
+  GeglNode             *src_node;
+
+  GeglBuffer           *dest_buffer;
+  GeglNode             *dest_node;
+
+  GeglBuffer           *mask_buffer;
+  GeglNode             *mask_node;
+
+  gint                  mask_offset_x;
+  gint                  mask_offset_y;
+  GeglNode             *mask_offset_node;
 };
 
 struct _GimpApplicatorClass
@@ -57,20 +75,35 @@ struct _GimpApplicatorClass
 };
 
 
-GType            gimp_applicator_get_type (void) G_GNUC_CONST;
-
-GimpApplicator * gimp_applicator_new      (GeglBuffer           *dest_buffer,
-                                           GimpComponentMask     affect,
-                                           GeglBuffer           *mask_buffer,
-                                           gint                  mask_offset_x,
-                                           gint                  mask_offset_y);
-void             gimp_applicator_apply    (GimpApplicator       *applicator,
-                                           GeglBuffer           *src_buffer,
-                                           GeglBuffer           *apply_buffer,
-                                           gint                  apply_buffer_x,
-                                           gint                  apply_buffer_y,
-                                           gdouble               opacity,
-                                           GimpLayerModeEffects  paint_mode);
+GType   gimp_applicator_get_type         (void) G_GNUC_CONST;
+
+GimpApplicator * gimp_applicator_new     (GeglNode             *parent);
+
+void    gimp_applicator_set_src_buffer   (GimpApplicator       *applicator,
+                                          GeglBuffer           *dest_buffer);
+void    gimp_applicator_set_dest_buffer  (GimpApplicator       *applicator,
+                                          GeglBuffer           *dest_buffer);
+
+void    gimp_applicator_set_mask_buffer  (GimpApplicator       *applicator,
+                                          GeglBuffer           *mask_buffer);
+void    gimp_applicator_set_mask_offset  (GimpApplicator       *applicator,
+                                          gint                  mask_offset_x,
+                                          gint                  mask_offset_y);
+
+void    gimp_applicator_set_apply_buffer (GimpApplicator       *applicator,
+                                          GeglBuffer           *apply_buffer);
+void    gimp_applicator_set_apply_offset (GimpApplicator       *applicator,
+                                          gint                  apply_offset_x,
+                                          gint                  apply_offset_y);
+
+void    gimp_applicator_set_mode         (GimpApplicator       *applicator,
+                                          gdouble               opacity,
+                                          GimpLayerModeEffects  paint_mode);
+void    gimp_applicator_set_affect       (GimpApplicator       *applicator,
+                                          GimpComponentMask     affect);
+
+void    gimp_applicator_blit             (GimpApplicator       *applicator,
+                                          const GeglRectangle  *rect);
 
 
 #endif  /*  __GIMP_APPLICATOR_H__  */
diff --git a/app/paint/gimppaintcore.c b/app/paint/gimppaintcore.c
index b5d44b5..50ecd9e 100644
--- a/app/paint/gimppaintcore.c
+++ b/app/paint/gimppaintcore.c
@@ -327,8 +327,9 @@ gimp_paint_core_start (GimpPaintCore     *core,
                        const GimpCoords  *coords,
                        GError           **error)
 {
-  GimpImage *image;
-  GimpItem  *item;
+  GimpImage   *image;
+  GimpItem    *item;
+  GimpChannel *mask;
 
   g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
   g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
@@ -398,29 +399,32 @@ gimp_paint_core_start (GimpPaintCore     *core,
   core->last_paint.x = -1e6;
   core->last_paint.y = -1e6;
 
-  {
-    GimpChannel *mask        = gimp_image_get_mask (image);
-    GeglBuffer  *mask_buffer = NULL;
-    gint         offset_x    = 0;
-    gint         offset_y    = 0;
+  mask = gimp_image_get_mask (image);
+
+  /*  don't apply the mask to itself and don't apply an empty mask  */
+  if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
+    mask = NULL;
 
-    /*  don't apply the mask to itself and don't apply an empty mask  */
-    if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
-      mask = NULL;
+  core->applicator = gimp_applicator_new (NULL);
 
-    if (mask)
-      {
-        mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
+  if (mask)
+    {
+      GeglBuffer *mask_buffer;
+      gint        offset_x;
+      gint        offset_y;
 
-        gimp_item_get_offset (item, &offset_x, &offset_y);
-      }
+      mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
+      gimp_item_get_offset (item, &offset_x, &offset_y);
 
-    core->applicator =
-      gimp_applicator_new (gimp_drawable_get_buffer (drawable),
-                           gimp_drawable_get_active_mask (drawable),
-                           mask_buffer,
-                           -offset_x, -offset_y);
-  }
+      gimp_applicator_set_mask_buffer (core->applicator, mask_buffer);
+      gimp_applicator_set_mask_offset (core->applicator,
+                                       -offset_x, -offset_y);
+    }
+
+  gimp_applicator_set_affect (core->applicator,
+                              gimp_drawable_get_active_mask (drawable));
+  gimp_applicator_set_dest_buffer (core->applicator,
+                                   gimp_drawable_get_buffer (drawable));
 
   /*  Freeze the drawable preview so that it isn't constantly updated.  */
   gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable));
@@ -740,9 +744,8 @@ gimp_paint_core_paste (GimpPaintCore            *core,
                        GimpLayerModeEffects      paint_mode,
                        GimpPaintApplicationMode  mode)
 {
-  GeglBuffer *base_buffer = NULL;
-  gint        width       = gegl_buffer_get_width  (core->paint_buffer);
-  gint        height      = gegl_buffer_get_height (core->paint_buffer);
+  gint width  = gegl_buffer_get_width  (core->paint_buffer);
+  gint height = gegl_buffer_get_height (core->paint_buffer);
 
   /*  If the mode is CONSTANT:
    *   combine the canvas buf, the paint mask to the canvas buffer
@@ -771,7 +774,8 @@ gimp_paint_core_paste (GimpPaintCore            *core,
                             GEGL_RECTANGLE (0, 0, width, height),
                             1.0);
 
-      base_buffer = core->undo_buffer;
+      gimp_applicator_set_src_buffer (core->applicator,
+                                      core->undo_buffer);
     }
   /*  Otherwise:
    *   combine the canvas buf and the paint mask to the canvas buf
@@ -783,16 +787,24 @@ gimp_paint_core_paste (GimpPaintCore            *core,
                             GEGL_RECTANGLE (0, 0, width, height),
                             paint_opacity);
 
-      base_buffer = gimp_drawable_get_buffer (drawable);
+      gimp_applicator_set_src_buffer (core->applicator,
+                                      gimp_drawable_get_buffer (drawable));
     }
 
+  gimp_applicator_set_apply_buffer (core->applicator,
+                                    core->paint_buffer);
+  gimp_applicator_set_apply_offset (core->applicator,
+                                    core->paint_buffer_x,
+                                    core->paint_buffer_y);
+
+  gimp_applicator_set_mode (core->applicator,
+                            image_opacity, paint_mode);
+
   /*  apply the paint area to the image  */
-  gimp_applicator_apply (core->applicator,
-                         base_buffer,
-                         core->paint_buffer,
-                         core->paint_buffer_x,
-                         core->paint_buffer_y,
-                         image_opacity, paint_mode);
+  gimp_applicator_blit (core->applicator,
+                        GEGL_RECTANGLE (core->paint_buffer_x,
+                                        core->paint_buffer_y,
+                                        width, height));
 
   /*  Update the undo extents  */
   core->x1 = MIN (core->x1, core->paint_buffer_x);


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