| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| <HTML> |
| <HEAD> |
| <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1"> |
| <TITLE> |
| C++ UNO Language Specification |
| </TITLE> |
| <style type="text/css"> |
| <!-- |
| h1 { text-align:center; margin-top: 0.2cm; text-decoration: none; color: #ffffff; font-size: 6; margin-top: 0.2cm} |
| h2 { margin-top: 0.2cm; margin-bottom=0.1cm; color: #ffffff; background-color: #666699 } |
| li {margin-bottom: 0.2cm;} |
| dl {margin-bottom: 0.2cm;} |
| dd {margin-bottom: 0.2cm;} |
| dt {margin-bottom: 0.2cm;} |
| pre {background-color: #ffffcc;} |
| --> |
| </style> |
| </HEAD> |
| <body> |
| <TABLE WIDTH=100% BORDER=0 CELLPADDING=4 CELLSPACING=0 summary=header bgcolor=#666699> |
| <tr><td> |
| <h1> C++ UNO Language Specification </h1> |
| </td><td> |
| <A HREF="http://www.openoffice.org/"> |
| <IMG SRC="../../../images/open_office_org_logo.gif" NAME="Grafik1" ALT="OpenOffice.org" ALIGN=RIGHT WIDTH=109 HEIGHT=54 BORDER=0/> |
| </A> |
| </TD></TR> |
| |
| </TABLE> |
| |
| <h2><A NAME="intro"></A> Introduction </h2> |
| |
| <p>This document describes the C++ representation of UNO IDL types as generated by the |
| <a href="../../../common/man/tools.html#cppumaker"><code>cppumaker</code> tool</a>. |
| Each C++ UNO type is generated into a corresponding <code>hpp</code> and |
| <code>hdl</code> header file. The <code>hdl</code> file contains only declarations while |
| the <code>hpp</code> includes it and defines all inline functions (e.g., default |
| constructors).</p> |
| |
| <p>A inline <code>getCppuType()</code> function is available for each UNO type either |
| in a <code>hpp</code> file or from basic type headers |
| (, e.g. <code>com/sun/star/uno/Any.hxx</code>).</p> |
| |
| <p>Calling this function you can obtain the meta type of a type, i.e. a value describing |
| the type. Using this type (reference) you can get comprehensive description of the type |
| using the C++ runtime (<code>cppu</code> library; have a look at |
| <code>typelib/typedescription.h</code>).</p> |
| |
| <p>The <code>getCppuType()</code> function has the following signature to be used for |
| template statements:</p> |
| |
| <pre> |
| // global lnamespace implied |
| const ::com::sun::star::uno::Type & SAL_CALL getCppuType( const <i>Type</i> * ); |
| </pre> |
| |
| <p>The UNO IDL character <code>char</code> type which is defined to be a C++ |
| <code>sal_Unicode</code> 16 bit unsigned short integer is ambiguous to the C++ |
| UNO IDL unsigned short (<code>sal_uInt16</code>), thus this points out an exception |
| to the rule above. Also, the <code>void</code> type cannot be used, because any C++ pointer |
| can be implicitly casted to a <code>void</code> pointer.</p> |
| |
| <pre> |
| // global namespace implied |
| // header com/sun/star/uno/Type.hxx |
| const ::com::sun::star::uno::Type & SAL_CALL getCppuCharType(); |
| const ::com::sun::star::uno::Type & SAL_CALL getCppuVoidType(); |
| // header com/sun/star/uno/Sequence.hxx |
| const ::com::sun::star::uno::Type & SAL_CALL getCharSequenceCppuType(); |
| </pre> |
| |
| <p>The following sections define all types and UNO IDL constructs, |
| which includes the binary memory layout, too.</p> |
| |
| <ul> |
| <li><a href="#modules">Modules, Constants</A></li> |
| <li><a href="#basic_types">basic Types</A></li> |
| <li><a href="#enum">Enum</A></li> |
| <li><a href="#sequence">Sequence</A></li> |
| <li><a href="#array">Array</A> |
| <li><a href="#interface">Interface</A></li> |
| <li><a href="#struct">Struct</A></li> |
| <li><a href="#exception">Exception</A></li> |
| <li><a href="#union">union</A></li> |
| </ul> |
| |
| <h2><A NAME="modules"></A> Modules, Constants </h2> |
| |
| <p>An IDL module definition is mapped to a C++ namespace with the same name. |
| All IDL type definition within the module are mapped to their corresponding C++ type |
| declarations within the generated namespace. |
| IDL declarations which are not enclosed in any modules are mapped into the C++ global scope.</p> |
| |
| <p>IDL constant groups are mapped to a C++ namespaces with the same name as the constant group. |
| All defined constants in this constant group are mapped to static const variables with type, |
| name and value of the IDL equivalent.</p> |
| |
| <p> |
| Example: |
| |
| <pre> |
| module foo |
| { |
| constants group |
| { |
| const long BAR = 0xdb0; |
| }; |
| }; |
| </pre> |
| |
| <p>is generated to</p> |
| |
| <pre> |
| file foo/bar.hdl: |
| |
| namespace foo |
| { |
| namespace group |
| { |
| static const sal_Int32 BAR = (sal_Int32)0xdb0; |
| } |
| } |
| </pre> |
| |
| <h2><A NAME="basic_types"></A> basic Types </h2> |
| |
| <p>The binary representation of UNO types is machine (e.g. big-/little-endian), |
| language and operating system dependent. |
| Alignment of data structures complicates even more, and is also processor and bus dependent. |
| The alignment used for C++ UNO types is defined by the following algorithm:</p> |
| |
| <p> |
| Structure members are stored sequentially by the order they are declared. |
| Every data object has an <i>alignment-requirement</i>. |
| For structures, the requirement is the largest size of its members. |
| Every object then has an allocated <i>offset</i> so that</p> |
| |
| <pre> |
| <i>offset</i> % <i>alignment-requirement</i> == 0 |
| </pre> |
| |
| <p>If it is possible that the maximum <code>alignment-requirement</code> can be restricted |
| (Microsoft C/C++ compiler, IBM C/C++ compiler using a compiler pragma), |
| then it is set to 8. |
| Under this condition the alignment-requirement is</p> |
| |
| <pre> |
| alignment-requirement := min( 8, sizeof( <i>type</i> ) ). |
| struct-alignment-requirement := min( 8, sizeof( <i>largest-member-type</i> ) ). |
| </pre> |
| |
| <p>The size of the struct is ceiled up to the largest integral member type.</p> |
| <p>In general, if the maximal <code>alignment-requirement</code> can be restricted to <i>max-alignment</i>, |
| then it is</p> |
| |
| <pre> |
| alignment-requirement := min( <i>max-alignment</i>, sizeof( <i>type</i> ) ). |
| struct-alignment-requirement := min( <i>max-alignment</i>, sizeof( <i>largest-member-type</i> ) ). |
| </pre> |
| |
| <p>The size of the struct is ceiled up to the largest integral member type.</p> |
| |
| <p>The following table shows the IDL type, size and layout of the basic C++ UNO specification. |
| Only 32-Bit C++ UNO is specified and tested for now. |
| Basic type definitions like <code>sal_Int32</code> are defined in header |
| <code>sal/types.h</code>.</p> |
| |
| <TABLE WIDTH=904 BORDER=1 CELLPADDING=5 CELLSPACING=0> |
| <COL WIDTH=128> <COL WIDTH=98> <COL WIDTH=318> <THEAD> |
| <tr> |
| <th>IDL type</th> |
| <th>Size [byte]</th> |
| <th>C++ type</th> |
| </TR> |
| </THEAD><TBODY> |
| <tr> |
| <td><code>void</code></td> |
| <td><code>-</code></td> |
| <td>void</td> |
| </TR> |
| <tr> |
| <td><code>byte</code></td> |
| <td><code>1</code></td> |
| <td>signed 8 bit integer (<code>sal_Int8</code>)</td> |
| </TR> |
| <tr> |
| <td><code>short</code></td> |
| <td><code>2</code></td> |
| <td>signed 16 bit integer (<code>sal_Int16</code>)</td> |
| </TR> |
| <tr> |
| <td><code>unsigned short</code></td> |
| <td><code>2</code></td> |
| <td>unsigned 16 bit integer (<code>sal_uInt16</code>)</td> |
| </TR> |
| <tr> |
| <td><code>signed long</code></td> |
| <td><code>4</code></td> |
| <td>signed 32 bit integer (<code>sal_Int32</code>)</td> |
| </TR> |
| <tr> |
| <td><code>unsigned long</code></td> |
| <td><code>4</code></td> |
| <td>unsigned 32 bit integer (<code>sal_uInt32</code>)</td> |
| </TR> |
| <tr> |
| <td><code>hyper</code></td> |
| <td><code>8</code></td> |
| <td>signed 64 bit integer (<code>sal_Int64</code>)</td> |
| </TR> |
| <tr> |
| <td><code>unsigned hyper</code></td> |
| <td><code>8</code></td> |
| <td>unsigned 64 bit integer (<code>sal_uInt64</code>)</td> |
| </TR> |
| <tr> |
| <td><code>enum</code></td> |
| <td><code>4</code></td> |
| <td>C++ enum</td> |
| </TR> |
| <tr> |
| <td><code>float</code></td> |
| <td><code>sizeof (float)</code></td> |
| <td>processor dependent: Intel, Sparc = IEEE float (<code>float</code>)</td> |
| </TR> |
| <tr> |
| <td><code>double</code></td> |
| <td><code>sizeof (double)</code></td> |
| <td>processor dependent: Intel, Sparc = IEEE double (<code>double</code>)</td> |
| </TR> |
| <tr> |
| <td><code>boolean</code></td> |
| <td><code>1</code></td> |
| <td>8 bit unsigned char (<code>sal_Bool { 0, 1 }</code>)</td> |
| </TR> |
| <tr> |
| <td><code>char</code></td> |
| <td><code>2</code></td> |
| <td>16 bit Unicode char (<code>sal_Unicode</code>)</td> |
| </TR> |
| <tr> |
| <td><code>string</code></td> |
| <td><code>4</code></td> |
| <td>Wrapper class <code>::rtl::OUString</code> |
| (header <code>rtl/ustring</code>) acquiring reference |
| to struct <code>rtl_uString</code> (header <code>rtl/ustring.h</code>). |
| </td> |
| </TR> |
| <tr> |
| <td><code>type</code></TD> |
| <td><code>4</code></TD> |
| <td>Wrapper class <code>::com::sun::star::uno::Type</code> acquiring |
| reference to <code>typelib_TypeDescriptionReference</code> |
| (header <code>typelib/typedescription.h</code>). |
| A default constructed meta type refers to type <code>VOID</code>. |
| </td> |
| </TR> |
| <tr> |
| <td><code>any</code></TD> |
| <td><code>sizeof (uno_Any)</code></TD> |
| <td>Wrapper class <code>::com::sun::star::uno::Any</code> |
| (header <code>com/sun/star/uno/Any.hxx</code>) derived from |
| struct <code>uno_Any</code> (header <code>uno/any2.h</code>): |
| <pre> |
| typedef struct _uno_Any |
| { |
| typelib_TypeDescriptionReference * pType; |
| void * pData; |
| } uno_Any; |
| </pre> |
| |
| <p>The struct contains a pointer to the type and value that is |
| held by the any. Anies cannot be nested, i.e. no any can contain an any! |
| </p> |
| </TD></TR> |
| </TBODY></TABLE> |
| |
| <h2><A NAME="enum"></A> Enum </h2> |
| <p>An IDL enumeration is mapped to a C++ enumeration type (<code>enum</code>). |
| The name of the enumeration is used as prefix for each enumeration label. |
| The enumeration labels will be initialized with the defined values in IDL or by default |
| in ascending order beginning with 0. |
| The last label (<i>EnumName</i><code>_MAKE_FIXED_SIZE = SAL_MAX_ENUM</code>) |
| is appended to fix the size of the enumeration type to 32 bit. |
| |
| <p> |
| Example: |
| |
| <pre> |
| module foo |
| { |
| enum Bar |
| { |
| JOHN, DOE |
| }; |
| }; |
| </pre> |
| |
| <p>is generated to</p> |
| |
| <pre> |
| file foo/Bar.hdl: |
| |
| namespace foo |
| { |
| |
| enum Bar |
| { |
| Bar_John = 0, |
| Bar_DOE = 1, |
| Bar_MAKE_FIXED_SIZE = SAL_MAX_ENUM |
| }; |
| |
| } |
| </pre> |
| |
| <h2><A NAME="sequence"></A> Sequence </h2> |
| |
| <p>C++ UNO sequences are reference counted. The value type of a sequence is handled by |
| template class <code>::com::sun::star::uno::Sequence</code> |
| (header <code>com/sun/star/uno/Sequence.hxx</code>). |
| It acquires a pointer to <code>uno_Sequence</code> which is of the following |
| structure (headers <code>uno/sequence2.h</code> and <code>sal/types.h</code>): |
| |
| <pre> |
| typedef struct _sal_Sequence |
| { |
| sal_Int32 nRefCount; |
| sal_Int32 nElements; |
| char elements[1]; |
| } sal_Sequence; |
| |
| typedef sal_Sequence uno_Sequence; |
| </pre> |
| |
| <p>Elements of the sequence follow up directly to the elements array. |
| API functions to cope with sequences are in header <code>uno/sequence2.h</code>. |
| <p> |
| Sequences are used generically in UNO, i.e. nothing has to be generated for a specific |
| sequence (e.g. used in an interface method declaration) by the |
| <a href="../../../common/man/tools.html#cppumaker"><code>cppumaker</code> tool</a>. |
| A UNO IDL type usage of <code>sequence< long ></code> will last in a C++ UNO |
| <code>::com::sun::star::uno::Sequence< sal_Int32 ></code>. |
| <p>Header <code>com/sun/star/uno/Sequence.hxx</code> defines a template |
| <code>getCppuType()</code> |
| function (template parameter is C++ UNO element type). |
| As stated in the first section, UNO IDL type <code>char</code> is ambiguous to |
| <code>unsigned short</code> C++ UNO type. |
| Thus for UNO IDL <code>sequence< char ></code> you |
| have to use <code>getCharSequenceCppuType()</code> obtaining its meta type |
| (header <code>com/sun/star/uno/Sequence.hxx</code>). |
| |
| <h2><A NAME="array"></A> Array </h2> |
| <p> |
| XXX TODO: |
| The array has yet to be specified, but is in work. |
| Ask <a href="mailto:Juergen.Schmidt@germany.sun.com">Juergen Schmidt</a> |
| for current status. |
| |
| <p>Thus the array specification is not fixed, to give an outlook: |
| It will follow C array specification and generated to a C array of given element type. |
| Arrays will allow multiple dimensions. |
| In contrast to <a href="#sequence">sequences</a> C arrays are <b>not</b> reference |
| counted, thus copying big arrays may be time consuming. |
| |
| <h2><A NAME="interface"></A> Interface </h2> |
| |
| <p> |
| Interfaces are generated to C++ classes having pure virtual member functions |
| (, e.g. <code>virtual void foo() = 0</code>). |
| C++ interface references control the lifetime of an interface |
| (template wrapper class <code>::com::sun::star::uno::Reference<></code> |
| in header <code>com/sun/star/uno/Reference.hxx</code>) and hold the acquired |
| interface pointer as only member. |
| They build up the value type of an interface, i.e. if a method expects an interface, |
| this implicitly means it gets an interface reference. |
| Note that the generated <code>getCppuType()</code> generated in the <code>hpp</code> |
| file has the following signature: |
| |
| <pre> |
| inline const ::com::sun::star::uno::Type& SAL_CALL getCppuType( |
| const ::com::sun::star::uno::Reference< <i>generated_C++_class</i> >* ) |
| throw(); |
| </pre> |
| |
| <p> |
| Return values are passed as C++ return values, the three different |
| types of parameters are generated as follows: |
| |
| <ul> |
| <li><i>in</i>: the parameter is pure in parameter; it is passed as call-by-value for |
| ordinal and float types or passed as call-by-reference |
| (<code>const &</code> [const C++ reference]) for C++ objects (, e.g. struct, exception, interface |
| reference). |
| </li> |
| <li><i>out</i>: the parameter is pure out parameter; it is anytime passed as call-by-reference |
| (<code>&</code> [non-const C++ reference]). |
| </li> |
| <li><i>inout</i>: the parameter is inout parameter; it is anytime passed as call-by-reference |
| (<code>&</code> [non-const C++ reference]). |
| </li> |
| </ul> |
| </p> |
| <p>If the UNO IDL interface declares an attribute, the corresponding C++ class gets a |
| <code>get</code><i>AttributeName</i><code>()</code> and |
| <code>set</code><i>AttributeName</i><code>()</code> |
| (if non-<code>readonly</code>). |
| |
| <p>Any interface method can declare <a href="#exception">exceptions</a> |
| that may be thrown upon invocation of it. |
| Implicitly any method may throw <code>com.sun.star.uno.RuntimeException</code> |
| (generated C++ struct <code>::com::sun::star::uno::RuntimeException</code>). |
| For now exception clauses are generated for the pure virtual member functions, but |
| due to compiler bugs this heavily increases code size on some platforms. |
| So the currently used C++ <code>throw</code> clause will probably exchanged by a macro |
| expansion soon. But nevertheless this only affects exception declarations, C++ UNO exceptions |
| can be thrown and caught as common in C++ (<code>try ... catch ()</code>).</p> |
| <p>The latter said is valid except for <code>com.sun.star.XInterface::acquire()</code> |
| and <code>com.sun.star.XInterface::release()</code> which never throw any exception. |
| |
| <p>Interface inheritance is similarly adopted to C++ class inheritance. |
| All interfaces inherit from UNO IDL interface <code>com.sun.star.XInterface</code> |
| (i.e. C++ generated class <code>::com::sun::star::XInterface</code>) |
| which serves as a base for lifetime control and querying the object for interfaces. |
| |
| <p> |
| Example: <code>com.sun.star.lang.XMultiServiceFactory</code> |
| |
| <pre> |
| module com { module sun { module star { module lang { |
| |
| interface XMultiServiceFactory: com::sun::star::uno::XInterface |
| { |
| com::sun::star::uno::XInterface createInstance( |
| [in] string aServiceSpecifier ) |
| raises( com::sun::star::uno::Exception ); |
| |
| com::sun::star::uno::XInterface createInstanceWithArguments( |
| [in] string ServiceSpecifier, |
| [in] sequence<any> Arguments ) |
| raises( com::sun::star::uno::Exception ); |
| |
| sequence<string> getAvailableServiceNames(); |
| }; |
| |
| }; }; }; }; |
| </pre> |
| |
| <p>will be generated to (<code>hdl</code> file)</p> |
| |
| <pre> |
| namespace com |
| { |
| namespace sun |
| { |
| namespace star |
| { |
| namespace lang |
| { |
| |
| class XMultiServiceFactory : public ::com::sun::star::uno::XInterface |
| { |
| public: |
| virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL |
| createInstance( const ::rtl::OUString& aServiceSpecifier ) |
| throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) = 0; |
| |
| virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL |
| createInstanceWithArguments( |
| const ::rtl::OUString& ServiceSpecifier, |
| const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Arguments ) |
| throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) = 0; |
| |
| virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL |
| getAvailableServiceNames( ) |
| throw(::com::sun::star::uno::RuntimeException) = 0; |
| }; |
| |
| } // lang |
| } // star |
| } // sun |
| } // com |
| </pre> |
| |
| <p>Oneway declarations are ignored for C++ bridges, they only affect inter-process bridges. |
| The macro <code>SAL_CALL</code> forces C calling convention to be used, e.g. |
| <code>__cdecl</code> for the Microsoft Visual C++ compiler. |
| |
| <h2><A NAME="struct"></A> Struct </h2> |
| |
| <p>UNO IDL Structs are generated to C++ structs declaring the C++ UNO types and members |
| in the same order. The member names are identical. |
| A default constructor initializing all members to their default values is generated, too. |
| Struct inheritance is adopted to C++ inheritance. |
| Note that the maximal alignment-requirement for structures for the OS/2 and Microsoft Visual C++ |
| compiler is 8. |
| |
| <p> |
| Example: <code>com.sun.star.lang.Locale</code> |
| |
| <pre> |
| module com { module sun { module star { module lang { |
| |
| struct Locale |
| { |
| string Language; |
| string Country; |
| string Variant; |
| }; |
| |
| }; }; }; }; |
| </pre> |
| |
| <p>will be generated to (<code>hdl</code> file)</p> |
| |
| <pre> |
| namespace com |
| { |
| namespace sun |
| { |
| namespace star |
| { |
| namespace lang |
| { |
| |
| #ifdef SAL_W32 |
| # pragma pack(push, 8) |
| #elif defined(SAL_OS2) |
| # pragma pack(8) |
| #endif |
| |
| struct Locale |
| { |
| inline Locale(); |
| |
| // inline ctor definition in hpp file |
| inline Locale( |
| const ::rtl::OUString& __Language, |
| const ::rtl::OUString& __Country, |
| const ::rtl::OUString& __Variant ); |
| |
| ::rtl::OUString Language; |
| ::rtl::OUString Country; |
| ::rtl::OUString Variant; |
| }; |
| |
| #ifdef SAL_W32 |
| # pragma pack(pop) |
| #elif defined(SAL_OS2) |
| # pragma pack() |
| #endif |
| |
| } // lang |
| } // star |
| } // sun |
| } // com |
| </pre> |
| |
| <h2><A NAME="exception"></A> Exception </h2> |
| |
| <p>Exceptions are generated similarly to <a href="#struct">structs</a>, meaning |
| they have identical |
| binary layout. There is only one minor difference in generation, i.e. exceptions are declared as |
| C++ classes not as structs. Exception members appear in the <code>public</code> section |
| of the class. Exceptions are thrown by instance. |
| <p> |
| Exceptions need not inherit from any base exception, though UNO API conventions |
| want any exception ([in-]directly) inherit from <code>com.sun.star.uno.Exception</code>. |
| |
| <p> |
| Example: <code>com.sun.star.lang.IllegalArgumentException</code> |
| |
| <pre> |
| module com { module sun { module star { module lang { |
| |
| exception IllegalArgumentException: com::sun::star::uno::Exception |
| { |
| short ArgumentPosition; |
| }; |
| |
| }; }; }; }; |
| </pre> |
| |
| <p>will be generated to (<code>hdl</code> file)</p> |
| |
| <pre> |
| namespace com |
| { |
| namespace sun |
| { |
| namespace star |
| { |
| namespace lang |
| { |
| |
| class IllegalArgumentException : public ::com::sun::star::uno::Exception |
| { |
| public: |
| // inline ctor definition in hpp file |
| inline IllegalArgumentException(); |
| // inline ctor definition in hpp file |
| inline IllegalArgumentException( |
| const ::rtl::OUString& __Message, |
| const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& __Context, |
| const sal_Int16& __ArgumentPosition ); |
| |
| sal_Int16 ArgumentPosition; |
| }; |
| |
| } // lang |
| } // star |
| } // sun |
| } // com |
| </pre> |
| |
| <h2><A NAME="union"></A> Union </h2> |
| |
| <p> |
| XXX TODO: |
| Currently, unions are not supported by the |
| <a href="../../../common/man/tools.html#cppumaker"><code>cppumaker</code> tool</a>, |
| but nevertheless the runtime can cope with it. |
| Union will be passed by C++ reference upon member function calls except for return values. |
| Unions will be generated as structs having a 64 bit discriminant as first member followed |
| by a C union declaration. Alignment is as for structs. |
| |
| <table bgcolor=#666699 summary=footer width=100%> |
| <TR><td> |
| <FONT COLOR="#ffffff"> |
| Author: <A HREF="mailto:Daniel.Boelzle@germany.sun.com"> |
| <FONT COLOR="#ffffff">Daniel Bölzle</A>. Last modified $Date: 2004/12/08 12:41:09 $<br/> |
| <I>Copyright 2001 Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, CA 94303 USA.</I> |
| </FONT> |
| </TD></tr> |
| </TABLE> |
| </BODY> |
| </html> |