[gobject-introspection] girepository: Use constant time calculation for sections after Object fields



commit df21d1f362a810f48a23b7c121bf09ce398539c7
Author: Simon Feltman <sfeltman src gnome org>
Date:   Thu Feb 27 17:10:19 2014 -0800

    girepository: Use constant time calculation for sections after Object fields
    
    Add "n_field_callbacks" to ObjectBlob which represents the number of object
    fields which are also callbacks. This a allows a constant time computation
    for accessing sections after fields. Track writing of this field by passing
    an extra argument through the girnode writers recursive call structure. This
    essentally reverts a portion of commit 7027bb256d0d1ab which added a linear
    time computation for accessing sections after fields.
    Update typelib validator to also ensure n_field_callbacks is properly set.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=700338

 girepository/giobjectinfo.c       |   35 +++++++++++---
 girepository/girmodule.c          |    2 +-
 girepository/girnode.c            |   92 ++++++++++++++++++++----------------
 girepository/girnode.h            |    3 +-
 girepository/gitypelib-internal.h |    5 +-
 girepository/gitypelib.c          |   17 ++++++-
 6 files changed, 101 insertions(+), 53 deletions(-)
---
diff --git a/girepository/giobjectinfo.c b/girepository/giobjectinfo.c
index 381f465..0991b80 100644
--- a/girepository/giobjectinfo.c
+++ b/girepository/giobjectinfo.c
@@ -342,7 +342,10 @@ g_object_info_get_property (GIObjectInfo *info,
   header = (Header *)rinfo->typelib->data;
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
-  offset = g_object_info_get_field_offset(info, blob->n_fields)
+  offset = rinfo->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size
+    + blob->n_field_callbacks * header->callback_blob_size
     + n * header->property_blob_size;
 
   return (GIPropertyInfo *) g_info_new (GI_INFO_TYPE_PROPERTY, (GIBaseInfo*)info,
@@ -397,7 +400,10 @@ g_object_info_get_method (GIObjectInfo *info,
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
 
-  offset = g_object_info_get_field_offset(info, blob->n_fields)
+  offset = rinfo->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size
+    + blob->n_field_callbacks * header->callback_blob_size
     + blob->n_properties * header->property_blob_size
     + n * header->function_blob_size;
 
@@ -431,7 +437,10 @@ g_object_info_find_method (GIObjectInfo *info,
   header = (Header *)rinfo->typelib->data;
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
-  offset = g_object_info_get_field_offset(info, blob->n_fields)
+  offset = rinfo->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size +
+    + blob->n_field_callbacks * header->callback_blob_size
     + blob->n_properties * header->property_blob_size;
 
   return _g_base_info_find_method ((GIBaseInfo*)info, offset, blob->n_methods, name);
@@ -541,7 +550,10 @@ g_object_info_get_signal (GIObjectInfo *info,
   header = (Header *)rinfo->typelib->data;
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
-  offset = g_object_info_get_field_offset(info, blob->n_fields)
+  offset = rinfo->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size
+    + blob->n_field_callbacks * header->callback_blob_size
     + blob->n_properties * header->property_blob_size
     + blob->n_methods * header->function_blob_size
     + n * header->signal_blob_size;
@@ -630,7 +642,10 @@ g_object_info_get_vfunc (GIObjectInfo *info,
   header = (Header *)rinfo->typelib->data;
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
-  offset = g_object_info_get_field_offset(info, blob->n_fields)
+  offset = rinfo->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size
+    + blob->n_field_callbacks * header->callback_blob_size
     + blob->n_properties * header->property_blob_size
     + blob->n_methods * header->function_blob_size
     + blob->n_signals * header->signal_blob_size
@@ -671,7 +686,10 @@ g_object_info_find_vfunc (GIObjectInfo *info,
   header = (Header *)rinfo->typelib->data;
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
-  offset = g_object_info_get_field_offset(info, blob->n_fields)
+  offset = rinfo->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size
+    + blob->n_field_callbacks * header->callback_blob_size
     + blob->n_properties * header->property_blob_size
     + blob->n_methods * header->function_blob_size
     + blob->n_signals * header->signal_blob_size;
@@ -786,7 +804,10 @@ g_object_info_get_constant (GIObjectInfo *info,
   header = (Header *)rinfo->typelib->data;
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
-  offset = g_object_info_get_field_offset(info, blob->n_fields)
+  offset = rinfo->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size
+    + blob->n_field_callbacks * header->callback_blob_size
     + blob->n_properties * header->property_blob_size
     + blob->n_methods * header->function_blob_size
     + blob->n_signals * header->signal_blob_size
diff --git a/girepository/girmodule.c b/girepository/girmodule.c
index e3897c3..66b33fa 100644
--- a/girepository/girmodule.c
+++ b/girepository/girmodule.c
@@ -508,7 +508,7 @@ _g_ir_module_build_typelib (GIrModule  *module)
          build.nodes_with_attributes = nodes_with_attributes;
          build.n_attributes = header->n_attributes;
          build.data = data;
-         _g_ir_node_build_typelib (node, NULL, &build, &offset, &offset2);
+         _g_ir_node_build_typelib (node, NULL, &build, &offset, &offset2, NULL);
 
          nodes_with_attributes = build.nodes_with_attributes;
          header->n_attributes = build.n_attributes;
diff --git a/girepository/girnode.c b/girepository/girnode.c
index d0a18a3..455e9d6 100644
--- a/girepository/girnode.c
+++ b/girepository/girnode.c
@@ -1326,7 +1326,8 @@ _g_ir_node_build_members (GList         **members,
                         GIrNode        *parent,
                          GIrTypelibBuild *build,
                         guint32        *offset,
-                        guint32        *offset2)
+                        guint32        *offset2,
+                        guint16        *count2)
 {
   GList *l = *members;
 
@@ -1338,7 +1339,7 @@ _g_ir_node_build_members (GList         **members,
       if (member->type == type)
        {
          (*count)++;
-         _g_ir_node_build_typelib (member, parent, build, offset, offset2);
+         _g_ir_node_build_typelib (member, parent, build, offset, offset2, count2);
          *members = g_list_delete_link (*members, l);
        }
       l = next;
@@ -1379,7 +1380,8 @@ _g_ir_node_build_typelib (GIrNode         *node,
                          GIrNode         *parent,
                          GIrTypelibBuild *build,
                          guint32         *offset,
-                         guint32         *offset2)
+                         guint32         *offset2,
+                         guint16         *count2)
 {
   gboolean appended_stack;
   GHashTable *strings = build->strings;
@@ -1480,7 +1482,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
                      *offset2 += sizeof (ArrayTypeBlob);
 
                      _g_ir_node_build_typelib ((GIrNode *)type->parameter_type1,
-                                              node, build, &pos, offset2);
+                                              node, build, &pos, offset2, NULL);
                    }
                    break;
 
@@ -1514,7 +1516,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
                      *offset2 += sizeof (ParamTypeBlob) + sizeof (SimpleTypeBlob);
 
                      _g_ir_node_build_typelib ((GIrNode *)type->parameter_type1,
-                                              node, build, &pos, offset2);
+                                              node, build, &pos, offset2, NULL);
                    }
                    break;
 
@@ -1533,9 +1535,9 @@ _g_ir_node_build_typelib (GIrNode         *node,
                      *offset2 += sizeof (ParamTypeBlob) + sizeof (SimpleTypeBlob)*2;
 
                      _g_ir_node_build_typelib ((GIrNode *)type->parameter_type1,
-                                              node, build, &pos, offset2);
+                                              node, build, &pos, offset2, NULL);
                      _g_ir_node_build_typelib ((GIrNode *)type->parameter_type2,
-                                              node, build, &pos, offset2);
+                                              node, build, &pos, offset2, NULL);
                    }
                    break;
 
@@ -1585,7 +1587,14 @@ _g_ir_node_build_typelib (GIrNode         *node,
             blob->type.offset = GI_INFO_TYPE_CALLBACK;
            *offset += sizeof (FieldBlob);
             _g_ir_node_build_typelib ((GIrNode *)field->callback,
-                                    node, build, offset, offset2);
+                                    node, build, offset, offset2, NULL);
+            /* Fields with callbacks are bigger than normal, update count2
+             * as an extra hint which represents the number of fields which are
+             * callbacks. This allows us to gain constant time performance in the
+             * repository for skipping over the fields section.
+             */
+            if (count2)
+              (*count2)++;
           }
         else
           {
@@ -1593,7 +1602,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
             /* We handle the size member specially below, so subtract it */
            *offset += sizeof (FieldBlob) - sizeof (SimpleTypeBlob);
             _g_ir_node_build_typelib ((GIrNode *)field->type,
-                                    node, build, offset, offset2);
+                                    node, build, offset, offset2, NULL);
           }
       }
       break;
@@ -1616,7 +1625,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
        blob->reserved = 0;
 
         _g_ir_node_build_typelib ((GIrNode *)prop->type,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
       }
       break;
 
@@ -1658,7 +1667,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
        g_debug ("building function '%s'", function->symbol);
 
         _g_ir_node_build_typelib ((GIrNode *)function->result->type,
-                                node, build, &signature, offset2);
+                                node, build, &signature, offset2, NULL);
 
        blob2->may_return_null = function->result->nullable;
        blob2->caller_owns_return_value = function->result->transfer;
@@ -1675,7 +1684,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
          {
            GIrNode *param = (GIrNode *)l->data;
 
-           _g_ir_node_build_typelib (param, node, build, &signature, offset2);
+           _g_ir_node_build_typelib (param, node, build, &signature, offset2, NULL);
          }
 
       }
@@ -1702,7 +1711,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
        blob->signature = signature;
 
         _g_ir_node_build_typelib ((GIrNode *)function->result->type,
-                                node, build, &signature, offset2);
+                                node, build, &signature, offset2, NULL);
 
        blob2->may_return_null = function->result->nullable;
        blob2->caller_owns_return_value = function->result->transfer;
@@ -1717,7 +1726,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
          {
            GIrNode *param = (GIrNode *)l->data;
 
-           _g_ir_node_build_typelib (param, node, build, &signature, offset2);
+           _g_ir_node_build_typelib (param, node, build, &signature, offset2, NULL);
          }
       }
       break;
@@ -1760,7 +1769,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
         ((GIrNode *) signal->result)->offset = signature;
 
         _g_ir_node_build_typelib ((GIrNode *)signal->result->type,
-                                node, build, &signature, offset2);
+                                node, build, &signature, offset2, NULL);
 
        blob2->may_return_null = signal->result->nullable;
        blob2->caller_owns_return_value = signal->result->transfer;
@@ -1775,7 +1784,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
          {
            GIrNode *param = (GIrNode *)l->data;
 
-           _g_ir_node_build_typelib (param, node, build, &signature, offset2);
+           _g_ir_node_build_typelib (param, node, build, &signature, offset2, NULL);
          }
       }
       break;
@@ -1819,7 +1828,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
        blob->signature = signature;
 
         _g_ir_node_build_typelib ((GIrNode *)vfunc->result->type,
-                                node, build, &signature, offset2);
+                                node, build, &signature, offset2, NULL);
 
        blob2->may_return_null = vfunc->result->nullable;
        blob2->caller_owns_return_value = vfunc->result->transfer;
@@ -1835,7 +1844,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
          {
            GIrNode *param = (GIrNode *)l->data;
 
-           _g_ir_node_build_typelib (param, node, build, &signature, offset2);
+           _g_ir_node_build_typelib (param, node, build, &signature, offset2, NULL);
          }
       }
       break;
@@ -1865,7 +1874,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
         blob->closure = param->closure;
         blob->destroy = param->destroy;
 
-        _g_ir_node_build_typelib ((GIrNode *)param->type, node, build, offset, offset2);
+        _g_ir_node_build_typelib ((GIrNode *)param->type, node, build, offset, offset2, NULL);
       }
       break;
 
@@ -1905,10 +1914,10 @@ _g_ir_node_build_typelib (GIrNode         *node,
        members = g_list_copy (struct_->members);
 
        _g_ir_node_build_members (&members, G_IR_NODE_FIELD, &blob->n_fields,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        _g_ir_node_build_members (&members, G_IR_NODE_FUNCTION, &blob->n_methods,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        _g_ir_node_check_unhandled_members (&members, node->type);
 
@@ -1940,10 +1949,10 @@ _g_ir_node_build_typelib (GIrNode         *node,
        members = g_list_copy (boxed->members);
 
        _g_ir_node_build_members (&members, G_IR_NODE_FIELD, &blob->n_fields,
-                                 node, build, offset, offset2);
+                                 node, build, offset, offset2, NULL);
 
        _g_ir_node_build_members (&members, G_IR_NODE_FUNCTION, &blob->n_methods,
-                                 node, build, offset, offset2);
+                                 node, build, offset, offset2, NULL);
 
        _g_ir_node_check_unhandled_members (&members, node->type);
 
@@ -1988,7 +1997,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
            *offset += 28;
            blob->discriminated = TRUE;
            _g_ir_node_build_typelib ((GIrNode *)union_->discriminator_type,
-                                    build, offset, offset2);
+                                    build, offset, offset2, NULL);
          }
        else
          {
@@ -2000,10 +2009,10 @@ _g_ir_node_build_typelib (GIrNode         *node,
        members = g_list_copy (union_->members);
 
        _g_ir_node_build_members (&members, G_IR_NODE_FIELD, &blob->n_fields,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        _g_ir_node_build_members (&members, G_IR_NODE_FUNCTION, &blob->n_functions,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        _g_ir_node_check_unhandled_members (&members, node->type);
 
@@ -2015,7 +2024,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
              {
                GIrNode *member = (GIrNode *)l->data;
 
-               _g_ir_node_build_typelib (member, node, build, offset, offset2);
+               _g_ir_node_build_typelib (member, node, build, offset, offset2, NULL);
              }
          }
       }
@@ -2063,7 +2072,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
            GIrNode *value = (GIrNode *)l->data;
 
            blob->n_values++;
-           _g_ir_node_build_typelib (value, node, build, offset, offset2);
+           _g_ir_node_build_typelib (value, node, build, offset, offset2, NULL);
          }
 
        for (l = enum_->methods; l; l = l->next)
@@ -2071,7 +2080,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
            GIrNode *method = (GIrNode *)l->data;
 
            blob->n_methods++;
-           _g_ir_node_build_typelib (method, node, build, offset, offset2);
+           _g_ir_node_build_typelib (method, node, build, offset, offset2, NULL);
          }
       }
       break;
@@ -2114,6 +2123,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
        blob->n_signals = 0;
        blob->n_vfuncs = 0;
        blob->n_constants = 0;
+       blob->n_field_callbacks = 0;
 
        *offset += sizeof(ObjectBlob);
        for (l = object->interfaces; l; l = l->next)
@@ -2127,27 +2137,27 @@ _g_ir_node_build_typelib (GIrNode         *node,
 
        *offset = ALIGN_VALUE (*offset, 4);
        _g_ir_node_build_members (&members, G_IR_NODE_FIELD, &blob->n_fields,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, &blob->n_field_callbacks);
 
        *offset = ALIGN_VALUE (*offset, 4);
        _g_ir_node_build_members (&members, G_IR_NODE_PROPERTY, &blob->n_properties,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        *offset = ALIGN_VALUE (*offset, 4);
        _g_ir_node_build_members (&members, G_IR_NODE_FUNCTION, &blob->n_methods,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        *offset = ALIGN_VALUE (*offset, 4);
        _g_ir_node_build_members (&members, G_IR_NODE_SIGNAL, &blob->n_signals,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        *offset = ALIGN_VALUE (*offset, 4);
        _g_ir_node_build_members (&members, G_IR_NODE_VFUNC, &blob->n_vfuncs,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        *offset = ALIGN_VALUE (*offset, 4);
        _g_ir_node_build_members (&members, G_IR_NODE_CONSTANT, &blob->n_constants,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        _g_ir_node_check_unhandled_members (&members, node->type);
 
@@ -2190,23 +2200,23 @@ _g_ir_node_build_typelib (GIrNode         *node,
 
        *offset = ALIGN_VALUE (*offset, 4);
        _g_ir_node_build_members (&members, G_IR_NODE_PROPERTY, &blob->n_properties,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        *offset = ALIGN_VALUE (*offset, 4);
        _g_ir_node_build_members (&members, G_IR_NODE_FUNCTION, &blob->n_methods,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        *offset = ALIGN_VALUE (*offset, 4);
        _g_ir_node_build_members (&members, G_IR_NODE_SIGNAL, &blob->n_signals,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        *offset = ALIGN_VALUE (*offset, 4);
        _g_ir_node_build_members (&members, G_IR_NODE_VFUNC, &blob->n_vfuncs,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        *offset = ALIGN_VALUE (*offset, 4);
        _g_ir_node_build_members (&members, G_IR_NODE_CONSTANT, &blob->n_constants,
-                                node, build, offset, offset2);
+                                node, build, offset, offset2, NULL);
 
        _g_ir_node_check_unhandled_members (&members, node->type);
 
@@ -2298,7 +2308,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
          }
        *offset2 += ALIGN_VALUE (blob->size, 4);
 
-       _g_ir_node_build_typelib ((GIrNode *)constant->type, node, build, &pos, offset2);
+       _g_ir_node_build_typelib ((GIrNode *)constant->type, node, build, &pos, offset2, NULL);
       }
       break;
     default:
diff --git a/girepository/girnode.h b/girepository/girnode.h
index 02196e7..e4ce85a 100644
--- a/girepository/girnode.h
+++ b/girepository/girnode.h
@@ -358,7 +358,8 @@ void      _g_ir_node_build_typelib   (GIrNode         *node,
                                      GIrNode         *parent,
                                      GIrTypelibBuild *build,
                                      guint32         *offset,
-                                     guint32         *offset2);
+                                     guint32         *offset2,
+                                     guint16         *count2);
 int       _g_ir_node_cmp             (GIrNode    *node,
                                     GIrNode    *other);
 gboolean  _g_ir_node_can_have_member (GIrNode    *node);
diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h
index 5ccff71..0f10512 100644
--- a/girepository/gitypelib-internal.h
+++ b/girepository/gitypelib-internal.h
@@ -1051,7 +1051,8 @@ typedef struct {
  * @n_constants: The lengths of the arrays.Up to 16bits of padding may be
  *   inserted between the arrays to ensure that they start on a 32bit
  *   boundary.
- * @reserved2: Reserved for future use.
+ * @n_field_callbacks: The number of n_fields which are also callbacks.
+ *   This is used to calculate the fields section size in constant time.
  * @ref_func: String pointing to a function which can be called to increase
  *   the reference count for an instance of this object type.
  * @unref_func: String pointing to a function which can be called to decrease
@@ -1088,7 +1089,7 @@ typedef struct {
   guint16   n_signals;
   guint16   n_vfuncs;
   guint16   n_constants;
-  guint16   reserved2;
+  guint16   n_field_callbacks;
 
   guint32   ref_func;
   guint32   unref_func;
diff --git a/girepository/gitypelib.c b/girepository/gitypelib.c
index 09e74f1..8ae4b44 100644
--- a/girepository/gitypelib.c
+++ b/girepository/gitypelib.c
@@ -1645,6 +1645,7 @@ validate_object_blob (ValidateContext *ctx,
   ObjectBlob *blob;
   gint i;
   guint32 offset2;
+  guint16 n_field_callbacks;
 
   header = (Header *)typelib->data;
 
@@ -1774,6 +1775,7 @@ validate_object_blob (ValidateContext *ctx,
 
   push_context (ctx, get_string_nofail (typelib, blob->name));
 
+  n_field_callbacks = 0;
   for (i = 0; i < blob->n_fields; i++)
     {
       FieldBlob *blob = (FieldBlob*) &typelib->data[offset2];
@@ -1783,8 +1785,21 @@ validate_object_blob (ValidateContext *ctx,
 
       offset2 += sizeof (FieldBlob);
       /* Special case fields which are callbacks. */
-      if (blob->has_embedded_type)
+      if (blob->has_embedded_type) {
         offset2 += sizeof (CallbackBlob);
+        n_field_callbacks++;
+      }
+    }
+
+  if (blob->n_field_callbacks != n_field_callbacks)
+    {
+      g_set_error (error,
+                   G_TYPELIB_ERROR,
+                   G_TYPELIB_ERROR_INVALID_BLOB,
+                   "Incorrect number of field callbacks; expected "
+                   G_GUINT16_FORMAT ", got " G_GUINT16_FORMAT,
+                   blob->n_field_callbacks, n_field_callbacks);
+      return FALSE;
     }
 
   for (i = 0; i < blob->n_properties; i++, offset2 += sizeof (PropertyBlob))


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