[gimp/wip/nielsdg/args] gimppdb: Allow more easy bindable API



commit 1911114145f87254093e8bb49bb3461fa5415ade
Author: Niels De Graef <nielsdegraef gmail com>
Date:   Tue May 19 18:43:43 2020 +0200

    gimppdb: Allow more easy bindable API
    
    Plug-ins that work from different bindings probably want to use their
    own list-type to specify arguments, rather than working with a more
    cumbersome `GimpValueArray`.
    
    This new API should make it less verbose. For example:
    
    ```
    args = Gimp.ValueArray.new(5)
    args.insert(0, GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE))
    args.insert(1, GObject.Value(Gimp.Image, image))
    args.insert(2, GObject.Value(Gimp.Drawable, mask))
    args.insert(3, GObject.Value(GObject.TYPE_INT, int(time.time())))
    args.insert(4, GObject.Value(GObject.TYPE_DOUBLE, turbulence))
    Gimp.get_pdb().run_procedure('plug-in-plasma', args)
    ```
    
    becomes
    
    ```
    Gimp.get_pdb().run_procedure('plug-in-plasma', [
        GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE),
        GObject.Value(Gimp.Image, image),
        GObject.Value(Gimp.Drawable, mask),
        GObject.Value(GObject.TYPE_INT, int(time.time())),
        GObject.Value(GObject.TYPE_DOUBLE, turbulence),
    ])
    ```

 devel-docs/libgimp/libgimp3-sections.txt         |  1 +
 devel-docs/libgimpbase/libgimpbase3-sections.txt |  1 +
 libgimp/gimp.def                                 |  1 +
 libgimp/gimppdb.c                                | 39 +++++++++-
 libgimp/gimppdb.h                                |  4 ++
 libgimpbase/gimpbase.def                         |  1 +
 libgimpbase/gimpvaluearray.c                     | 36 +++++++++-
 libgimpbase/gimpvaluearray.h                     |  3 +
 plug-ins/python/colorxhtml.py                    |  7 +-
 plug-ins/python/file-openraster.py               | 91 +++++++++++-------------
 plug-ins/python/foggify.py                       | 14 ++--
 plug-ins/python/spyro-plus.py                    | 32 +++------
 12 files changed, 144 insertions(+), 86 deletions(-)
---
diff --git a/devel-docs/libgimp/libgimp3-sections.txt b/devel-docs/libgimp/libgimp3-sections.txt
index 8a11ea45df..d2642926a7 100644
--- a/devel-docs/libgimp/libgimp3-sections.txt
+++ b/devel-docs/libgimp/libgimp3-sections.txt
@@ -943,6 +943,7 @@ gimp_pdb_lookup_procedure
 gimp_pdb_run_procedure
 gimp_pdb_run_procedure_valist
 gimp_pdb_run_procedure_array
+gimp_pdb_run_procedure_argv
 gimp_pdb_temp_procedure_name
 gimp_pdb_dump_to_file
 gimp_pdb_query_procedures
diff --git a/devel-docs/libgimpbase/libgimpbase3-sections.txt 
b/devel-docs/libgimpbase/libgimpbase3-sections.txt
index 48cc3d31b8..381ceaf0c6 100644
--- a/devel-docs/libgimpbase/libgimpbase3-sections.txt
+++ b/devel-docs/libgimpbase/libgimpbase3-sections.txt
@@ -530,6 +530,7 @@ GimpValueArray
 gimp_value_array_new
 gimp_value_array_new_from_types
 gimp_value_array_new_from_types_valist
+gimp_value_array_new_from_values
 gimp_value_array_ref
 gimp_value_array_unref
 gimp_value_array_length
diff --git a/libgimp/gimp.def b/libgimp/gimp.def
index 3d556c5cfa..58d3f22d09 100644
--- a/libgimp/gimp.def
+++ b/libgimp/gimp.def
@@ -664,6 +664,7 @@ EXPORTS
        gimp_pdb_procedure_exists
        gimp_pdb_query_procedures
        gimp_pdb_run_procedure
+       gimp_pdb_run_procedure_argv
        gimp_pdb_run_procedure_array
        gimp_pdb_run_procedure_valist
        gimp_pdb_set_data
diff --git a/libgimp/gimppdb.c b/libgimp/gimppdb.c
index ce777e01c7..08daacff12 100644
--- a/libgimp/gimppdb.c
+++ b/libgimp/gimppdb.c
@@ -193,7 +193,7 @@ gimp_pdb_lookup_procedure (GimpPDB     *pdb,
 }
 
 /**
- * gimp_pdb_run_procedure:
+ * gimp_pdb_run_procedure: (skip)
  * @pdb:            the #GimpPDB object.
  * @procedure_name: the procedure registered name.
  * @first_type:     the #GType of the first argument, or #G_TYPE_NONE.
@@ -229,7 +229,7 @@ gimp_pdb_run_procedure (GimpPDB     *pdb,
 }
 
 /**
- * gimp_pdb_run_procedure_valist:
+ * gimp_pdb_run_procedure_valist: (skip)
  * @pdb:            the #GimpPDB object.
  * @procedure_name: the procedure registered name.
  * @first_type:     the #GType of the first argument, or #G_TYPE_NONE.
@@ -280,7 +280,40 @@ gimp_pdb_run_procedure_valist (GimpPDB     *pdb,
 }
 
 /**
- * gimp_pdb_run_procedure_array: (rename-to gimp_pdb_run_procedure)
+ * gimp_pdb_run_procedure_argv: (rename-to gimp_pdb_run_procedure)
+ * @pdb:            the #GimpPDB object.
+ * @procedure_name: the procedure registered name.
+ * @arguments: (array length=n_arguments): the call arguments.
+ * @n_arguments: the number of arguments.
+ *
+ * Runs the procedure named @procedure_name with @arguments.
+ *
+ * Returns: (transfer full): the return values for the procedure call.
+ *
+ * Since: 3.0
+ */
+GimpValueArray *
+gimp_pdb_run_procedure_argv (GimpPDB       *pdb,
+                             const gchar   *procedure_name,
+                             const GValue **arguments,
+                             gint           n_arguments)
+{
+  GimpValueArray *args;
+  GimpValueArray *return_values;
+
+  g_return_val_if_fail (GIMP_IS_PDB (pdb), NULL);
+  g_return_val_if_fail (gimp_is_canonical_identifier (procedure_name), NULL);
+  g_return_val_if_fail (arguments != NULL, NULL);
+
+  args = gimp_value_array_new_from_values (arguments, n_arguments);
+  return_values = gimp_pdb_run_procedure_array (pdb, procedure_name, args);
+  gimp_value_array_unref (args);
+
+  return return_values;
+}
+
+/**
+ * gimp_pdb_run_procedure_array:
  * @pdb:            the #GimpPDB object.
  * @procedure_name: the procedure registered name.
  * @arguments:      the call arguments.
diff --git a/libgimp/gimppdb.h b/libgimp/gimppdb.h
index fa45af611a..cb029202d5 100644
--- a/libgimp/gimppdb.h
+++ b/libgimp/gimppdb.h
@@ -81,6 +81,10 @@ GimpValueArray * gimp_pdb_run_procedure_valist (GimpPDB              *pdb,
                                                 const gchar          *procedure_name,
                                                 GType                 first_type,
                                                 va_list               args);
+GimpValueArray * gimp_pdb_run_procedure_argv   (GimpPDB              *pdb,
+                                                const gchar          *procedure_name,
+                                                const GValue        **arguments,
+                                                gint                  n_arguments);
 GimpValueArray * gimp_pdb_run_procedure_array  (GimpPDB              *pdb,
                                                 const gchar          *procedure_name,
                                                 const GimpValueArray *arguments);
diff --git a/libgimpbase/gimpbase.def b/libgimpbase/gimpbase.def
index 3e9f2cd43e..521fd8779e 100644
--- a/libgimpbase/gimpbase.def
+++ b/libgimpbase/gimpbase.def
@@ -219,6 +219,7 @@ EXPORTS
        gimp_value_array_new
        gimp_value_array_new_from_types
        gimp_value_array_new_from_types_valist
+       gimp_value_array_new_from_values
        gimp_value_array_prepend
        gimp_value_array_ref
        gimp_value_array_remove
diff --git a/libgimpbase/gimpvaluearray.c b/libgimpbase/gimpvaluearray.c
index 0df8efdc78..e7c21c7299 100644
--- a/libgimpbase/gimpvaluearray.c
+++ b/libgimpbase/gimpvaluearray.c
@@ -147,7 +147,7 @@ gimp_value_array_new (gint n_prealloced)
 }
 
 /**
- * gimp_value_array_new_from_types:
+ * gimp_value_array_new_from_types: (skip)
  * @error_msg:  return location for an error message.
  * @first_type: first type in the array, or #G_TYPE_NONE.
  * @...:        the remaining types in the array, terminated by #G_TYPE_NONE
@@ -183,7 +183,7 @@ gimp_value_array_new_from_types (gchar **error_msg,
 }
 
 /**
- * gimp_value_array_new_from_types_valist:
+ * gimp_value_array_new_from_types_valist: (skip)
  * @error_msg:  return location for an error message.
  * @first_type: first type in the array, or #G_TYPE_NONE.
  * @va_args:    a va_list of GTypes and values, terminated by #G_TYPE_NONE
@@ -250,6 +250,38 @@ gimp_value_array_new_from_types_valist (gchar   **error_msg,
   return value_array;
 }
 
+/**
+ * gimp_value_array_new_from_values:
+ * @values: (array length=n_values) The #GValue elements
+ * @n_values: the number of value elements
+ *
+ * Allocate and initialize a new #GimpValueArray, and fill it with
+ * the given #GValues.
+ *
+ * Returns: a newly allocated #GimpValueArray.
+ *
+ * Since: 3.0
+ */
+GimpValueArray *
+gimp_value_array_new_from_values (const GValue **values,
+                                  gint           n_values)
+{
+  GimpValueArray *value_array;
+  gint i;
+
+  g_return_val_if_fail (values != NULL, NULL);
+  g_return_val_if_fail (n_values > 0, NULL);
+
+  value_array = gimp_value_array_new (n_values);
+
+  for (i = 0; i < n_values; i++)
+    {
+      gimp_value_array_insert (value_array, i, values[i]);
+    }
+
+  return value_array;
+}
+
 /**
  * gimp_value_array_ref:
  * @value_array: #GimpValueArray to ref
diff --git a/libgimpbase/gimpvaluearray.h b/libgimpbase/gimpvaluearray.h
index 5c17eb6d1a..1c3cbdc8e6 100644
--- a/libgimpbase/gimpvaluearray.h
+++ b/libgimpbase/gimpvaluearray.h
@@ -49,6 +49,9 @@ GimpValueArray * gimp_value_array_new_from_types_valist
                                            (gchar               **error_msg,
                                             GType                 first_type,
                                             va_list               va_args);
+GimpValueArray * gimp_value_array_new_from_values
+                                           (const GValue **values,
+                                            gint           n_values);
 
 GimpValueArray * gimp_value_array_ref      (GimpValueArray       *value_array);
 void             gimp_value_array_unref    (GimpValueArray       *value_array);
diff --git a/plug-ins/python/colorxhtml.py b/plug-ins/python/colorxhtml.py
index 85fe5301ff..bb5946ab71 100755
--- a/plug-ins/python/colorxhtml.py
+++ b/plug-ins/python/colorxhtml.py
@@ -267,10 +267,9 @@ def save_colorxhtml(procedure, run_mode, image, drawable, file, args, data):
     if separate:
         css.close()
 
-    retval = Gimp.ValueArray.new(1)
-    retval.insert(0, GObject.Value(Gimp.PDBStatusType, Gimp.PDBStatusType.SUCCESS))
-
-    return retval
+    return Gimp.ValueArray.new([
+        GObject.Value(Gimp.PDBStatusType, Gimp.PDBStatusType.SUCCESS)
+    ])
 
 
 class ColorXhtml(Gimp.PlugIn):
diff --git a/plug-ins/python/file-openraster.py b/plug-ins/python/file-openraster.py
index 7b292721d7..2f2ef40623 100755
--- a/plug-ins/python/file-openraster.py
+++ b/plug-ins/python/file-openraster.py
@@ -91,25 +91,24 @@ def thumbnail_ora(procedure, file, thumb_size, args, data):
     with open(tmp, 'wb') as fid:
         fid.write(orafile.read('Thumbnails/thumbnail.png'))
 
-    args = Gimp.ValueArray.new(2)
-    args.insert(0, GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE))
-    args.insert(1, GObject.Value(GObject.TYPE_STRING, tmp))
-    img = Gimp.get_pdb().run_procedure('file-png-load', args)
+    img = Gimp.get_pdb().run_procedure('file-png-load', [
+        GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE),
+        GObject.Value(GObject.TYPE_STRING, tmp),
+    ])
     img = img.index(1)
     img = Gimp.Image.get_by_id(img)
     # TODO: scaling
     os.remove(tmp)
     os.rmdir(tempdir)
 
-    retval = Gimp.ValueArray.new(2)
-    retval.insert(0, GObject.Value(Gimp.PDBStatusType, Gimp.PDBStatusType.SUCCESS))
-    retval.insert(1, GObject.Value(Gimp.Image, img))
-    retval.insert(2, GObject.Value(GObject.TYPE_INT, w))
-    retval.insert(3, GObject.Value(GObject.TYPE_INT, h))
-    retval.insert(4, GObject.Value(Gimp.ImageType, Gimp.ImageType.RGB_IMAGE))
-    retval.insert(5, GObject.Value(GObject.TYPE_INT, 1))
-
-    return retval
+    return Gimp.ValueArray.new_from_values([
+        GObject.Value(Gimp.PDBStatusType, Gimp.PDBStatusType.SUCCESS),
+        GObject.Value(Gimp.Image, img),
+        GObject.Value(GObject.TYPE_INT, w),
+        GObject.Value(GObject.TYPE_INT, h),
+        GObject.Value(Gimp.ImageType, Gimp.ImageType.RGB_IMAGE),
+        GObject.Value(GObject.TYPE_INT, 1)
+    ])
 
 def save_ora(procedure, run_mode, image, drawable, file, args, data):
     def write_file_str(zfile, fname, data):
@@ -137,20 +136,21 @@ def save_ora(procedure, run_mode, image, drawable, file, args, data):
     def store_layer(image, drawable, path):
         tmp = os.path.join(tempdir, 'tmp.png')
         interlace, compression = 0, 2
-        args = Gimp.ValueArray.new(11)
-        args.insert(0, GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE))
-        args.insert(1, GObject.Value(Gimp.Image, image))
-        args.insert(2, GObject.Value(Gimp.Drawable, drawable))
-        args.insert(3, GObject.Value(GObject.TYPE_STRING, tmp))
-        args.insert(4, GObject.Value(GObject.TYPE_STRING, 'tmp.png'))
-        args.insert(5, GObject.Value(GObject.TYPE_BOOLEAN, interlace))
-        args.insert(6, GObject.Value(GObject.TYPE_INT, compression))
-        # write all PNG chunks except oFFs(ets)
-        args.insert(7, GObject.Value(GObject.TYPE_BOOLEAN, True))
-        args.insert(8, GObject.Value(GObject.TYPE_BOOLEAN, True))
-        args.insert(9, GObject.Value(GObject.TYPE_BOOLEAN, False))
-        args.insert(10, GObject.Value(GObject.TYPE_BOOLEAN, True))
-        Gimp.get_pdb().run_procedure('file-png-save', args)
+
+        Gimp.get_pdb().run_procedure('file-png-save', [
+            GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE),
+            GObject.Value(Gimp.Image, image),
+            GObject.Value(Gimp.Drawable, drawable),
+            GObject.Value(GObject.TYPE_STRING, tmp),
+            GObject.Value(GObject.TYPE_STRING, 'tmp.png'),
+            GObject.Value(GObject.TYPE_BOOLEAN, interlace),
+            GObject.Value(GObject.TYPE_INT, compression),
+            # write all PNG chunks except oFFs(ets)
+            GObject.Value(GObject.TYPE_BOOLEAN, True),
+            GObject.Value(GObject.TYPE_BOOLEAN, True),
+            GObject.Value(GObject.TYPE_BOOLEAN, False),
+            GObject.Value(GObject.TYPE_BOOLEAN, True),
+        ])
         orafile.write(tmp, path)
         os.remove(tmp)
 
@@ -220,9 +220,9 @@ def save_ora(procedure, run_mode, image, drawable, file, args, data):
             add_layer(parent, x, y, opac, lay, path_name, lay.get_visible())
 
     # save mergedimage
-    args = Gimp.ValueArray.new(1)
-    args.insert(0, GObject.Value(Gimp.Image, image))
-    thumb = Gimp.get_pdb().run_procedure('gimp-image-duplicate', args)
+    thumb = Gimp.get_pdb().run_procedure('gimp-image-duplicate', [
+        GObject.Value(Gimp.Image, image),
+    ])
     thumb = thumb.index(1)
     thumb = Gimp.Image.get_by_id(thumb)
     thumb_layer = thumb.merge_visible_layers (Gimp.MergeType.CLIP_TO_IMAGE)
@@ -253,10 +253,9 @@ def save_ora(procedure, run_mode, image, drawable, file, args, data):
         os.remove(file.peek_path()) # win32 needs that
     os.rename(file.peek_path() + '.tmpsave', file.peek_path())
 
-    retval = Gimp.ValueArray.new(1)
-    retval.insert(0, GObject.Value(Gimp.PDBStatusType, Gimp.PDBStatusType.SUCCESS))
-
-    return retval
+    return Gimp.ValueArray.new_from_values([
+        GObject.Value(Gimp.PDBStatusType, Gimp.PDBStatusType.SUCCESS)
+    ])
 
 def load_ora(procedure, run_mode, file, args, data):
     tempdir = tempfile.mkdtemp('gimp-plugin-file-openraster')
@@ -312,14 +311,11 @@ def load_ora(procedure, run_mode, file, args, data):
                 fid.write(data)
 
             # import layer, set attributes and add to image
-            args = Gimp.ValueArray.new(3)
-            arg0 = GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE)
-            args.insert(0, arg0)
-            arg1 = GObject.Value(Gimp.Image, img)
-            args.insert(1, arg1)
-            arg2 = GObject.Value(GObject.TYPE_STRING, tmp)
-            args.insert(2, arg2)
-            gimp_layer = Gimp.get_pdb().run_procedure('gimp-file-load-layer', args)
+            gimp_layer = Gimp.get_pdb().run_procedure('gimp-file-load-layer', [
+                GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE),
+                GObject.Value(Gimp.Image, img),
+                GObject.Value(GObject.TYPE_STRING, tmp),
+            ])
             gimp_layer = gimp_layer.index(1)
             gimp_layer = Gimp.Item.get_by_id(gimp_layer)
             os.remove(tmp)
@@ -342,13 +338,10 @@ def load_ora(procedure, run_mode, file, args, data):
 
     os.rmdir(tempdir)
 
-    retval = Gimp.ValueArray.new(2)
-    arg0 = GObject.Value(Gimp.PDBStatusType, Gimp.PDBStatusType.SUCCESS)
-    retval.insert(0, arg0)
-    arg1 = GObject.Value(Gimp.Image, img)
-    retval.insert(1, arg1)
-
-    return retval
+    return Gimp.ValueArray.new_from_values([
+        GObject.Value(Gimp.PDBStatusType, Gimp.PDBStatusType.SUCCESS),
+        GObject.Value(Gimp.Image, img),
+    ])
 
 
 class FileOpenRaster (Gimp.PlugIn):
diff --git a/plug-ins/python/foggify.py b/plug-ins/python/foggify.py
index c7bcf9c939..7f26a11c66 100755
--- a/plug-ins/python/foggify.py
+++ b/plug-ins/python/foggify.py
@@ -58,13 +58,13 @@ def foggify(procedure, run_mode, image, drawable, args, data):
     fog.add_mask(mask)
 
     # add some clouds to the layer
-    args = Gimp.ValueArray.new(5)
-    args.insert(0, GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE))
-    args.insert(1, GObject.Value(Gimp.Image, image))
-    args.insert(2, GObject.Value(Gimp.Drawable, mask))
-    args.insert(3, GObject.Value(GObject.TYPE_INT, int(time.time())))
-    args.insert(4, GObject.Value(GObject.TYPE_DOUBLE, turbulence))
-    Gimp.get_pdb().run_procedure('plug-in-plasma', args)
+    Gimp.get_pdb().run_procedure('plug-in-plasma', [
+        GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE),
+        GObject.Value(Gimp.Image, image),
+        GObject.Value(Gimp.Drawable, mask),
+        GObject.Value(GObject.TYPE_INT, int(time.time())),
+        GObject.Value(GObject.TYPE_DOUBLE, turbulence),
+    ])
 
     # apply the clouds to the layer
     fog.remove_mask(Gimp.MaskApplyMode.APPLY)
diff --git a/plug-ins/python/spyro-plus.py b/plug-ins/python/spyro-plus.py
index 1710e559c7..cc82ab4c78 100644
--- a/plug-ins/python/spyro-plus.py
+++ b/plug-ins/python/spyro-plus.py
@@ -18,6 +18,8 @@
 import gi
 gi.require_version('Gimp', '3.0')
 from gi.repository import Gimp
+gi.require_version('GimpUi', '3.0')
+from gi.repository import GimpUi
 from gi.repository import GObject
 from gi.repository import GLib
 from gi.repository import Gio
@@ -38,18 +40,6 @@ import math
 import time
 
 
-def pdb_call(proc_name, *args):
-    if len(args) % 2 == 1:
-        raise ValueError("The number of arguments after proc_name needs to be even. ")
-
-    num_args = len(args) // 2
-    proc_args = Gimp.ValueArray.new(num_args)
-    for i in range(num_args):
-        proc_args.append(GObject.Value(args[2 * i], args[2 * i + 1]))
-
-    return Gimp.get_pdb().run_procedure(proc_name, proc_args)
-
-
 def result_success():
     return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())
 
@@ -386,11 +376,11 @@ class SelectionToPath:
         else:
             selection_was_empty = False
 
-        result = pdb_call('plug-in-sel2path',
-                          Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE,
-                          Gimp.Image, self.image,
-                          Gimp.Drawable, self.image.get_active_layer()
-        )
+        result = Gimp.get_pdb().run_procedure('plug-in-sel2path', [
+            GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE),
+            GObject.Value(Gimp.Image, self.image),
+            GObject.Value(Gimp.Drawable, self.image.get_active_layer()),
+        ])
 
         self.path = self.image.get_vectors()[0]
         self.stroke_ids = self.path.get_strokes()
@@ -1736,8 +1726,8 @@ class SpyroWindow():
         def create_ui():
 
             use_header_bar = Gtk.Settings.get_default().get_property("gtk-dialogs-use-header")
-            self.dialog = Gimp.Dialog(use_header_bar=use_header_bar,
-                                      title=_("Spyrogimp"))
+            self.dialog = GimpUi.Dialog(use_header_bar=use_header_bar,
+                                        title=_("Spyrogimp"))
             #self.set_default_size(350, -1)
             #self.set_border_width(10)
 
@@ -1746,7 +1736,7 @@ class SpyroWindow():
             self.dialog.get_content_area().add(vbox)
             vbox.show()
 
-            box = Gimp.HintBox.new(_("Draw spyrographs using current tool settings and selection."))
+            box = GimpUi.HintBox.new(_("Draw spyrographs using current tool settings and selection."))
             vbox.pack_start(box, False, False, 0)
             box.show()
 
@@ -1799,7 +1789,7 @@ class SpyroWindow():
         self.drawing_layer = self.spyro_layer
 
         # Create the UI.
-        Gimp.ui_init(sys.argv[0])
+        GimpUi.ui_init(sys.argv[0])
         create_ui()
         self.update_view()   # Update UI to reflect the parameter values.
 


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