Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

TAO_Singleton_Manager Class Reference

Manager for TAO library services and singleton cleanup. More...

#include <TAO_Singleton_Manager.h>

Inheritance diagram for TAO_Singleton_Manager:

Inheritance graph
[legend]
Collaboration diagram for TAO_Singleton_Manager:

Collaboration graph
[legend]
List of all members.

Public Types

enum  Preallocated_Object { TAO_EMPTY_PREALLOCATED_OBJECT, TAO_PREALLOCATED_OBJECTS }
 Unique identifiers for preallocated Objects. More...


Public Methods

virtual int init (void)
 Explicitly initialize. More...

int init (int register_with_object_manager)
virtual int fini (void)
 Explicitly destroy. More...

void _set_unexpected (TAO_unexpected_handler u)
 Set a new unexpected exception handler. More...


Static Public Methods

int starting_up (void)
int shutting_down (void)
 Returns 1 after the TAO_Singleton_Manager has been destroyed. See ACE_Object_Manager::shutting_down for more information. More...

sigset_t * default_mask (void)
 Accesses a default signal set used, for example, in ACE_Sig_Guard methods. More...

ACE_Thread_Hookthread_hook (void)
 Returns the current thread hook for the process. More...

ACE_Thread_Hookthread_hook (ACE_Thread_Hook *new_thread_hook)
 Returns the existing thread hook and assign a new_thread_hook. More...

TAO_Singleton_Manager * instance (void)
 Accessor to singleton instance. More...

int at_exit (ACE_Cleanup *object, void *param=0)
 Register an ACE_Cleanup object for cleanup at process termination. More...

int at_exit (void *object, ACE_CLEANUP_FUNC cleanup_hook, void *param)
 Register an object (or array) for cleanup at process termination. More...


Private Methods

int at_exit_i (void *object, ACE_CLEANUP_FUNC cleanup_hook, void *param)
 Register an object or array for deletion at program termination. See description of static version above for return values. More...

 TAO_Singleton_Manager (void)
 ~TAO_Singleton_Manager (void)
 TAO_Singleton_Manager (const TAO_Singleton_Manager &)
TAO_Singleton_Manager & operator= (const TAO_Singleton_Manager &)

Private Attributes

sigset_t * default_mask_
 Default signal set used, for example, in ACE_Sig_Guard. More...

ACE_Thread_Hookthread_hook_
 Thread hook that's used by this process. More...

ACE_OS_Exit_Info exit_info_
 For at_exit support. More...

int registered_with_object_manager_
 Indicates if TAO_Singleton_Manager is registered with the ACE_Object_Manager. More...

TAO_unexpected_handler old_unexpected_
 The old unexpected exception handler. More...


Static Private Attributes

TAO_Singleton_Manager * instance_ = 0
 Singleton instance pointer. More...

void * preallocated_object [TAO_PREALLOCATED_OBJECTS] = { 0 }
 Table of preallocated objects. More...


Friends

void TAO_Singleton_Manager_cleanup_destroyer (void *, void *)
 Adapter for cleanup, used to register cleanup function with the ACE_Object_Manager. More...


Detailed Description

Manager for TAO library services and singleton cleanup.

The TAO_Singleton_Manager is basically simplified version of the ACE_Object_Manager. It is designed specifically to manage singletons created by TAO. For example, singleton instances created by TAO will be automatically registered with the singleton instance of this Singleton Manager.

This class is necessary to ensure that TAO-specific singletons are isolated to TAO itself, not ACE, for example. The idea is that destruction of the instance of the TAO_Singleton_Manager triggers destruction of all objects/services registered with it.

Definition at line 62 of file TAO_Singleton_Manager.h.


Member Enumeration Documentation

enum TAO_Singleton_Manager::Preallocated_Object
 

Unique identifiers for preallocated Objects.

Enumeration values:
TAO_EMPTY_PREALLOCATED_OBJECT  Without ACE_MT_SAFE, There are no preallocated objects. Make sure that the preallocated_array size is at least one by declaring this dummy ...
TAO_PREALLOCATED_OBJECTS  This enum value must be last!

Definition at line 93 of file TAO_Singleton_Manager.h.

00094     {
00095 # if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
00096       /// @@ No MT-specific preallocated objects (yet).  Remove the
00097       ///    below dummy enum once a preallocated object is added.
00098       TAO_EMPTY_PREALLOCATED_OBJECT,
00099 # else
00100       /// Without ACE_MT_SAFE, There are no preallocated objects.
00101       /// Make sure that the preallocated_array size is at least one
00102       /// by declaring this dummy ...
00103       TAO_EMPTY_PREALLOCATED_OBJECT,
00104 # endif /* ACE_MT_SAFE */
00105 
00106       /// This enum value must be last!
00107       TAO_PREALLOCATED_OBJECTS
00108     };


Constructor & Destructor Documentation

TAO_Singleton_Manager::TAO_Singleton_Manager void    [private]
 

Definition at line 48 of file TAO_Singleton_Manager.cpp.

References TAO_SYNCH_RECURSIVE_MUTEX.

00050   : thread_hook_ (0),
00051     exit_info_ (),
00052     registered_with_object_manager_ (-1)
00053 #if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
00054     , internal_lock_ (new TAO_SYNCH_RECURSIVE_MUTEX)
00055 # endif /* ACE_MT_SAFE */
00056 #if defined (ACE_HAS_EXCEPTIONS)
00057     , old_unexpected_ (0)
00058 #endif  /* ACE_HAS_EXCEPTIONS */
00059 {
00060   // Be sure that no further instances are created via instance ().
00061   if (instance_ == 0)
00062     instance_ = this;
00063 
00064   // @@ This is a hack.  Allow the TAO_Singleton_Manager to be registered
00065   //    with the ACE_Object_Manager (or not) in an explicit call to
00066   //    TAO_Singleton_Manager::init().  However, once the explicit call is
00067   //    made, it will not be possible to alter the setting.
00068   int register_with_object_manager = -1;
00069   (void) this->init (register_with_object_manager);
00070 }

TAO_Singleton_Manager::~TAO_Singleton_Manager void    [private]
 

Definition at line 72 of file TAO_Singleton_Manager.cpp.

References ACE_Object_Manager_Base::dynamically_allocated_, and fini.

00073 {
00074   this->dynamically_allocated_ = 0;   // Don't delete this again in fini()
00075   (void) this->fini ();
00076 }

TAO_Singleton_Manager::TAO_Singleton_Manager const TAO_Singleton_Manager &    [private]
 


Member Function Documentation

void TAO_Singleton_Manager::_set_unexpected TAO_unexpected_handler    u
 

Set a new unexpected exception handler.

The old one will be stored for restoration later on.

Note:
Calling this method multiple times will cause the stored old unexpected exception handler pointer to be lost.

Definition at line 303 of file TAO_Singleton_Manager.cpp.

References old_unexpected_, and TAO_unexpected_handler.

Referenced by CORBA_ORB::init_orb_globals.

00304 {
00305   // This must be done after the system TypeCodes and Exceptions have
00306   // been initialized.  An unexpected exception will cause TAO's
00307   // unexpected exception handler to be called.  That handler
00308   // transforms all unexpected exceptions to CORBA::UNKNOWN, which of
00309   // course requires the TypeCode constants and system exceptions to
00310   // have been initialized.
00311 # if (!defined (_MSC_VER) \
00312       && defined (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB) \
00313       && (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB != 0)) || defined (ghs)
00314   this->old_unexpected_ = std::set_unexpected (u);
00315 # else
00316   this->old_unexpected_ = set_unexpected (u);
00317 # endif  /* ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB */
00318 }

ACE_INLINE int TAO_Singleton_Manager::at_exit void *    object,
ACE_CLEANUP_FUNC    cleanup_hook,
void *    param
[static]
 

Register an object (or array) for cleanup at process termination.

cleanup_hook points to a (global, or static member) function that is called for the object or array when it to be destroyed. It may perform any necessary cleanup specific for that object or its class. param is passed as the second parameter to the cleanup_hook function; the first parameter is the object (or array) to be destroyed. cleanup_hook, for example, may delete the object (or array). For OS's that do not have processes, this function is the same as <at_thread_exit>. Returns 0 on success. On failure, returns -1 and sets errno to: EAGAIN if shutting down, ENOMEM if insufficient virtual memory, or EEXIST if the object (or array) had already been registered.

Definition at line 18 of file TAO_Singleton_Manager.inl.

References ACE_CLEANUP_FUNC, at_exit_i, and instance.

00021 {
00022   return TAO_Singleton_Manager::instance ()->at_exit_i (
00023     object,
00024     cleanup_hook,
00025     param);
00026 }

ACE_INLINE int TAO_Singleton_Manager::at_exit ACE_Cleanup   object,
void *    param = 0
[static]
 

Register an ACE_Cleanup object for cleanup at process termination.

The object is deleted via the ace_cleanup_destroyer. If you need more flexiblity, see the other at_exit method below. For OS's that do not have processes, cleanup takes place at the end of main. Returns 0 on success. On failure, returns -1 and sets errno to: EAGAIN if shutting down, ENOMEM if insufficient virtual memory, or EEXIST if the object (or array) had already been registered.

Definition at line 7 of file TAO_Singleton_Manager.inl.

References ACE_CLEANUP_FUNC, at_exit_i, and instance.

Referenced by TAO_TSS_Singleton::instance, and TAO_Singleton::instance.

00009 {
00010   return TAO_Singleton_Manager::instance ()->at_exit_i (
00011     object,
00012     (ACE_CLEANUP_FUNC) ace_cleanup_destroyer,
00013     param);
00014 }

int TAO_Singleton_Manager::at_exit_i void *    object,
ACE_CLEANUP_FUNC    cleanup_hook,
void *    param
[private]
 

Register an object or array for deletion at program termination. See description of static version above for return values.

Definition at line 322 of file TAO_Singleton_Manager.cpp.

References ACE_CLEANUP_FUNC, ACE_GUARD_RETURN, ACE_MT, ACE_OS_Exit_Info::at_exit_i, exit_info_, ACE_OS_Exit_Info::find, instance_, ACE_Object_Manager_Base::shutting_down_i, and TAO_SYNCH_RECURSIVE_MUTEX.

Referenced by at_exit.

00325 {
00326   ACE_MT (ACE_GUARD_RETURN (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon,
00327     *instance_->internal_lock_, -1));
00328 
00329   if (this->shutting_down_i ())
00330     {
00331       errno = EAGAIN;
00332       return -1;
00333     }
00334 
00335   if (this->exit_info_.find (object))
00336     {
00337       // The object has already been registered.
00338       errno = EEXIST;
00339       return -1;
00340     }
00341 
00342   return this->exit_info_.at_exit_i (object, cleanup_hook, param);
00343 }

sigset_t * TAO_Singleton_Manager::default_mask void    [static]
 

Accesses a default signal set used, for example, in ACE_Sig_Guard methods.

Definition at line 79 of file TAO_Singleton_Manager.cpp.

References default_mask_, and instance.

00080 {
00081   return TAO_Singleton_Manager::instance ()->default_mask_;
00082 }

int TAO_Singleton_Manager::fini void    [virtual]
 

Explicitly destroy.

Implements ACE_Object_Manager_Base.

Definition at line 205 of file TAO_Singleton_Manager.cpp.

References ACE_OS_Exit_Info::call_hooks, default_mask_, ACE_Object_Manager_Base::dynamically_allocated_, exit_info_, TAO_TypeCodes::fini, TAO_Exceptions::fini, ACE_Object_Manager_Base::fini, instance_, ACE_Object_Manager_Base::next_, ACE_Object_Manager_Base::OBJ_MAN_SHUT_DOWN, ACE_Object_Manager_Base::OBJ_MAN_SHUTTING_DOWN, ACE_Object_Manager_Base::object_manager_state_, and ACE_Object_Manager_Base::shutting_down_i.

Referenced by TAO_DLL_ORB::fini, TAO_Singleton_Manager_cleanup_destroyer, and ~TAO_Singleton_Manager.

00206 {
00207   if (instance_ == 0  ||  this->shutting_down_i ())
00208     // Too late.  Or, maybe too early.  Either fini () has already
00209     // been called, or init () was never called.
00210     return this->object_manager_state_ == OBJ_MAN_SHUT_DOWN  ?  1  :  -1;
00211 
00212   // No mutex here.  Only the main thread should destroy the singleton
00213   // TAO_Singleton_Manager instance.
00214 
00215   // Indicate that the TAO_Singleton_Manager instance is being shut
00216   // down.  This object manager should be the last one to be shut
00217   // down.
00218   this->object_manager_state_ = OBJ_MAN_SHUTTING_DOWN;
00219 
00220   // If another Object_Manager has registered for termination, do it.
00221   if (this->next_)
00222     {
00223       this->next_->fini ();
00224       this->next_ = 0;  // Protect against recursive calls.
00225     }
00226 
00227   // Call all registered cleanup hooks, in reverse order of
00228   // registration.
00229   this->exit_info_.call_hooks ();
00230 
00231   // Only clean up preallocated objects when the singleton Instance is being
00232   // destroyed.
00233   if (this == instance_)
00234     {
00235 #if ! defined (ACE_HAS_STATIC_PREALLOCATION)
00236       // Cleanup the dynamically preallocated objects.
00237 # if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
00238       // @@ No MT-specific preallocated objects yet.
00239 # endif  /* ACE_MT_SAFE */
00240       // @@ No preallocated objects yet.
00241 #endif  /* ! ACE_HAS_STATIC_PREALLOCATION */
00242     }
00243 
00244   delete this-> default_mask_;
00245   this->default_mask_ = 0;
00246 
00247 #if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
00248   delete this->internal_lock_;
00249   this->internal_lock_ = 0;
00250 #endif /* ACE_MT_SAFE */
00251 
00252 #if defined (ACE_HAS_EXCEPTIONS)
00253   // Restore the old unexpected exception handler since TAO will no
00254   // longer be handling exceptions.  Allow the application to once
00255   // again handle unexpected exceptions.
00256 # if (!defined (_MSC_VER) \
00257       && defined (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB) \
00258       && (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB != 0)) || defined (ghs)
00259   (void) std::set_unexpected (this->old_unexpected_);
00260 # else
00261   (void) set_unexpected (this->old_unexpected_);
00262 # endif  /* ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB */
00263 #endif /* ACE_HAS_EXCEPTIONS */
00264 
00265   // Indicate that this TAO_Singleton_Manager instance has been shut down.
00266   this->object_manager_state_ = OBJ_MAN_SHUT_DOWN;
00267 
00268   if (this == instance_)
00269     instance_ = 0;
00270 
00271   if (this->dynamically_allocated_)
00272     {
00273       delete this;
00274     }
00275 
00276   // Clean up all ORB owned Exceptions (before TypeCode clean up).
00277   TAO_Exceptions::fini ();
00278 
00279   // Clean up all ORB owned TypeCodes.
00280   TAO_TypeCodes::fini ();
00281 
00282   return 0;
00283 }

int TAO_Singleton_Manager::init int    register_with_object_manager
 

Explicitly initialize the TAO_Singleton_Manager, in addition to explicitly registering (or not registering) with the ACE_Object_Manager.

Definition at line 139 of file TAO_Singleton_Manager.cpp.

References ACE_CLEANUP_FUNC, ACE_NEW_RETURN, ACE_Object_Manager::at_exit, instance_, ACE_Object_Manager_Base::OBJ_MAN_INITIALIZED, ACE_Object_Manager_Base::OBJ_MAN_INITIALIZING, ACE_Object_Manager_Base::object_manager_state_, registered_with_object_manager_, ACE_OS::sigfillset, ACE_Object_Manager_Base::starting_up_i, and TAO_Singleton_Manager_cleanup_destroyer.

00140 {
00141   if (this->starting_up_i ())
00142     {
00143       // First, indicate that this TAO_Singleton_Manager instance is being
00144       // initialized.
00145       this->object_manager_state_ = OBJ_MAN_INITIALIZING;
00146 
00147       if (this == instance_)
00148         {
00149 # if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
00150           // @@ No MT-specific pre-allocated objects.
00151 # endif /* ACE_MT_SAFE */
00152         }
00153 
00154       ACE_NEW_RETURN (this->default_mask_, sigset_t, -1);
00155       ACE_OS::sigfillset (this->default_mask_);
00156 
00157       // Finally, indicate that the TAO_Singleton_Manager instance has
00158       // been initialized.
00159       this->object_manager_state_ = OBJ_MAN_INITIALIZED;
00160 
00161       return 0;
00162     }
00163 
00164   // @@ This strange looking code is what provides the "register on
00165   //    explicit call to init()" semantics.  This was needed since the
00166   //    TAO_Singleton_Manager constructor invokes init().
00167   //    Unfortunately, I couldn't get rid of that init() call without
00168   //    breaking things.  The fact things broke needs to be
00169   //    investigated further.
00170   if (this->registered_with_object_manager_ != -1
00171       && register_with_object_manager != this->registered_with_object_manager_)
00172     {
00173       // An attempt was made to register the TAO_Singleton_Manager
00174       // with a manager of a different type from the one it is
00175       // currently registered with.  This indicates a problem with the
00176       // caller's logic.
00177 
00178       errno = EINVAL;
00179       return -1;
00180     }
00181 
00182   if (this->registered_with_object_manager_ == -1)
00183     {
00184       if (register_with_object_manager == 1
00185           && ACE_Object_Manager::at_exit (
00186                this,
00187                (ACE_CLEANUP_FUNC) TAO_Singleton_Manager_cleanup_destroyer,
00188                0) != 0)
00189         return -1;
00190 
00191       this->registered_with_object_manager_ =
00192         register_with_object_manager;
00193     }
00194 
00195   // Had already initialized.
00196   return 1;
00197 }

int TAO_Singleton_Manager::init void    [virtual]
 

Explicitly initialize.

Implements ACE_Object_Manager_Base.

Definition at line 124 of file TAO_Singleton_Manager.cpp.

References registered_with_object_manager_.

Referenced by TAO_DLL_ORB::init.

00125 {
00126   if (this->registered_with_object_manager_ == -1)
00127     {
00128       // Register the TAO_Singleton_Manager with the
00129       // ACE_Object_Manager.
00130       int register_with_object_manager = 1;
00131 
00132       return this->init (register_with_object_manager);
00133     }
00134 
00135   return 1;  // Already initialized.
00136 }

TAO_Singleton_Manager * TAO_Singleton_Manager::instance void    [static]
 

Accessor to singleton instance.

Definition at line 100 of file TAO_Singleton_Manager.cpp.

References ACE_ASSERT, ACE_NEW_RETURN, ACE_Object_Manager_Base::dynamically_allocated_, and instance_.

Referenced by at_exit, default_mask, TAO_DLL_ORB::fini, TAO_DLL_ORB::init, CORBA_ORB::init_orb_globals, TAO_Singleton_Manager_cleanup_destroyer, and thread_hook.

00101 {
00102   // This function should be called during construction of static
00103   // instances, or before any other threads have been created in the
00104   // process.  So, it's not thread safe.
00105 
00106   if (instance_ == 0)
00107     {
00108       TAO_Singleton_Manager *instance_pointer;
00109 
00110       ACE_NEW_RETURN (instance_pointer,
00111                       TAO_Singleton_Manager,
00112                       0);
00113       ACE_ASSERT (instance_pointer == instance_);
00114 
00115       instance_pointer->dynamically_allocated_ = 1;
00116 
00117       return instance_pointer;
00118     }
00119   else
00120     return instance_;
00121 }

TAO_Singleton_Manager& TAO_Singleton_Manager::operator= const TAO_Singleton_Manager &    [private]
 

int TAO_Singleton_Manager::shutting_down void    [static]
 

Returns 1 after the TAO_Singleton_Manager has been destroyed. See ACE_Object_Manager::shutting_down for more information.

Definition at line 294 of file TAO_Singleton_Manager.cpp.

References instance_, and ACE_Object_Manager_Base::shutting_down_i.

Referenced by TAO_TSS_Singleton::instance, and TAO_Singleton::instance.

00295 {
00296   return TAO_Singleton_Manager::instance_
00297     ? instance_->shutting_down_i ()
00298     : 1;
00299 }

int TAO_Singleton_Manager::starting_up void    [static]
 

Returns 1 before the TAO_Singleton_Manager has been constructed. See ACE_Object_Manager::starting_up for more information.

Definition at line 286 of file TAO_Singleton_Manager.cpp.

References instance_, and ACE_Object_Manager_Base::starting_up_i.

Referenced by TAO_TSS_Singleton::instance, and TAO_Singleton::instance.

00287 {
00288   return TAO_Singleton_Manager::instance_
00289     ? instance_->starting_up_i ()
00290     : 1;
00291 }

ACE_Thread_Hook * TAO_Singleton_Manager::thread_hook ACE_Thread_Hook   new_thread_hook [static]
 

Returns the existing thread hook and assign a new_thread_hook.

Definition at line 91 of file TAO_Singleton_Manager.cpp.

References instance, and thread_hook_.

00092 {
00093   TAO_Singleton_Manager *tao_om = TAO_Singleton_Manager::instance ();
00094   ACE_Thread_Hook *old_hook = tao_om->thread_hook_;
00095   tao_om->thread_hook_ = new_thread_hook;
00096   return old_hook;
00097 }

ACE_Thread_Hook * TAO_Singleton_Manager::thread_hook void    [static]
 

Returns the current thread hook for the process.

Definition at line 85 of file TAO_Singleton_Manager.cpp.

References instance, and thread_hook_.

00086 {
00087   return TAO_Singleton_Manager::instance ()->thread_hook_;
00088 }


Friends And Related Function Documentation

void TAO_Singleton_Manager_cleanup_destroyer void *   ,
void *   
[friend]
 

Adapter for cleanup, used to register cleanup function with the ACE_Object_Manager.

Definition at line 37 of file TAO_Singleton_Manager.cpp.

Referenced by init.

00038 {
00039   if (TAO_Singleton_Manager::instance_)
00040     (void) TAO_Singleton_Manager::instance ()->fini ();
00041 }


Member Data Documentation

sigset_t* TAO_Singleton_Manager::default_mask_ [private]
 

Default signal set used, for example, in ACE_Sig_Guard.

Definition at line 194 of file TAO_Singleton_Manager.h.

Referenced by default_mask, and fini.

ACE_OS_Exit_Info TAO_Singleton_Manager::exit_info_ [private]
 

For at_exit support.

Definition at line 200 of file TAO_Singleton_Manager.h.

Referenced by at_exit_i, and fini.

TAO_Singleton_Manager * TAO_Singleton_Manager::instance_ = 0 [static, private]
 

Singleton instance pointer.

Definition at line 43 of file TAO_Singleton_Manager.cpp.

Referenced by at_exit_i, fini, init, instance, shutting_down, and starting_up.

TAO_unexpected_handler TAO_Singleton_Manager::old_unexpected_ [private]
 

The old unexpected exception handler.

A pointer to the old unexpected exception handler is stored so that it can be restored when TAO is unloaded, for example. Otherwise, any unexpected exceptions will result in a call to TAO's unexpected exception handler which may no longer exist if TAO was unloaded.

Definition at line 220 of file TAO_Singleton_Manager.h.

Referenced by _set_unexpected.

void * TAO_Singleton_Manager::preallocated_object = { 0 } [static, private]
 

Table of preallocated objects.

Definition at line 46 of file TAO_Singleton_Manager.cpp.

int TAO_Singleton_Manager::registered_with_object_manager_ [private]
 

Indicates if TAO_Singleton_Manager is registered with the ACE_Object_Manager.

Definition at line 204 of file TAO_Singleton_Manager.h.

Referenced by init.

ACE_Thread_Hook* TAO_Singleton_Manager::thread_hook_ [private]
 

Thread hook that's used by this process.

Definition at line 197 of file TAO_Singleton_Manager.h.

Referenced by thread_hook.


The documentation for this class was generated from the following files:
Generated on Mon Jun 16 15:39:35 2003 for TAO by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002