Sophie

Sophie

distrib > Fedora > 14 > x86_64 > media > updates > by-pkgid > 727fa15453fcace956b835e2377d4269 > files > 820

player-doc-3.0.2-5.fc14.noarch.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html>
<!-- $Id: header.html 8799 2010-06-28 04:12:42Z jpgr87 $ -->

<HEAD>


<meta HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=utf-8">
<meta name="keywords" content="stage, robot, simulation, player, player/stage">
<link href="doxygen.css" rel="stylesheet" type="text/css">

<style type="text/css">

.floatright { float: right; margin: 0 0 1em 1em; }

body {
  font-family: sans-serif;
  #font-family: Geneva, Verdana, Helvetica, Arial, sans-serif;
  background-color: #FFF;
  color:#000;
}


a:link { 
	color: #A00;
}

a:visited { 
	color: #800;
}

a { text-decoration: none; }
a:hover { text-decoration: underline; }


.timestamp { text-align:right; background-color: #DDD; font-size:75%;}

h1 { 
  font-size:160%; 
}

h2 {
  font-size:110%;
  #color: #FFF;
  #background-color: #666;
  #padding:3px;
}

h3 { text-align:left; }

img {
  border: 0;
}

ul.menu { 
    position:relative;
    left:-2.5em;
    margin-bottom:0px;
    margin-top:0px;
}

ul.menu1 { 
    position:relative;
    left:-2.1em;
    margin-bottom:0px;
    margin-top:0px;
}

li.menu { 
    list-style-type: none;
    position:relative;
    #left:-0.5em;
}


#sidebar { position: absolute; left:0px; padding:2em; top:0em; width:12em;}

#content { position: absolute; left:12em; top:0em; padding-left:3em; padding-right:3em; padding-bottom:2em; margin-top:1em; margin-right:2em; }

div.box { background-color:#EEE; border: 1px solid #000; padding: 0.5ex 0.4em 0.5ex 0.6em; margin:1em;  }
div.title { font-weight:bold; background-color:#eee; margin-bottom:2px;}

div.topbar { position: absolute; top:0px; left:9em; margin:1em; }

</style>

<TITLE>Player Manual</TITLE>

</HEAD>

<body>

<div id="sidebar"> 

<h2 style="text-align:center;">
<a href="index.html">
<img width=140 src="http://playerstage.sourceforge.net/images/player_button_v3.png" alt="Player logo"><br></a>
</h2>



<div class="box">
<div class=title>Player</div>

<ul class=menu>
<li class=menu><a href="index.html">Frontpage</a>
<li class=menu><a href="modules.html">Contents</a>
</ul>
</div>

<div class="box">
<div class=title>User</div>

<ul class=menu>
<li class=menu><a href="install.html">Installation</a>
<li class=menu><a href="start.html">Quick start</a>
<li class=menu><a href="supported_hardware.html">Supported&nbsp;devices</a>
<li class=menu><a href="group__tutorials.html">Tutorials</a>
<li class=menu><a href="group__utils.html">Utilities</a>
<li class=menu><a href="group__clientlibs.html">Client&nbsp;libraries</a>
<li class=menu><a href="http://playerstage.sourceforge.net/wiki/Basic_FAQ">FAQ</a>
<li class=menu><a href="help.html">Help</a>

</ul>
</div>

<div class=box>
<div class="title">Developer</div>
<ul class=menu>
<li class=menu><a href="architecture.html">Architecture</a>
<li class=menu><a href="group__libplayercore.html">libplayercore</a>
<ul class=menu1>
<li class=menu><a href="group__interfaces.html">interfaces</a></li>
</ul>
<li class=menu><a href="group__libplayerdrivers.html">libplayerdrivers</a>
<ul class=menu1>
<li class=menu><a href="group__drivers.html">drivers</a></li>
</ul>
<li class=menu><a href="group__libplayercommon.html">libplayercommon</a>
<li class=menu><a href="group__libplayerutils.html">libplayerutils</a>
<li class=menu><a href="group__libplayersd.html">libplayersd</a>
<li class=menu><a href="group__libplayertcp.html">libplayertcp</a>
<li class=menu><a href="group__libplayerxdr.html">libplayerxdr</a>
<li class=menu><a href="todo.html">TODO</a>
</ul>
</div>

<div class=box>
<!-- <a href="http://sourceforge.net"><img border=0 src="http://sourceforge.net/sflogo.php?group_id=42445&type=1"></a> -->
<div class="title">Online</div>
<a href="http://playerstage.sourceforge.net">Homepage</a><br>
<a href="http://sourceforge.net/project/showfiles.php?group_id=42445">Download</a><br>
<a href="http://sourceforge.net/projects/playerstage">Project</a><br>
<a href="http://sourceforge.net/tracker/?group_id=42445">Bugs</a><br>
<a href="http://sourceforge.net/mail/?group_id=42445">Help</a>
</div>


</div>

<div id="content" >
<!-- Generated by Doxygen 1.7.1 -->
<div class="header">
  <div class="headertitle">
<h1>Migrating from Player 1.6 to Player 2.0<br/>
<small>
[<a class="el" href="group__tutorials.html">Tutorials</a>]</small>
</h1>  </div>
</div>
<div class="contents">

<p>Including a guide to updating your drivers.  
<a href="#_details">More...</a></p>
<table class="memberdecls">
</table>
<p>Including a guide to updating your drivers. </p>
<p>Much changed in Player between 1.6 and 2.0, from the fundamental message model to the nuts and bolts of message formats. This page aims to ease the transition by explaining what changed (and sometimes why it changed). At least initially, the focus here will be on providing driver maintainers with the information necessary to update their code.</p>
<ul>
<li><a class="el" href="group__tutorial__migrating__drivers.html#fundamentals">Fundamentals</a><ul>
<li><a class="el" href="group__tutorial__migrating__drivers.html#framework">TCP server vs. robot programming framework</a></li>
<li><a class="el" href="group__tutorial__migrating__drivers.html#message-model">State-based vs. message-passing</a></li>
</ul>
</li>
<li><a class="el" href="group__tutorial__migrating__drivers.html#details">Details</a><ul>
<li><a class="el" href="group__tutorial__migrating__drivers.html#message-formats">Message formats</a></li>
<li><a class="el" href="group__libplayerxdr.html#arrays">Arrays</a></li>
<li><a class="el" href="group__tutorial__migrating__drivers.html#subtypes">Message type namespace</a></li>
<li><a class="el" href="group__tutorial__migrating__drivers.html#dynamic-libs">Dynamic libs</a></li>
</ul>
</li>
<li><a class="el" href="group__tutorial__migrating__drivers.html#low-details">Low-level details (how to update your driver)</a></li>
</ul>
<h2><a class="anchor" id="fundamentals"></a>
Fundamentals</h2>
<p>Two core aspects of Player have changed:</p>
<ul>
<li><a class="el" href="group__tutorial__migrating__drivers.html#framework">TCP server vs. robot programming framework</a></li>
<li><a class="el" href="group__tutorial__migrating__drivers.html#message-model">State-based vs. message-passing</a></li>
</ul>
<h3><a class="anchor" id="framework"></a>
TCP server vs. robot programming framework</h3>
<p>Player 1.6.x was many things:</p>
<ul>
<li>A state-based message model.</li>
<li>A list of interfaces, specifying the messages used to interact with a device.</li>
<li>A format for transmitting these messages over a network.</li>
<li>A TCP/IP client/server protocol for developing robot control programs.</li>
<li>A C++ API for developing device drivers.</li>
<li>A collection of device drivers that control common hardware and implement useful algorithms.</li>
<li>A server that loads, configures, and provides client access to device drivers.</li>
<li>A collection of libraries in various languages that facilitate the development of client programs.</li>
</ul>
<p>Though we tried to keep these aspects of Player separate, they were really inextricably intertwined. While Player was useful to a lot of people, it couldn't easily be extended or reused.</p>
<p>Player 2.0 aims to clarify and compartmentalize its components in such a way that they can be extended, resused, and replaced, as the situation demands. At its core, Player 2.0 comprises 5 components:</p>
<ul>
<li><a class="el" href="group__interfaces.html">interface</a>: The world of robotic devices is carved up into a set of interfaces. Each interface defines the syntax and semantics of the messages that a conforming device can consume and produce. This specification is written as a C header file, &lt;<a class="el" href="player_8h_source.html">player.h</a>&gt;, in which the messages are defined as C structs.</li>
</ul>
<ul>
<li><a class="el" href="group__libplayercore.html">libplayercore</a> : A C++ library that defines a device driver API, facilities for instantiating drivers, and the message queues used to move messages around between drivers. This library also provides methods to parse configuration files and load plugin drivers from shared objects.</li>
</ul>
<ul>
<li><a class="el" href="group__libplayerdrivers.html">libplayerdrivers</a> : A C++ library that contains the device drivers that are included with the Player distribution (the drivers that were formerly "built-in" to the player server). The exact contents of this library vary from system to system, depending on which drivers' prerequisites are satisifed, as well as the user-supplied options to the configure script. Each driver is also built as a standalone C++ library.</li>
</ul>
<ul>
<li>libplayerinterface : A C library that provides functions to translate Player messages between the native C struct format and the XDR-encoded format that can be safely sent over a network. This code is autogenerated by a program that parses &lt;<a class="el" href="player_8h_source.html">player.h</a>&gt;.</li>
</ul>
<ul>
<li><a class="el" href="group__libplayertcp.html">libplayertcp</a> : A C++ library that provides the facilities for servicing clients over TCP. This library moves messages between TCP sockets and message queues (as defined in libplayercore). All messages are XDR-encoded (with libplayerinterface) before network transmission.</li>
</ul>
<p>Because it's just so darn useful, Player 2.0 still contains a TCP <a class="el" href="group__util__player.html">player server</a>. As you can imagine, this server is a short C++ program that uses the above libraries to provide the ability to parse a configuration file, load/instantiate device drivers, and allow clients access to these devices via XDR-encoded messages over a TCP socket.</p>
<p>Use the player server if it's what you need, but don't hesitate to use the various components however you like. For example, currently in development are SWIG-generated Java bindings to libplayercore. Using these bindings, you can write a native Java program that instantiates and control device drivers. You might then plug that Java program into a Jini network and exchange Player messages as serialized Java objects, instead of XDR-encoded structs.</p>
<h3><a class="anchor" id="message-model"></a>
State-based vs. message-passing</h3>
<p>From its inception through version 1.6.x, Player was a <em>state-based</em> system. In this model, each device is presumed to have some time-varying state, and the goal of Player is to provide the ability to read and (sometimes) write this state. The content of a device's state and whether it is mutable is defined by the interface(s) that the device supports. For example, a mobile robot that supports the <a class="el" href="group__interface__position2d.html">position2d</a> interface maintains as its state the robot's position and velocity. These data are reported in the <em>data</em> messages produced by the robot and can be changed by <em>command</em> messages sent to the robot. This model is conceptually simple but is inflexible and not always appropriate.</p>
<p>Player 2.0 employs a more general <em>message-passing</em> model. In this approach, each device can produce a certain set of messages, and it can consume a certain set of messages. These messages are still defined by the interface(s) that the device supports, but they no longer need to report the entire state of the device. For example, in addition to periodic updates on its current position and velocity, a mobile robot might send out a different message when it has reached a goal or when a motor current limit was exceeded.</p>
<h2><a class="anchor" id="details"></a>
Details</h2>
<p>A variety of details have changed, including:</p>
<ul>
<li><a class="el" href="group__tutorial__migrating__drivers.html#message-formats">Message formats</a></li>
<li><a class="el" href="group__libplayerxdr.html#arrays">Arrays</a></li>
<li><a class="el" href="group__tutorial__migrating__drivers.html#subtypes">Message type namespace</a></li>
<li><a class="el" href="group__tutorial__migrating__drivers.html#dynamic-libs">Dynamic libs</a></li>
</ul>
<h3><a class="anchor" id="message-formats"></a>
Message formats</h3>
<p>Because of the techniques used to encode messages for network transmission, Player 1.6.x had frustrating limits on the data types that were allowed. Specifically, floating point values were not supported, so real numbers were represented as integers in fixed point.</p>
<p>Player 2.0 is far more flexible in this regard. Virtually all C data types are supported, as are nested message structures and fixed- and variable-length one-dimensional arrays. Multi-dimensional arrays are not supported.</p>
<p>Unless otherwise noted, all message fields are represented in MKS units.</p>
<h3><a class="anchor" id="arrays"></a>
Arrays</h3>
<p>Some arrays in message structures are fixed-length and some are variable-length. An array 'foo' is variable-length if the message structure containing 'foo' also contains a uint32_t called 'foo_count' ('foo_count' must appear before 'foo' in the structure). Otherwise, it is fixed-length. Basically, small arrays (2 or 3 elements) are fixed-length and bigger ones are variable-length.</p>
<p>The name 'foo_count' is special. It tells you how many items are actually in the array 'foo'. This information is used by the XDR functions during (de)marshaling. As a result, you must *always* fill in this field when sending a message containing a variable-length array (and you should always consult this field when receiving such a message).</p>
<p>For example, when sending a camera image, put the data in 'image' and fill in 'image_count' with the actual size of the frame. Then only those bytes will be transferred. Another example: when asking for the list of available devices, you send a <a class="el" href="structplayer__device__devlist.html" title="Request/reply: Get the list of available devices.">player_device_devlist</a>, with the field 'devices_count' set to 0. The server responds with it filled in.</p>
<h3><a class="anchor" id="subtypes"></a>
Message type namespace</h3>
<p>Player 2.0 defines a 2-level namespace of messages. At the first level, there are 7 <code>type</code>s:</p>
<ul>
<li>data (PLAYER_MSGTYPE_DATA) : A message emitted by a device, usually communicating something about the state of the device. Data messages are not acknowledged.</li>
<li>command (PLAYER_MSGTYPE_CMD) : A message sent to a device, usually changing something about the state of the device. Command messages are not acknowledged.</li>
<li>request (PLAYER_MSGTYPE_REQ) : A message sent to a device, usually requesting a configuration change or querying some information. Each request message is acknowledged by a response message.</li>
<li>positive response (PLAYER_MSGTYPE_RESP_ACK) : Sent in response to a request message, a positive response message indicates that the request was successfully processed by the device. Any requested information is contained in the body of the message.</li>
<li>negative response (PLAYER_MSGTYPE_RESP_NACK) : Sent in response to a request message, a negative response indicates that the request was received by the device but could not be processed (e.g., the request was incorrectly formatted, the device doesn't support that requst, or the underlying hardware refused to make the requested configuration change). The body of this response will be empty.</li>
<li>error response (PLAYER_MSGTYPE_RESP_ERR) : Sent in response to a request, an error response indicates that the request was never sent to the device (e.g., the device's address is invalid, or the device's message queue is full). The body of this response will be empty.</li>
<li>synch (PLAYER_MSGTYPE_SYNCH) : This message will likely be deprecated.</li>
</ul>
<p>Each message also has an interface-specific <code>subtype</code>. For example, the <a class="el" href="group__interface__laser.html">laser</a> interface defines 2 data messages: one contains a scan, while the other contains both a scan and a pose. The <code>subtype</code> field of the message header allows the recipient to disambiguate the two. The <code>subtype</code> of a response message will be identical to the corresponding request message.</p>
<h3><a class="anchor" id="dynamic-libs"></a>
Dynamic libs</h3>
<p>All libraries are now built using libtool in both static and dynamic versions (assuming your system supports building and loading shared libraries).</p>
<h2><a class="anchor" id="low-details"></a>
Low-level details (how to update your driver)</h2>
<p>The amount of work required to update a Player 1.6.x driver to the Player 2.0 API varies greatly from driver to driver. Simple, single-interface drivers tend to be pretty easy to update, whereas complex, multi-interface drivers can be quite tedious. There is no tool for automatically updating driver code; writing such a tool would be very difficult indeed.</p>
<p>Because each driver can be structured differently and use different parts of the <a class="el" href="classDriver.html" title="Base class for all drivers.">Driver</a> API, I don't have step-by-step instructions for updating a driver. Instead, below is a list of tips, hints, and things to look out for. I find that a combination of systematically following the items on this list and compilation by attrition (i.e., fix each problem as the compiler finds and complains about it) does the job.</p>
<ul>
<li><code>libplayerinterface/functiontable.c</code> must be updated manually to handle each message. The array <code>init_ftable</code> defined in that file contains a (interface, type, subtype, XDR packing function) tuple for each message. Any message without an entry in that table will not be sent or received.</li>
</ul>
<ul>
<li>The player_device_id_t structure has been replaced with the <a class="el" href="group__address__structs.html#ga5ca2fbef892715fdd468ded72c78708a">player_devaddr_t</a> structure. The <code>code</code> field is now called <code>interf</code>, the <code>port</code> field is <code>robot</code>, and a <code>host</code> field has been added.</li>
</ul>
<ul>
<li>The <a class="el" href="group__address__structs.html#gaf9df82a54edfa8d38d74d9469794ec8d">player_msghdr_t</a> structure has changed:<ul>
<li>The addressing information formerly stored in <code>code</code> and <code>index</code> is now contained in <code>addr</code>, which is of type <a class="el" href="group__address__structs.html#ga5ca2fbef892715fdd468ded72c78708a">player_devaddr_t</a>.</li>
<li>As explained above (<a class="el" href="group__tutorial__migrating__drivers.html#subtypes">Message type namespace</a>), the message header has <code>type</code> and a <code>subtype</code>.</li>
<li>The timestamp is a double, containing the number of seconds since the epoch.</li>
</ul>
</li>
</ul>
<ul>
<li>ConfigFile::ReadDeviceId is now <a class="el" href="classConfigFile.html#ab3f2b1557d97d5460a3d0ce83def74c8" title="Read a device id.">ConfigFile::ReadDeviceAddr</a>.</li>
</ul>
<ul>
<li>The <code>position</code> interface is now the <a class="el" href="group__interface__position2d.html">position2d</a> interface, and its code is PLAYER_POSITION2D_CODE.</li>
</ul>
<ul>
<li>The driver no longer specifies an allowable access mode, in either the <a class="el" href="classDriver.html" title="Base class for all drivers.">Driver</a> constructor or in <a class="el" href="classDriver.html#acc3440a6247ddb1965f670a3988e0b9d" title="Add an interface.">Driver::AddInterface</a>. The READ, WRITE, and ALL access modes have been collapsed into OPEN. A subscriber can simply OPEN or CLOSE a subscription to a device.</li>
</ul>
<ul>
<li>The data/command buffers and request/reply queues have been replaced by general-purpose message queues, of type <a class="el" href="classMessageQueue.html" title="A doubly-linked queue of messages.">MessageQueue</a>. Each driver has an incoming queue, <a class="el" href="classDriver.html#a125eab00b72ad55885162aef7024e09b" title="Queue for all incoming messages for this driver.">Driver::InQueue</a>. All messages to the driver, whether commands or requests, arrive on this queue. The queue has a maximum length, set in the <a class="el" href="classDriver.html" title="Base class for all drivers.">Driver</a> constructor or in <a class="el" href="classDriver.html#acc3440a6247ddb1965f670a3988e0b9d" title="Add an interface.">Driver::AddInterface</a>.</li>
</ul>
<ul>
<li>All external access to a driver is done via the appropriate <a class="el" href="classDevice.html" title="Encapsulates a device (i.e., a driver bound to an interface).">Device</a>, NOT the <a class="el" href="classDriver.html" title="Base class for all drivers.">Driver</a> itself. For example, to subscribe to another device, call <a class="el" href="classDevice.html#af98df4944ecf9090d0c08749a7765336" title="Subscribe the given queue to this device.">Device::Subscribe</a> on the Device* (which you can retrieve from the deviceTable with DeviceTable::GetDevice).</li>
</ul>
<ul>
<li>It is no longer to possible to block on another device to wait for data from that device. Instead, a driver can, via <a class="el" href="classDriver.html#ad34ec968daab0ff82af4c01c33676003" title="Wait for new data to arrive on the driver&#39;s queue.">Driver::Wait</a>, block on its own queue (<a class="el" href="classDriver.html#a125eab00b72ad55885162aef7024e09b" title="Queue for all incoming messages for this driver.">Driver::InQueue</a>). If any message are pending on the queue, <a class="el" href="classDriver.html#ad34ec968daab0ff82af4c01c33676003" title="Wait for new data to arrive on the driver&#39;s queue.">Driver::Wait</a> returns immediately; otherwise, it blocks until a new message is pushed onto the queue (or until the specified timeout).</li>
</ul>
<ul>
<li>The Get/Put Data/Command/Config/Reply methods have been replaced with methods for pushing and popping messages on queues. To process incoming messages, override the default implementation of <a class="el" href="classDriver.html#ab05d0e8502a494a83d0442a48095a35c" title="Message handler.">Driver::ProcessMessage</a>; this method should handle a single message. The method <a class="el" href="classDriver.html#a24f15e0e5b8931805f734862f5bc8a7d" title="Process pending messages.">Driver::ProcessMessages</a> will pop all pending messages from <a class="el" href="classDriver.html#a125eab00b72ad55885162aef7024e09b" title="Queue for all incoming messages for this driver.">Driver::InQueue</a>, calling <a class="el" href="classDriver.html#ab05d0e8502a494a83d0442a48095a35c" title="Message handler.">Driver::ProcessMessage</a> once for each message. <a class="el" href="classDriver.html#a24f15e0e5b8931805f734862f5bc8a7d" title="Process pending messages.">Driver::ProcessMessages</a> facilitates sending replies and should be used in place of calling <a class="el" href="classMessageQueue.html#a4a35916cdeaec3db74d9f9aa4e8284e4" title="Pop a message off the queue.">MessageQueue::Pop</a> directly on <a class="el" href="classDriver.html#a125eab00b72ad55885162aef7024e09b" title="Queue for all incoming messages for this driver.">Driver::InQueue</a> (although you can certainly do this if you want). To send a message to a device (i.e., to push a message onto a device's queue), call <a class="el" href="classDevice.html#a37323e0a016d0f8fb544199129f05a4e" title="Send a message to this device.">Device::PutMsg</a>.</li>
</ul>
<ul>
<li>Non-threaded drivers MUST override <a class="el" href="classDriver.html#ab05d0e8502a494a83d0442a48095a35c" title="Message handler.">Driver::ProcessMessage</a>, and they MUST respond to each request message in place in this method. <a class="el" href="classDriver.html#a24f15e0e5b8931805f734862f5bc8a7d" title="Process pending messages.">Driver::ProcessMessages</a> will be invoked periodically on each non-threaded driver. Forwarding requests to an underlying driver from a non-threaded driver is tricky; look at the <a class="el" href="group__driver__lasercspace.html">lasercspace</a> driver for an example.</li>
</ul>
<ul>
<li><a class="el" href="classDevice.html#aeafd1418afc82da4603310b6e35ff3dc" title="Make a request of another device.">Device::Request</a> provides an easy way to send a request to another device and wait for the reply. Do NOT call this method inside <a class="el" href="classDriver.html#ab05d0e8502a494a83d0442a48095a35c" title="Message handler.">Driver::ProcessMessage</a> in a non-threaded driver, as it would block the caller, which could be a very bad thing.</li>
</ul>
<ul>
<li>No more byte-swapping or unit-conversions in driver code. Drivers are transport-independent modules, and as such send and receive all messages in their native C struct formats (host byte-order, MKS units), as defined in &lt;<a class="el" href="player_8h_source.html">player.h</a>&gt;. Nobody should include &lt;netinet/in.h&gt;.</li>
</ul>
<ul>
<li>Only one file should be included from Player: <div class="fragment"><pre class="fragment"><span class="preprocessor">    #include &lt;libplayerinterface/player.h&gt;</span>
</pre></div> Use pkg-config (i.e., <code>pkg-config --cflags libplayercore</code>) to get the appropriate compiler flags.</li>
</ul>
<ul>
<li>For "built-in" drivers (i.e., those included in the Player distribution, NOT plugin drivers), the Makefile.am layout has changed:<ul>
<li>All drivers are now built as libtool libraries, with the extension <code>.la</code>.</li>
<li>An automake conditional tells you whether your driver should be built.</li>
</ul>
</li>
</ul>
<ul>
<li>As an example, if your driver is called <code>foo</code>, and is built from <code>foo.cc</code>, then your Makefile.am might look like this: <div class="fragment"><pre class="fragment">    noinst_LTLIBRARIES = 
    <span class="keywordflow">if</span> INCLUDE_FOO
    noinst_LTLIBRARIES += libfoo.la
    endif

    AM_CPPFLAGS = -Wall -I$(top_srcdir)

    libfoo_la_SOURCES = foo.cc
</pre></div> </li>
</ul>
</div>
<!-- render the modification time of the source file -->


<div class="timestamp">
<hr>

<table style="width:100%;">
<tr>
<td style="text-align:left;">
Last updated 12 September 2005 21:38:45
<!--
<td style="text-align:right;">
<a href="http://validator.w3.org/check/referer"><img style="vertical-align:middle;border:0;width:88px;height:31px"
          src="http://www.w3.org/Icons/valid-html401"
          alt="Valid HTML 4.01!"></a>

 <a href="http://jigsaw.w3.org/css-validator/">
  <img style="vertical-align:middle;border:0;width:88px;height:31px"
       src="http://jigsaw.w3.org/css-validator/images/vcss"
       alt="Valid CSS!">
 </a>
-->
</tr>
</table>
</div>


</tr>
</table>

</BODY>
</HTML>