2003-07-28 16:44:57 -04:00
/////////////////////////////////////////////////////////////////////////////
// Name: wx/xtistrm.h
// Purpose: streaming runtime metadata information (extended class info)
// Author: Stefan Csomor
2004-09-24 10:32:35 -04:00
// Modified by:
2003-07-28 16:44:57 -04:00
// Created: 27/07/03
// RCS-ID: $Id$
// Copyright: (c) 2003 Stefan Csomor
2004-05-23 16:53:33 -04:00
// Licence: wxWindows licence
2003-07-28 16:44:57 -04:00
/////////////////////////////////////////////////////////////////////////////
# ifndef _WX_XTISTRMH__
# define _WX_XTISTRMH__
# include "wx/wx.h"
# if wxUSE_EXTENDED_RTTI
2003-08-05 13:24:02 -04:00
const int wxInvalidObjectID = - 2 ;
2003-09-04 12:18:07 -04:00
const int wxNullObjectID = - 3 ;
2003-08-05 13:24:02 -04:00
2003-07-28 16:44:57 -04:00
// Filer contains the interfaces for streaming objects in and out of XML,
// rendering them either to objects in memory, or to code. Note: We
// consider the process of generating code to be one of *depersisting* the
// object from xml, *not* of persisting the object to code from an object
// in memory. This distincation can be confusing, and should be kept
// in mind when looking at the property streamers and callback interfaces
// listed below.
/*
2003-08-08 16:35:19 -04:00
Main interfaces for streaming out objects .
2003-07-28 16:44:57 -04:00
*/
2003-08-13 12:59:46 -04:00
// ----------------------------------------------------------------------------
// wxPersister
//
// This class will be asked during the streaming-out process about every single
// property or object instance. It can veto streaming out by returning false
// or modify the value before it is streamed-out.
// ----------------------------------------------------------------------------
2003-08-24 11:22:07 -04:00
class WXDLLIMPEXP_BASE wxWriter ;
class WXDLLIMPEXP_BASE wxReader ;
2003-08-13 12:59:46 -04:00
2003-08-24 11:22:07 -04:00
class WXDLLIMPEXP_BASE wxPersister
2003-08-08 16:35:19 -04:00
{
public :
2007-04-11 06:32:01 -04:00
virtual ~ wxPersister ( ) { }
2003-08-13 12:59:46 -04:00
// will be called before an object is written, may veto by returning false
2004-09-24 10:32:35 -04:00
virtual bool BeforeWriteObject ( wxWriter * WXUNUSED ( writer ) , const wxObject * WXUNUSED ( object ) , const wxClassInfo * WXUNUSED ( classInfo ) , wxxVariantArray & WXUNUSED ( metadata ) ) { return true ; }
2003-08-13 12:59:46 -04:00
// will be called after this object has been written, may be needed for adjusting stacks
virtual void AfterWriteObject ( wxWriter * WXUNUSED ( writer ) , const wxObject * WXUNUSED ( object ) , const wxClassInfo * WXUNUSED ( classInfo ) ) { }
2003-08-08 16:35:19 -04:00
2004-09-24 10:32:35 -04:00
// will be called before a property gets written, may change the value , eg replace a concrete wxSize by wxSize( wxDefaultCoord , wxDefaultCoord ) or veto
2003-08-08 16:35:19 -04:00
// writing that property at all by returning false
2004-09-24 10:32:35 -04:00
virtual bool BeforeWriteProperty ( wxWriter * WXUNUSED ( writer ) , const wxObject * WXUNUSED ( object ) , const wxPropertyInfo * WXUNUSED ( propInfo ) , wxxVariant & WXUNUSED ( value ) ) { return true ; }
2003-08-08 16:35:19 -04:00
2004-09-24 10:32:35 -04:00
// will be called before a property gets written, may change the value , eg replace a concrete wxSize by wxSize( wxDefaultCoord , wxDefaultCoord ) or veto
2003-08-08 16:35:19 -04:00
// writing that property at all by returning false
2004-09-24 10:32:35 -04:00
virtual bool BeforeWriteProperty ( wxWriter * WXUNUSED ( writer ) , const wxObject * WXUNUSED ( object ) , const wxPropertyInfo * WXUNUSED ( propInfo ) , wxxVariantArray & WXUNUSED ( value ) ) { return true ; }
2003-08-13 12:59:46 -04:00
// will be called after a property has been written out, may be needed for adjusting stacks
virtual void AfterWriteProperty ( wxWriter * WXUNUSED ( writer ) , const wxPropertyInfo * WXUNUSED ( propInfo ) ) { }
// will be called before this delegate gets written
2004-09-24 10:32:35 -04:00
virtual bool BeforeWriteDelegate ( wxWriter * WXUNUSED ( writer ) , const wxObject * WXUNUSED ( object ) , const wxClassInfo * WXUNUSED ( classInfo ) , const wxPropertyInfo * WXUNUSED ( propInfo ) ,
const wxObject * & WXUNUSED ( eventSink ) , const wxHandlerInfo * & WXUNUSED ( handlerInfo ) ) { return true ; }
2003-08-08 16:35:19 -04:00
2004-09-24 10:32:35 -04:00
virtual void AfterWriteDelegate ( wxWriter * WXUNUSED ( writer ) , const wxObject * WXUNUSED ( object ) , const wxClassInfo * WXUNUSED ( classInfo ) , const wxPropertyInfo * WXUNUSED ( propInfo ) ,
const wxObject * & WXUNUSED ( eventSink ) , const wxHandlerInfo * & WXUNUSED ( handlerInfo ) ) { }
2003-08-08 16:35:19 -04:00
} ;
2003-08-24 11:22:07 -04:00
class WXDLLIMPEXP_BASE wxWriter : public wxObject
2003-08-08 16:35:19 -04:00
{
public :
wxWriter ( ) ;
2006-09-05 16:47:48 -04:00
virtual ~ wxWriter ( ) ;
2003-08-08 16:35:19 -04:00
// with this call you start writing out a new top-level object
2003-08-21 16:27:46 -04:00
void WriteObject ( const wxObject * object , const wxClassInfo * classInfo , wxPersister * persister , const wxString & name , wxxVariantArray & WXUNUSED ( metadata ) ) ;
2003-08-08 16:35:19 -04:00
2003-08-13 12:59:46 -04:00
//
// Managing the object identity table a.k.a context
//
2004-09-24 10:32:35 -04:00
// these methods make sure that no object gets written twice, because sometimes multiple calls to the WriteObject will be
2003-08-13 12:59:46 -04:00
// made without wanting to have duplicate objects written, the object identity table will be reset manually
virtual void ClearObjectContext ( ) ;
2003-08-24 08:22:08 -04:00
2003-08-13 12:59:46 -04:00
// gets the object Id for a passed in object in the context
2003-08-08 16:35:19 -04:00
int GetObjectID ( const wxObject * obj ) ;
2003-08-13 12:59:46 -04:00
// returns true if this object has already been written in this context
bool IsObjectKnown ( const wxObject * obj ) ;
2003-08-08 16:35:19 -04:00
//
// streaming callbacks
//
// these callbacks really write out the values in the stream format
2003-08-13 12:59:46 -04:00
// begins writing out a new toplevel entry which has the indicated unique name
virtual void DoBeginWriteTopLevelEntry ( const wxString & name ) = 0 ;
// ends writing out a new toplevel entry which has the indicated unique name
virtual void DoEndWriteTopLevelEntry ( const wxString & name ) = 0 ;
// start of writing an object having the passed in ID
2003-08-21 16:27:46 -04:00
virtual void DoBeginWriteObject ( const wxObject * object , const wxClassInfo * classInfo , int objectID , wxxVariantArray & metadata ) = 0 ;
2003-08-08 16:35:19 -04:00
// end of writing an toplevel object name param is used for unique identification within the container
2003-08-13 12:59:46 -04:00
virtual void DoEndWriteObject ( const wxObject * object , const wxClassInfo * classInfo , int objectID ) = 0 ;
// writes a simple property in the stream format
virtual void DoWriteSimpleType ( wxxVariant & value ) = 0 ;
2003-08-08 16:35:19 -04:00
2003-08-13 12:59:46 -04:00
// start of writing a complex property into the stream (
virtual void DoBeginWriteProperty ( const wxPropertyInfo * propInfo ) = 0 ;
2003-08-08 16:35:19 -04:00
2003-08-13 12:59:46 -04:00
// end of writing a complex property into the stream
virtual void DoEndWriteProperty ( const wxPropertyInfo * propInfo ) = 0 ;
2003-08-08 16:35:19 -04:00
2003-08-13 12:59:46 -04:00
virtual void DoBeginWriteElement ( ) = 0 ;
virtual void DoEndWriteElement ( ) = 0 ;
2004-09-24 10:32:35 -04:00
// insert an object reference to an already written object
2003-08-13 12:59:46 -04:00
virtual void DoWriteRepeatedObject ( int objectID ) = 0 ;
2003-08-08 16:35:19 -04:00
2003-08-13 12:59:46 -04:00
// insert a null reference
virtual void DoWriteNullObject ( ) = 0 ;
2003-08-08 16:35:19 -04:00
// writes a delegate in the stream format
2004-09-24 10:32:35 -04:00
virtual void DoWriteDelegate ( const wxObject * object , const wxClassInfo * classInfo , const wxPropertyInfo * propInfo ,
2003-08-08 16:35:19 -04:00
const wxObject * eventSink , int sinkObjectID , const wxClassInfo * eventSinkClassInfo , const wxHandlerInfo * handlerIndo ) = 0 ;
private :
struct wxWriterInternal ;
wxWriterInternal * m_data ;
struct wxWriterInternalPropertiesData ;
void WriteAllProperties ( const wxObject * obj , const wxClassInfo * ci , wxPersister * persister , wxWriterInternalPropertiesData * data ) ;
2003-08-22 20:37:55 -04:00
void WriteOneProperty ( const wxObject * obj , const wxClassInfo * ci , const wxPropertyInfo * pi , wxPersister * persister , wxWriterInternalPropertiesData * data ) ;
2003-08-21 16:27:46 -04:00
void WriteObject ( const wxObject * object , const wxClassInfo * classInfo , wxPersister * persister , bool isEmbedded , wxxVariantArray & metadata ) ;
2003-08-23 15:40:04 -04:00
void FindConnectEntry ( const wxEvtHandler * evSource , const wxDelegateTypeInfo * dti , const wxObject * & sink , const wxHandlerInfo * & handler ) ;
2003-08-08 16:35:19 -04:00
} ;
2003-07-28 16:44:57 -04:00
/*
2003-08-05 13:24:02 -04:00
Streaming callbacks for depersisting XML to code , or running objects
2003-07-28 16:44:57 -04:00
*/
2003-08-24 11:22:07 -04:00
class WXDLLIMPEXP_BASE wxDepersister ;
2003-07-28 16:44:57 -04:00
/*
2003-08-05 13:24:02 -04:00
wxReader handles streaming in a class from a arbitrary format . While walking through
it issues calls out to interfaces to depersist the guts from the underlying storage format .
2003-07-28 16:44:57 -04:00
*/
2003-08-05 13:24:02 -04:00
2003-08-24 11:22:07 -04:00
class WXDLLIMPEXP_BASE wxReader : public wxObject
2003-07-28 16:44:57 -04:00
{
2003-08-05 13:24:02 -04:00
public :
wxReader ( ) ;
2006-09-05 16:47:48 -04:00
virtual ~ wxReader ( ) ;
2003-08-08 16:35:19 -04:00
2003-08-05 13:24:02 -04:00
// the only thing wxReader knows about is the class info by object ID
wxClassInfo * GetObjectClassInfo ( int objectID ) ;
bool HasObjectClassInfo ( int objectID ) ;
void SetObjectClassInfo ( int objectID , wxClassInfo * classInfo ) ;
2004-09-24 10:32:35 -04:00
// Reads the component the reader is pointed at from the underlying format.
2003-08-05 13:24:02 -04:00
// The return value is the root object ID, which can
// then be used to ask the depersister about that object
2003-09-04 12:18:07 -04:00
// if there was a problem you will get back wxInvalidObjectID and the current
// error log will carry the problems encoutered
2003-08-13 12:59:46 -04:00
virtual int ReadObject ( const wxString & name , wxDepersister * depersist ) = 0 ;
2003-08-05 13:24:02 -04:00
private :
2003-07-28 16:44:57 -04:00
struct wxReaderInternal ;
2003-08-05 13:24:02 -04:00
wxReaderInternal * m_data ;
} ;
// This abstract class matches the allocate-init/create model of creation of objects.
// At runtime, these will create actual instances, and manipulate them.
// When generating code, these will just create statements of C++
// code to create the objects.
2003-08-24 11:22:07 -04:00
class WXDLLIMPEXP_BASE wxDepersister
2003-07-28 16:44:57 -04:00
{
2003-08-05 13:24:02 -04:00
public :
2007-04-11 06:32:01 -04:00
virtual ~ wxDepersister ( ) { }
2003-08-05 13:24:02 -04:00
// allocate the new object on the heap, that object will have the passed in ID
2003-08-21 16:27:46 -04:00
virtual void AllocateObject ( int objectID , wxClassInfo * classInfo , wxxVariantArray & metadata ) = 0 ;
2003-08-05 13:24:02 -04:00
2003-08-14 14:03:06 -04:00
// initialize the already allocated object having the ID objectID with the Create method
2003-08-05 13:24:02 -04:00
// creation parameters which are objects are having their Ids passed in objectIDValues
// having objectId <> wxInvalidObjectID
2003-08-14 14:03:06 -04:00
virtual void CreateObject ( int objectID ,
const wxClassInfo * classInfo ,
int paramCount ,
2003-08-05 13:24:02 -04:00
wxxVariant * VariantValues ,
int * objectIDValues ,
2003-08-21 16:27:46 -04:00
const wxClassInfo * * objectClassInfos ,
wxxVariantArray & metadata ) = 0 ;
2003-08-05 13:24:02 -04:00
2003-08-25 19:29:55 -04:00
// construct the new object on the heap, that object will have the passed in ID (for objects that
// don't support allocate-create type of creation)
// creation parameters which are objects are having their Ids passed in objectIDValues
// having objectId <> wxInvalidObjectID
virtual void ConstructObject ( int objectID ,
const wxClassInfo * classInfo ,
int paramCount ,
wxxVariant * VariantValues ,
int * objectIDValues ,
const wxClassInfo * * objectClassInfos ,
wxxVariantArray & metadata ) = 0 ;
2003-08-14 14:03:06 -04:00
// destroy the heap-allocated object having the ID objectID, this may be used if an object
2003-08-05 13:24:02 -04:00
// is embedded in another object and set via value semantics, so the intermediate
// object can be destroyed after safely
2003-08-14 14:03:06 -04:00
virtual void DestroyObject ( int objectID , wxClassInfo * classInfo ) = 0 ;
2003-08-05 13:24:02 -04:00
// set the corresponding property
2003-08-14 14:03:06 -04:00
virtual void SetProperty ( int objectID ,
const wxClassInfo * classInfo ,
const wxPropertyInfo * propertyInfo ,
2003-08-05 13:24:02 -04:00
const wxxVariant & VariantValue ) = 0 ;
// sets the corresponding property (value is an object)
2003-08-14 14:03:06 -04:00
virtual void SetPropertyAsObject ( int objectID ,
const wxClassInfo * classInfo ,
const wxPropertyInfo * propertyInfo ,
2003-08-05 13:24:02 -04:00
int valueObjectId ) = 0 ;
2003-08-14 14:03:06 -04:00
// adds an element to a property collection
virtual void AddToPropertyCollection ( int objectID ,
const wxClassInfo * classInfo ,
const wxPropertyInfo * propertyInfo ,
const wxxVariant & VariantValue ) = 0 ;
// sets the corresponding property (value is an object)
virtual void AddToPropertyCollectionAsObject ( int objectID ,
const wxClassInfo * classInfo ,
const wxPropertyInfo * propertyInfo ,
int valueObjectId ) = 0 ;
2003-08-05 13:24:02 -04:00
// sets the corresponding event handler
2003-07-28 16:44:57 -04:00
virtual void SetConnect ( int EventSourceObjectID ,
2003-08-05 13:24:02 -04:00
const wxClassInfo * EventSourceClassInfo ,
2003-09-03 21:08:25 -04:00
const wxPropertyInfo * delegateInfo ,
2003-08-05 13:24:02 -04:00
const wxClassInfo * EventSinkClassInfo ,
const wxHandlerInfo * handlerInfo ,
int EventSinkObjectID ) = 0 ;
2003-07-28 16:44:57 -04:00
} ;
/*
2003-08-05 13:24:02 -04:00
wxRuntimeDepersister implements the callbacks that will depersist
an object into a running memory image , as opposed to writing
C + + initialization code to bring the object to life .
2003-07-28 16:44:57 -04:00
*/
2003-08-24 11:22:07 -04:00
class WXDLLIMPEXP_BASE wxRuntimeDepersister : public wxDepersister
2003-07-28 16:44:57 -04:00
{
2003-08-05 13:24:02 -04:00
struct wxRuntimeDepersisterInternal ;
wxRuntimeDepersisterInternal * m_data ;
public :
2003-08-24 09:27:56 -04:00
wxRuntimeDepersister ( ) ;
virtual ~ wxRuntimeDepersister ( ) ;
2003-08-05 13:24:02 -04:00
2004-09-24 10:32:35 -04:00
// returns the object having the corresponding ID fully constructed
2003-08-05 13:24:02 -04:00
wxObject * GetObject ( int objectID ) ;
// allocate the new object on the heap, that object will have the passed in ID
2003-08-21 16:27:46 -04:00
virtual void AllocateObject ( int objectID , wxClassInfo * classInfo ,
wxxVariantArray & metadata ) ;
2003-08-05 13:24:02 -04:00
2003-08-14 14:03:06 -04:00
// initialize the already allocated object having the ID objectID with the Create method
2003-08-05 13:24:02 -04:00
// creation parameters which are objects are having their Ids passed in objectIDValues
// having objectId <> wxInvalidObjectID
2003-08-14 14:03:06 -04:00
virtual void CreateObject ( int objectID ,
const wxClassInfo * classInfo ,
int paramCount ,
2003-08-05 13:24:02 -04:00
wxxVariant * VariantValues ,
int * objectIDValues ,
2003-08-21 16:27:46 -04:00
const wxClassInfo * * objectClassInfos ,
wxxVariantArray & metadata
2003-08-05 13:24:02 -04:00
) ;
2003-08-25 19:29:55 -04:00
// construct the new object on the heap, that object will have the passed in ID (for objects that
// don't support allocate-create type of creation)
// creation parameters which are objects are having their Ids passed in objectIDValues
// having objectId <> wxInvalidObjectID
virtual void ConstructObject ( int objectID ,
const wxClassInfo * classInfo ,
int paramCount ,
wxxVariant * VariantValues ,
int * objectIDValues ,
const wxClassInfo * * objectClassInfos ,
wxxVariantArray & metadata ) ;
2003-08-14 14:03:06 -04:00
// destroy the heap-allocated object having the ID objectID, this may be used if an object
2003-08-05 13:24:02 -04:00
// is embedded in another object and set via value semantics, so the intermediate
// object can be destroyed after safely
virtual void DestroyObject ( int objectID , wxClassInfo * classInfo ) ;
// set the corresponding property
virtual void SetProperty ( int objectID ,
const wxClassInfo * classInfo ,
const wxPropertyInfo * propertyInfo ,
const wxxVariant & variantValue ) ;
// sets the corresponding property (value is an object)
virtual void SetPropertyAsObject ( int objectId ,
const wxClassInfo * classInfo ,
const wxPropertyInfo * propertyInfo ,
int valueObjectId ) ;
2003-08-14 14:03:06 -04:00
// adds an element to a property collection
virtual void AddToPropertyCollection ( int objectID ,
const wxClassInfo * classInfo ,
const wxPropertyInfo * propertyInfo ,
const wxxVariant & VariantValue ) ;
// sets the corresponding property (value is an object)
virtual void AddToPropertyCollectionAsObject ( int objectID ,
const wxClassInfo * classInfo ,
const wxPropertyInfo * propertyInfo ,
int valueObjectId ) ;
2003-08-05 13:24:02 -04:00
// sets the corresponding event handler
virtual void SetConnect ( int eventSourceObjectID ,
const wxClassInfo * eventSourceClassInfo ,
2003-09-03 21:08:25 -04:00
const wxPropertyInfo * delegateInfo ,
2003-08-05 13:24:02 -04:00
const wxClassInfo * eventSinkClassInfo ,
const wxHandlerInfo * handlerInfo ,
int eventSinkObjectID ) ;
2003-07-28 16:44:57 -04:00
} ;
/*
2003-08-05 13:24:02 -04:00
wxDepersisterCode implements the callbacks that will depersist
2004-09-24 10:32:35 -04:00
an object into a C + + initialization function . this will move to
2003-08-24 11:22:07 -04:00
a utility lib soon
2003-07-28 16:44:57 -04:00
*/
2003-08-24 11:22:07 -04:00
class WXDLLIMPEXP_BASE wxTextOutputStream ;
2003-07-28 16:44:57 -04:00
2003-08-24 11:22:07 -04:00
class WXDLLIMPEXP_BASE wxCodeDepersister : public wxDepersister
2003-07-28 16:44:57 -04:00
{
2003-08-05 13:24:02 -04:00
private :
struct wxCodeDepersisterInternal ;
wxCodeDepersisterInternal * m_data ;
wxTextOutputStream * m_fp ;
wxString ValueAsCode ( const wxxVariant & param ) ;
2003-07-28 16:44:57 -04:00
public :
2003-08-24 09:27:56 -04:00
wxCodeDepersister ( wxTextOutputStream * out ) ;
virtual ~ wxCodeDepersister ( ) ;
2003-08-05 13:24:02 -04:00
// allocate the new object on the heap, that object will have the passed in ID
2003-08-21 16:27:46 -04:00
virtual void AllocateObject ( int objectID , wxClassInfo * classInfo ,
wxxVariantArray & metadata ) ;
2003-08-05 13:24:02 -04:00
2003-08-14 14:03:06 -04:00
// initialize the already allocated object having the ID objectID with the Create method
2003-08-05 13:24:02 -04:00
// creation parameters which are objects are having their Ids passed in objectIDValues
// having objectId <> wxInvalidObjectID
virtual void CreateObject ( int objectID ,
const wxClassInfo * classInfo ,
int paramCount ,
wxxVariant * variantValues ,
int * objectIDValues ,
2003-08-21 16:27:46 -04:00
const wxClassInfo * * objectClassInfos ,
wxxVariantArray & metadata
2003-08-05 13:24:02 -04:00
) ;
2003-08-25 19:29:55 -04:00
// construct the new object on the heap, that object will have the passed in ID (for objects that
// don't support allocate-create type of creation)
// creation parameters which are objects are having their Ids passed in objectIDValues
// having objectId <> wxInvalidObjectID
virtual void ConstructObject ( int objectID ,
const wxClassInfo * classInfo ,
int paramCount ,
wxxVariant * VariantValues ,
int * objectIDValues ,
const wxClassInfo * * objectClassInfos ,
wxxVariantArray & metadata ) ;
2003-08-14 14:03:06 -04:00
// destroy the heap-allocated object having the ID objectID, this may be used if an object
2003-08-05 13:24:02 -04:00
// is embedded in another object and set via value semantics, so the intermediate
// object can be destroyed after safely
virtual void DestroyObject ( int objectID , wxClassInfo * classInfo ) ;
// set the corresponding property
virtual void SetProperty ( int objectID ,
const wxClassInfo * classInfo ,
const wxPropertyInfo * propertyInfo ,
const wxxVariant & variantValue ) ;
// sets the corresponding property (value is an object)
virtual void SetPropertyAsObject ( int objectId ,
const wxClassInfo * classInfo ,
const wxPropertyInfo * propertyInfo ,
int valueObjectId ) ;
2003-08-14 14:03:06 -04:00
// adds an element to a property collection
virtual void AddToPropertyCollection ( int objectID ,
const wxClassInfo * classInfo ,
const wxPropertyInfo * propertyInfo ,
const wxxVariant & VariantValue ) ;
// sets the corresponding property (value is an object)
virtual void AddToPropertyCollectionAsObject ( int objectID ,
const wxClassInfo * classInfo ,
const wxPropertyInfo * propertyInfo ,
int valueObjectId ) ;
2003-08-05 13:24:02 -04:00
// sets the corresponding event handler
virtual void SetConnect ( int eventSourceObjectID ,
const wxClassInfo * eventSourceClassInfo ,
2003-09-03 21:08:25 -04:00
const wxPropertyInfo * delegateInfo ,
2003-08-05 13:24:02 -04:00
const wxClassInfo * eventSinkClassInfo ,
const wxHandlerInfo * handlerInfo ,
int eventSinkObjectID ) ;
2003-07-28 16:44:57 -04:00
} ;
# endif // wxUSE_EXTENDED_RTTI
2003-08-09 08:38:21 -04:00
# endif