639 lines
18 KiB
HTML
639 lines
18 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<meta name="Copyright" content="Copyright (c) 2006 by IBM Corporation">
|
|
<title>send_file()--Send a File over a Socket Connection</title>
|
|
<!-- All rights reserved. Licensed Materials Property of IBM -->
|
|
<!-- US Government Users Restricted Rights -->
|
|
<!-- Use, duplication or disclosure restricted by -->
|
|
<!-- GSA ADP Schedule Contract with IBM Corp. -->
|
|
<!-- Begin Header Records ========================================== -->
|
|
<!-- Unix8 SCRIPT J converted by B2H R4.1 (346) (CMS) by V2KEA304 -->
|
|
<!-- at RCHVMW2 on 17 Feb 1999 at 11:05:09 -->
|
|
<!-- 020618 EMIG: updated for NFS threadsafety, V5R3 -->
|
|
<!-- 020718 MFENLON: updated for QFileSvr.400 threadsafety, V5R3 -->
|
|
<!--End Header Records -->
|
|
<!-- Edited by Kersten Feb 02 -->
|
|
<link rel="stylesheet" type="text/css" href="../rzahg/ic.css">
|
|
</head>
|
|
<body>
|
|
<a name="Top_Of_Page"></a>
|
|
<!-- Java sync-link -->
|
|
<script type="text/javascript" language="Javascript" src="../rzahg/synch.js">
|
|
</script>
|
|
|
|
<h2>send_file()--Send a File over a Socket Connection</h2>
|
|
|
|
<div class="box" style="width: 60%;">
|
|
<br>
|
|
Syntax<br>
|
|
<pre>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
|
|
int send_file(int *<em>socket_descriptor</em>,
|
|
struct sf_parms *<em>sf_struct</em>,
|
|
int <em>flags</em>)
|
|
</pre>
|
|
|
|
<br>
|
|
Service Program Name: QSOSRV1<br>
|
|
<!-- iddvc RMBR -->
|
|
<br>
|
|
Default Public Authority: *USE<br>
|
|
<!-- iddvc RMBR -->
|
|
<br>
|
|
Threadsafe: Conditional; see <a href="#HDRSDFUSAG">Usage Notes</a>.<br>
|
|
<!-- iddvc RMBR -->
|
|
<br>
|
|
</div>
|
|
<p>The <em>send_file()</em> function is used to send the contents of an open
|
|
file over an existing socket connection.</p>
|
|
|
|
<p>The <em>send_file()</em> API is a combination of the IFS <em>read()</em> and
|
|
the sockets <em>send()</em> and <em>close()</em> APIs. Socket applications that
|
|
transmit a file over a socket connection can, under certain circumstances,
|
|
obtain improved performance by using <em>send_file()</em>.</p>
|
|
|
|
<br>
|
|
<h3>Parameters</h3>
|
|
|
|
<dl>
|
|
<dt><strong>socket_descriptor</strong></dt>
|
|
|
|
<dd>(Input/Output) A pointer to the socket descriptor that is to be written
|
|
to.<br>
|
|
<br>
|
|
</dd>
|
|
|
|
<dt><strong>sf_struct</strong></dt>
|
|
|
|
<dd>(Input/Output) A pointer to the send_file structure that contains the
|
|
following:
|
|
|
|
<ul>
|
|
<li>The header buffer and length<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>The file descriptor, the offset into the file, the file size, and number of
|
|
bytes to send from the file<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>The trailer buffer and length<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>The number of bytes of data that were sent</li>
|
|
</ul>
|
|
|
|
<p>The structure pointed to by the <em>sf_struct</em> parameter is defined in
|
|
<strong><sys/socket.h></strong>.</p>
|
|
|
|
<pre>
|
|
struct sf_parms
|
|
{
|
|
void *header_data;
|
|
size_t header_length;
|
|
|
|
int file_descriptor;
|
|
size_t file_size;
|
|
off_t file_offset;
|
|
ssize_t file_bytes;
|
|
|
|
void *trailer_data;
|
|
size_t trailer_length;
|
|
|
|
size_t bytes_sent;
|
|
}
|
|
</pre>
|
|
|
|
<table cellpadding="5">
|
|
<!-- cols="15 85" -->
|
|
<tr>
|
|
<td align="left" valign="top"><em>header_data </em></td>
|
|
<td align="left" valign="top">(Input/Output) A pointer to a buffer that
|
|
contains data to be sent before the file data is sent.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>header_length</em> </td>
|
|
<td align="left" valign="top">(Input/Output) The length in bytes of
|
|
<em>header_data</em>.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>file_descriptor</em> </td>
|
|
<td align="left" valign="top">(Input) The file descriptor for a file that has
|
|
been opened for read access. This is the descriptor for the file that contains
|
|
the data to be transmitted. This field is ignored if the <em>file_bytes</em>
|
|
field is set to 0.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>file_size</em> </td>
|
|
<td align="left" valign="top">(Output) The size in bytes of the file associated
|
|
with <em>file_descriptor</em>.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>file_offset </em></td>
|
|
<td align="left" valign="top">(Input/Output) The byte offset into the file from
|
|
which to start sending data. Specify a value of 0 to start sending data from
|
|
the start of the file. If a negative value is passed in, <em>send_file()</em>
|
|
API will return with -1 and the <em>errno</em> will be set to EINVAL.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>file_bytes</em> </td>
|
|
<td align="left" valign="top">(Input/Output) The number of bytes from the file
|
|
to be transmitted. Set the <em>file_bytes</em> field to -1 to transmit all of
|
|
the data from the <em>file_offset</em> position in the file to the end of the
|
|
file. If the <em>file_bytes</em> field is set to 0, no data from the file will
|
|
be transmitted.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>trailer_data </em></td>
|
|
<td align="left" valign="top">(Input/Output) A pointer to a buffer that
|
|
contains data to be sent after the file data is sent.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>trailer_length</em> </td>
|
|
<td align="left" valign="top">(Input/Output) The length in bytes of
|
|
<em>trailer_data</em>.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>bytes_sent</em> </td>
|
|
<td align="left" valign="top">(Output) The number of bytes that have been
|
|
successfully sent. </td>
|
|
</tr>
|
|
</table>
|
|
|
|
<br>
|
|
<br>
|
|
</dd>
|
|
|
|
<dt><strong>flags</strong></dt>
|
|
|
|
<dd>(Input) A flag value that controls what is done with the socket connection
|
|
after the data has been transmitted. The <em>flags</em> value is either zero or
|
|
it is one of the following constants:
|
|
|
|
<table cellpadding="5">
|
|
<!-- cols="15 85" -->
|
|
<tr>
|
|
<td align="left" valign="top"><em>SF_CLOSE</em></td>
|
|
<td align="left" valign="top">After the <em>header_data</em>, file data, and
|
|
<em>trailer_data</em> have been successfully sent, the connection and the
|
|
socket descriptor are closed. The descriptor that is pointed to by the
|
|
<em>socket_descriptor</em> parameter is set to -1 before the
|
|
<em>send_file()</em> API returns to the application.</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>SF_REUSE</em></td>
|
|
<td align="left" valign="top">After the <em>header_data</em>, file data, and
|
|
<em>trailer_data</em> have been successfully sent, the connection is closed. If
|
|
socket reuse is supported, the descriptor that is pointed to by the
|
|
<em>socket_descriptor</em> parameter is reset. If socket reuse is not
|
|
supported, the descriptor that is pointed to by the <em>socket_descriptor</em>
|
|
parameter is closed and set to -1.</td>
|
|
</tr>
|
|
</table>
|
|
</dd>
|
|
</dl>
|
|
|
|
<br>
|
|
<h3>Authorities</h3>
|
|
|
|
<p>No authorization is required.</p>
|
|
|
|
<br>
|
|
<h3>Return Value</h3>
|
|
|
|
<p><em>send_file()</em> returns an integer. Possible values are:</p>
|
|
|
|
<ul>
|
|
<li>-1 (unsuccessful call) Check <em>errno</em> for additional information</li>
|
|
|
|
<li>0 (successful call) All of the data has been successfully sent</li>
|
|
|
|
<li>1 (interrupted call) The command was interrupted while sending data</li>
|
|
</ul>
|
|
|
|
<br>
|
|
<h3>Error Conditions</h3>
|
|
|
|
<p>When <em>send_file()</em> fails, <em>errno</em> can be set to one of the
|
|
following:</p>
|
|
|
|
<table cellpadding="5">
|
|
<!-- cols="15 85" -->
|
|
<tr>
|
|
<td align="left" valign="top"><em>[EACCES]</em></td>
|
|
<td align="left" valign="top">Permission denied.
|
|
|
|
<p>An attempt was made to access an object in a way forbidden by its object
|
|
access permissions. A thread does not have access to the specified file,
|
|
directory, component, or path.</p>
|
|
|
|
<p>If you are accessing a remote file through the Network File System, update
|
|
operations to file permissions at the server are not reflected at the client
|
|
until updates to data that is stored locally by the Network File System takes
|
|
place. (Several options on the Add Mounted File System (ADDMFS) command
|
|
determine the time between refresh operations of local data.) Access to a
|
|
remote file may also fail due to different mappings of user IDs (UID) or group
|
|
IDs (GID) on the local and remote systems.</p>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[EBADF]</em></td>
|
|
<td align="left" valign="top">Descriptor not valid.
|
|
|
|
<p>This error code indicates one of the following:</p>
|
|
|
|
<ul>
|
|
<li>The descriptor pointed to by the <em>socket_descriptor</em> parameter is
|
|
not a valid socket descriptor.<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>The <em>file_descriptor</em> parameter is not valid for this operation. The
|
|
specified descriptor is incorrect, does not refer to an open file, or refers to
|
|
a file that was only open for writing.</li>
|
|
</ul>
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[ECONVERT]</em></td>
|
|
<td align="left" valign="top">Conversion error.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[EFAULT]</em></td>
|
|
<td align="left" valign="top">Bad address.
|
|
|
|
<p>The system detected an address that was not valid while attempting to access
|
|
the <em>socket_descriptor</em> or one of the fields in the send_file
|
|
structure.</p>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[EINTR]</em></td>
|
|
<td align="left" valign="top">Interrupted function call.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[EINVAL]</em></td>
|
|
<td align="left" valign="top">Parameter not valid.
|
|
|
|
<p>This error code indicates one of the following:</p>
|
|
|
|
<ul>
|
|
<li>A NULL pointer was specified for the <em>sf_struct</em> parameter<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>The <em>file_offset</em> parameter specified a negative value.<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>The <em>file_offset</em> parameter specified a value that was greater than
|
|
the file size.<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>The <em>file_bytes</em> parameter would have resulted in a read operation
|
|
beyond the end of the file.<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>The <em>flags</em> parameter specified a value that was not valid.</li>
|
|
</ul>
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[EIO]</em></td>
|
|
<td align="left" valign="top">Input/output error.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[ENOBUFS]</em></td>
|
|
<td align="left" valign="top">There is not enough buffer space for the
|
|
requested operation.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[ENOTCONN]</em></td>
|
|
<td align="left" valign="top">Requested operation requires a connection.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[ENOTSAFE]</em></td>
|
|
<td align="left" valign="top">Function is not allowed in a job that is running
|
|
with multiple threads.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[ENOTSOCK]</em></td>
|
|
<td align="left" valign="top">The specified descriptor does not reference a
|
|
socket.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[EOPNOTSUPP]</em></td>
|
|
<td align="left" valign="top">Operation not supported.
|
|
|
|
<p>The <em>socket_descriptor</em> parameter references a socket that does not
|
|
support the <em>send_file()</em> function. The <em>send_file()</em> function is
|
|
only valid on sockets that have an address family of <samp>AF_INET</samp>, <samp>AF_INET6</samp>, <samp>AF_UNIX</samp>, or
|
|
<samp>AF_UNIX_CCSID</samp> and a socket type of <samp>SOCK_STREAM</samp>.</p>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[EOVERFLOW]</em></td>
|
|
<td align="left" valign="top">Object is too large to process.
|
|
|
|
<p>This error code indicates one of the following:</p>
|
|
|
|
<ul>
|
|
<li>The size of the file associated with <em>file_descriptor</em> parameter is
|
|
greater than 2 GB minus 1 byte.<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>The total number of bytes to be sent, <em>header_length</em> +
|
|
<em>file_bytes</em> + <em>trailer_length</em>, is greater than 4 GB minus 1,
|
|
the largest value that can be stored in the <em>bytes_sent</em> output
|
|
field.</li>
|
|
</ul>
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[EPIPE]</em></td>
|
|
<td align="left" valign="top">Broken pipe.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[EUNATCH]</em></td>
|
|
<td align="left" valign="top">The protocol required to support the specified
|
|
address family is not available at this time.<br>
|
|
<br>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top"><em>[EUNKNOWN]</em></td>
|
|
<td align="left" valign="top">Unknown system state.</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<br>
|
|
<br>
|
|
<h3>Error Messages</h3>
|
|
|
|
<table width="100%" cellpadding="5">
|
|
<!-- cols="15 85" -->
|
|
<tr>
|
|
<th align="left" valign="top">Message ID</th>
|
|
<th align="left" valign="top">Error Message Text</th>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top">CPE3418 E</td>
|
|
<td align="left" valign="top">Possible APAR condition or hardware failure.</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top">CPF3CF2 E</td>
|
|
<td align="left" valign="top">Error(s) occurred during running of &1
|
|
API.</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top">CPF9872 E</td>
|
|
<td align="left" valign="top">Program or service program &1 in library
|
|
&2 ended. Reason code &3.</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top">CPFA081 E</td>
|
|
<td align="left" valign="top">Unable to set return value or error code.</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td align="left" valign="top">CPFA0D4 E</td>
|
|
<td align="left" valign="top">File system error occurred.</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<br>
|
|
<br>
|
|
|
|
|
|
<h3><a name="HDRSDFUSAG"><strong>Usage Notes</strong></a></h3>
|
|
|
|
<ol>
|
|
<li>The <em>send_file()</em> function is only valid on sockets that have an
|
|
address family of <samp>AF_INET</samp>, <samp>AF_INET6</samp>, <samp>AF_UNIX</samp>, or <samp>AF_UNIX_CCSID</samp> and a
|
|
socket type of <samp>SOCK_STREAM</samp>. If the descriptor pointed to by the
|
|
<em>socket_descriptor</em> parameter does not have the correct address family
|
|
and socket type, -1 is returned and the <em>errno</em> value is set to
|
|
EOPNOTSUPP.<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>This function will fail with error code [ENOTSAFE] when all the following
|
|
conditions are true:
|
|
|
|
<ul>
|
|
<li>Where multiple threads exist in the job.<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>The object on which this function is operating resides in a file system
|
|
that is not threadsafe. Only the following file systems are threadsafe for this
|
|
function:
|
|
|
|
<ul>
|
|
<li>Root</li>
|
|
|
|
<li>QOpenSys</li>
|
|
|
|
<li>User-defined</li>
|
|
|
|
<li>QNTC</li>
|
|
|
|
<li>QSYS.LIB</li>
|
|
|
|
<li>QOPT</li>
|
|
|
|
<li>Network File System</li>
|
|
|
|
|
|
<li>QFileSvr.400</li>
|
|
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
|
|
<br>
|
|
</li>
|
|
|
|
<li>The <em>file_offset</em> parameter is used to specify a base zero location
|
|
in the file referenced by the <em>file_descriptor</em> parameter. If the
|
|
<em>file_bytes</em> parameter is set to a value of 1 and the
|
|
<em>file_offset</em> parameter is set to a value of 0, the first byte from the
|
|
file is sent. If the <em>file_offset</em> parameter is set to a value of 1, the
|
|
second byte from the file is sent.<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>An application that uses the <em>send_file()</em> API may specify the
|
|
O_SHARE_RDONLY or the O_SHARE_NONE option on the <em>open()</em> call when the
|
|
file represented by <em>file_descriptor</em> is first opened. These options
|
|
prevent other jobs or threads on the system from updating the file while it is
|
|
being transmitted.<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>If the O_TEXTDATA option was specified on the <em>open()</em> call when the
|
|
file represented by <em>file_descriptor</em> was first opened, the data is sent
|
|
from the file assuming it is in textual form. The data is converted from the
|
|
code page of the file to the code page of the application, job, or system as
|
|
follows:<br>
|
|
|
|
|
|
<ul>
|
|
<li>When reading from a true stream file, any line-formatting characters (such
|
|
as carriage return, tab, and end-of-file) are just converted from one code page
|
|
to another.<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li>When reading from record files that are being used as stream files,
|
|
end-of-line characters are added to the end of the data in each record.</li>
|
|
</ul>
|
|
|
|
<p>If O_TEXTDATA was not specified on the <em>open()</em> call, the data is
|
|
sent from the file without conversion.</p>
|
|
|
|
<p>Regardless of whether or not O_TEXTDATA was specified on the <em>open()</em>
|
|
call, the <em>header_data</em> and <em>trailer_data</em> are not translated. It
|
|
is the application's responsibility to translate the <em>header_data</em> and
|
|
<em>trailer_data</em> to the correct code page before calling
|
|
<em>send_file()</em>. The <em>send_file()</em> function will not translate the
|
|
data buffers pointed to by the <em>header_data</em> and <em>trailer_data</em>
|
|
parameters prior to sending them.</p>
|
|
|
|
<p><strong>Note:</strong> The ability to do code-page translation is an i5/OS
|
|
specific extension to the <em>send_file()</em> API. The overhead to translate
|
|
the file will have an effect on the performance of the <em>send_file()</em>
|
|
API.</p>
|
|
</li>
|
|
|
|
<li>The <em>send_file()</em> function attempts to write <em>header_length</em>
|
|
from the buffer pointed to by <em>header_data</em>, followed by
|
|
<em>file_bytes</em> from the file associated with <em>file_descriptor</em>,
|
|
followed by <em>trailer_length</em> from the buffer pointed to by
|
|
<em>trailer_data</em>, over the connection associated with
|
|
<em>socket_descriptor</em>. As the data is sent, the API will update the
|
|
variables in the sf_parms structure so that if the <em>send_file()</em> API is
|
|
interrupted by a signal, the application simply needs to reissue the
|
|
<em>send_file()</em> call using the same parameters.
|
|
|
|
<p><strong>Note:</strong> The value that is passed in for the <em>flags</em>
|
|
parameter is ignored if the <em>send_file()</em> API is interrupted by a
|
|
signal.</p>
|
|
</li>
|
|
|
|
<li>When you develop in C-based languages and this function is compiled with
|
|
_LARGE_FILES defined, it will be mapped to <em>send_file64()</em>. Note that
|
|
the type of the <em>sf_struct</em> parameter, <samp>struct sf_parms *</samp>,
|
|
also will be mapped to type <samp>struct sf_parms64 *</samp>.</li>
|
|
</ol>
|
|
|
|
<br>
|
|
<h3>Related Information</h3>
|
|
|
|
<ul>
|
|
<li><a href="acceptr.htm">accept_and_recv()</a>--Wait for Connection Request
|
|
and Receive the First Message That Was Sent<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li><a href="close.htm">close()</a>--Close File or Socket Descriptor<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li><a href="open.htm">open()</a>--Open File<br>
|
|
<br>
|
|
</li>
|
|
|
|
<li><a href="send.htm">send()</a>--Send Data</li>
|
|
</ul>
|
|
|
|
<br>
|
|
<hr>
|
|
API introduced: V4R3
|
|
|
|
<hr>
|
|
<center>
|
|
<table cellpadding="2" cellspacing="2">
|
|
<tr align="center">
|
|
<td valign="middle" align="center"><a href="#Top_Of_Page">Top</a> |
|
|
<a href="unix.htm">UNIX-Type APIs</a> |
|
|
<a href="aplist.htm">APIs by category</a> </td>
|
|
</tr>
|
|
</table>
|
|
</center>
|
|
</body>
|
|
</html>
|
|
|