 |
 |
 |
15) Informatique distribuée |
|
 |
|
Texte original |
 |
Traducteur : Jean-Pierre VIDAL, Alban PEIGNIER |
|
 |
|
 |
 |
 |
 |
 |
 |
|
 |
|
 |
 |
 |
The join process
|
 |
Le processus de jonction
|
 |
 |
 |
Once a service provider has a service
registrar object, the end product of discovery, it is ready to do a
join—to become part of the federation of services that are registered in
the lookup service. To do a join, the service provider invokes the
register( ) method on the service registrar object, passing as a
parameter an object called a service item, a bundle of objects that describe the
service. The register( ) method sends a copy of the service item up
to the lookup service, where the service item is stored. Once this has
completed, the service provider has finished the join process: its service has
become registered in the lookup service.
|
 |
Dès lors qu'un fournisseur de service possède un enregistreur de
service, le produit final du processus de découverte, il est prêt à entreprendre une jonction
pour intégrer la fédération des services qui sont enregistrés auprès du service de recherche. Pour
réaliser une jonction, le fournisseur de service fait appel à la méthode
register( )de l' "font-weight: medium">enregistreur de service,
passant en argument un objet appelé élément de service (service item), un ensemble d'objets qui
décrit le service. La méthode register( )envoie une copie de cet élément de
service au service de recherche, où celui-ci sera stocké. Lorsque ceci est achevé, le fournisseur
de service a fini le processus de jonction : son service est maintenant enregistré auprès du
service de recherche.
|
 |
 |
 |
The service item is a container for
several objects, including an object called a service object, which
clients can use to interact with the service. The service item can also include
any number of attributes, which can be any object. Some potential
attributes are icons, classes that provide GUIs for the service, and objects
that give more information about the service.
|
 |
L'élément de service contient plusieurs objets, parmi lesquels un objet
appelé un objet service, que les clients utilisent pour interagir avec le service.
L'élément de service peut aussi inclure une certain nombre d'attributs, qui peuvent
être n'importe quel objet. Certains de ces attributs sont des icônes, des classes qui fournissent
des interfaces graphiques pour le service et des objets apportant plus de détails sur le
service.
|
 |
 |
 |
Service objects usually implement one or
more interfaces through which clients interact with the service. For example, a
lookup service is a Jini service, and its service object is the service
registrar. The register( ) method invoked by service providers
during join is declared in the ServiceRegistrar interface (a member of
the net.jini.core.lookup package), which all service registrar objects
implement. Clients and service providers talk to the lookup service through the
service registrar object by invoking methods declared in the
ServiceRegistrar interface. Likewise, a disk drive would provide a
service object that implemented some well-known storage service interface.
Clients would look up and interact with the disk drive by this storage service
interface.
|
 |
Les objects service implémentent généralement une ou plusieurs interfaces à
travers lesquelles les clients interagissent avec le service. Par exemple, le service de recherche
est un service Jini, et son objet service est un service de registre. La méthode
register( )appelée par les fournisseurs de service durant la jonction est
déclarée dans l'interface ServiceRegistrar(un membre du package
net.jini.core.lookup) que tous les services de registre implémentent. Les clients
et les fournisseurs de registre discutent avec le service de recherche à travers l'objet de service
de registre en invoquant les méthodes déclarées dans l'interface ServiceRegistrar.
De la même manière, le disque dur fournit un objet service qui implémente l'une des interfaces
connues de service de stockage. Les clients peuvent rechercher le disque dur et interagir avec
celui-ci par cette interface de service de stockage.
|
 |
 |
 |
The lookup process
|
 |
Le processus de recherche
|
 |
 |
 |
Once a service has registered with a
lookup service via the join process, that service is available for use by
clients who query that lookup service. To build a distributed system of services
that will work together to perform some task, a client must locate and enlist
the help of the individual services. To find a service, clients query lookup
services via a process called lookup.
|
 |
Une fois qu'un service a été enregistré par un service de recherche grâce
au processus de jonction, ce service est utilisable par les clients qui le demandent au service de
recherche. Pour construire un système distribué de services qui collaborent pour réaliser une
tâche, un client doit localiser ses services et s'aider de chacun d'eux. Pour trouver un service,
les clients formulent des requêtes auprès des services de recherche par l'intermédiaire d'un
processus appelé recherche.
|
 |
 |
 |
To perform a lookup, a client invokes the
lookup( ) method on a service registrar object. (A client, like a
service provider, gets a service registrar through the previously-described
process of discovery.) The client passes as an argument to lookup( )
a service template, an object that serves as search criteria for the
query. The service template can include a reference to an array of Class
objects. These Class objects indicate to the lookup service the Java type
(or types) of the service object desired by the client. The service template can
also include a service ID, which uniquely identifies a service, and
attributes, which must exactly match the attributes uploaded by the service
provider in the service item. The service template can also contain wildcards
for any of these fields. A wildcard in the service ID field, for example, will
match any service ID. The lookup( ) method sends the service
template to the lookup service, which performs the query and sends back zero to
any matching service objects. The client gets a reference to the matching
service objects as the return value of the lookup( ) method.
|
 |
Pour réaliser une recherche, un client fait appel à la méthode
lookup( ) d'un service de registre (comme un fournisseur de service, un
client obtient un service de registre grâce au processus de découverte décrit précédemment). Le
client passe en argument un modèle de service à lookup( ), un objet utilisé
comme critère de recherche. Le modèle de service peut inclure une référence à un tableau
d'objets Class. Ces objets Classindiquent au service de recherche
le type Java (ou les types)) de l'objet service voulu par le client. Le modèle de service peut
aussi inclure un service ID, qui identifie de manière unique le service, ainsi que des
attributs, qui doivent correspondre exactement aux attributs fournis par le fournisseur de service
dans l'élément de service. Le modèle de service peut aussi contenir
des critères génériques pour n'importe quel attribut. Par exemple, un critère générique dans le
champ service ID correspondra à n'importe quel service ID. La méthode lookup( ) envoie le modèle de service au service de recherche, qui
exécute la requête et renvoie s'il y en a les objets services
correspondants. Le client récupère une référence vers ces objets services comme résultat de la
méthode lookup( ).
|
 |
 |
 |
In the general case, a client looks up a
service by Java type, usually an interface. For example, if a client needed to
use a printer, it would compose a service template that included a Class
object for a well-known interface to printer services. All printer services
would implement this well-known interface. The lookup service would return a
service object (or objects) that implemented this interface. Attributes can be
included in the service template to narrow the number of matches for such a
type-based search. The client would use the printer service by invoking methods
from the well-known printer service interface on the service object.
|
 |
En général, un client recherche un service selon le type Java, souvent une
interface. Par exemple, si un client avait besoin d'utiliser une imprimante, il pourrait créer un
modèle de service qui comprend un objet Class d'une interface connue de services
d'impression. Tous les services d'impression implémenteraient cette interface connue. Le service de
recherche retournerait un ou plusieurs objets services qui implémentent cette interface. Les
attributs peuvent être inclus dans le modèle de service pour réduire le nombre de correspondances
de ce genre de recherche par type. Le client pourrait utiliser le service d'impression en invoquant
sur l'objet service les méthodes définies dans l'interface.
|
 |
 |
 |
Separation of interface and implementation
|
 |
Séparation de l'interface et de l'implémentation
|
 |
 |
 |
Jini’s architecture brings
object-oriented programming to the network by enabling network services to take
advantage of one of the fundamentals of objects: the separation of interface and
implementation. For example, a service object can grant clients access to the
service in many ways. The object can actually represent the entire service,
which is downloaded to the client during lookup and then executed locally.
Alternatively, the service object can serve merely as a proxy to a remote
server. Then when the client invokes methods on the service object, it sends the
requests across the network to the server, which does the real work. A third
option is for the local service object and a remote server to each do part of
the work.
|
 |
L'architecture Jini met en place pour le réseau une programmation
orientée-objet en permettant aux services du réseau de tirer parti de l'un des fondements des
objets : la séparation de l'interface et l'implémentation. Par exemple, un objet service peut
permettre aux clients d'accéder au service de différentes manières. L'objet peut réellement
représenter le service entier, qui sera donc téléchargé par le client lors de la recherche et
exécuté localement ensuite. Autrement, l'objet service peut n'être qu'un proxy vers un serveur
distant. Lorsqu'un client invoque des méthodes de l'objet service, il envoie les requêtes au
serveur à travers le réseau, qui fait réellement le travail. Une troisième option consiste à
partager le travail entre l'objet service local et le serveur distant.
|
 |
 |
 |
One important consequence of Jini’s
architecture is that the network protocol used to communicate between a proxy
service object and a remote server does not need to be known to the client. As
illustrated in the figure below, the network protocol is part of the
service’s implementation. This protocol is a private matter decided upon
by the developer of the service. The client can communicate with the service via
this private protocol because the service injects some of its own code (the
service object) into the client’s address space. The injected service
object could communicate with the service via RMI, CORBA, DCOM, some home-brewed
protocol built on top of sockets and streams, or anything else. The client
simply doesn’t need to care about network protocols, because it can talk
to the well-known interface that the service object implements. The service
object takes care of any necessary communication on the network.
|
 |
Une conséquence importante de l'architecture Jini est que le protocole
réseau utilisé pour communiquer entre l'objet service proxy et le serveur distant n'a pas besoin
d'être connu du client. Comme le montre la figure suivante, le protocole réseau est une partie de
l'implémentation du service. Ce protocole est une question privée prise en compte par le
développeur du service. Le client peut communiquer avec l'implémentation du service à travers un
protocole privée car le service injecte un peu de son propre code (l'objet service) au sein de
l'espace d'adressage du client. L'objet service ainsi injecté peut communiquer avec le service à
travers RMI, CORBA, DCOM, un protocole fait maison construit sur des sockets et des flux ou
n'importe quoi d'autre. Le client ne porte simplement aucune attention quant aux protocoles réseau,
puisqu'il ne fait que communiquer avec l'interface publique que le service implémente. L'objet
service prend en charge toutes les communications nécessaires sur le réseau.
|
 |
 |
 |
|
 |
height="38" border="0">
|
 |
 |
 |
The client talks to the service
through a well-known interface
|
 |
Le client communique avec le service à travers une interface
publique
|
 |
 |
 |
Different implementations of the same
service interface can use completely different approaches and network protocols.
A service can use specialized hardware to fulfill client requests, or it can do
all its work in software. In fact, the implementation approach taken by a single
service can evolve over time. The client can be sure it has a service object
that understands the current implementation of the service, because the client
receives the service object (by way of the lookup service) from the service
provider itself. To the client, a service looks like the well-known interface,
regardless of how the service is implemented.
|
 |
Différentes implémentations de la même interface d'un service peuvent
utiliser des approches et des protocoles réseau totalement différents. Un service peut utiliser un
matériel spécialisé pour répondre aux requêtes clientes, ou il peut tout réaliser de manière
logicielle. En fait, le choix d'implémentation d'un même service peut évoluer dans le temps. Le
client peut être sûr qu'il possède l'objet service qui comprend l'implémentation actuelle de ce
service, puisque le client reçoit l'objet service (grâce au service de recherche) du fournisseur du
service lui-même. Du point de vue du client, le service ressemble à une interface publique, sans
qu'il ait à se soucier de l'implémentation du service.
|
 |
 |
 |
Abstracting distributed systems
|
 |
Abstraction des systèmes distribués
|
 |
 |
 |
Jini attempts to raise the level of
abstraction for distributed systems programming, from the network protocol level
to the object interface level. In the emerging proliferation of embedded devices
connected to networks, many pieces of a distributed system may come from
different vendors. Jini makes it unnecessary for vendors of devices to agree on
network level protocols that allow their devices to interact. Instead, vendors
must agree on Java interfaces through which their devices can interact. The
processes of discovery, join, and lookup, provided by the Jini run-time
infrastructure, enable devices to locate each other on the network. Once they
locate each other, devices can communicate with each other through Java
interfaces.
|
 |
Jini tente d'élever passer le niveau d'abstraction de la programmation de
systèmes distribués, passant du niveau du protocole réseau à celui de l'interface objet. Dans
l'optique d'une prolifération des systèmes embarqués connectés au réseau, beaucoup de pièces d'un
système distribué pourront venir de fournisseurs différents. Jini évite aux fournisseurs de devoir
se mettre d'accord sur les protocoles réseau qui permettent à leurs systèmes d'interagir. A la
place, les fournisseurs doivent se mettre d'accord sur les interfaces Java à travers lesquelles
leurs systèmes peuvent interagir. Les processus de découverte, de jonction et de recherche, fournis
par l'infrastructure d'exécution de Jini, permettront aux systèmes de se localiser les uns les
autres sur le réseau. Une fois qu'ils se sont localisés, les systèmes sont capables de communiquer
entre eux à travers des interfaces Java.
|
 |
 |
 |
Summary
|
 |
Résumé
|
 |
 |
 |
Along with Jini for local device networks, this chapter has introduced some, but not all, of the components that Sun refers to as J2EE: the Java 2 Enterprise Edition. The goal of J2EE is to build a set of tools that allows the Java developer to build server-based applications much more quickly, and in a platform-independent way. It’s not only difficult and time-consuming to build such applications, but it’s especially hard to build them so that they can be easily ported to other platforms, and also to keep the business logic separated from the underlying details of the implementation. J2EE provides a framework to assist in creating server-based applications; these applications are in demand now, and that demand appears to be increasing. |
 |
Avec Jini pour des réseaux de systèmes locaux, ce chapitre vous a présenté
une partie (une partie seulement) des composants que Sun regroupe sous le terme de J2EE : the Java
2 Enterprise Edition. Le but de J2EE est de construire un ensemble d'outils qui permettent au
développeur Java de construire des applications serveurs beaucoup plus rapidement et indépendamment
de la plate-forme. Construire de telles applications n'est pas seulement difficile et coûteux en
temps, mais il est particulièrement dur de les construire en faisant en sorte qu'elles puissent
être facilement portées sur une autre plate-formes, et aussi que la logique métier soit isolée des
détails relevant de l'implémentation. J2EE met à disposition une structure pour assister la
création d'applications serveurs ; ces applications sont très demandées en ce moment, et cette
demande semble grandir.
|
 |
 |
 |
Exercises
|
 |
Exercices
|
 |
 |
 |
Solutions to selected exercises can be found in the electronic document The Thinking in Java Annotated Solution Guide, available for a small fee from www.BruceEckel.com.
|
 |
On triouvera les solutions des exercices sélectionnés dans le document
électronique The Thinking in Java Annotated Solution Guide, disponible pour une
participation minime à www.BruceEckel.com.
|
 |
 |
 |
- Compile and run the
JabberServer and JabberClient programs in this chapter. Now edit the files to remove all of the buffering for the input and output, then compile and run them again to observe the results. - Create a
server that asks for a password, then opens a file and sends the file over the network connection. Create a client that connects to this server, gives the appropriate password, then captures and saves the file. Test the pair of programs on your machine using the localhost (the local loopback IP address 127.0.0.1 produced by calling InetAddress.getByName(null)). - Modify
the server in Exercise 2 so that it uses multithreading to handle multiple clients. - Modify
JabberClient.java so that output flushing doesn’t occur and observe the effect. - Modify
MultiJabberServer so that it uses thread pooling. Instead of throwing away a thread each time a client disconnects, the thread should put itself into an “available pool” of threads. When a new client wants to connect, the server will look in the available pool for a thread to handle the request, and if one isn’t available, make a new one. This way the number of threads necessary will naturally grow to the required quantity. The value of thread pooling is that it doesn’t require the overhead of creating and destroying a new thread for each new client. - Starting
with ShowHTML.java, create an applet that is a password-protected gateway to a particular portion of your Web site. - Modify
CIDCreateTables.java so that it reads the SQL strings from a text file instead of CIDSQL. - Configure
your system so that you can successfully execute CIDCreateTables.java and LoadDB.java. - Modify
ServletsRule.java by overriding the destroy( ) method to save the value of i to a file, and and the init( ) method to restore the value. Demonstrate that it works by rebooting the servlet container. If you do not have an existing servlet container, you will need to download, install, and run Tomcat from jakarta.apache.org in order to run servlets. - Create a
servlet that adds a cookie to the response object, thereby storing it on the client’s site. Add code to the servlet that retrieves and displays the cookie. If you do not have an existing servlet container, you will need to download, install, and run Tomcat from jakarta.apache.org in order to run servlets. - Create a
servlet that uses a Session object to store session information of your choosing. In the same servlet, retrieve and display that session information. If you do not have an existing servlet container, you will need to download, install, and run Tomcat from jakarta.apache.org in order to run servlets. - Create a
servlet that changes the inactive interval of a session to 5 seconds by calling getMaxInactiveInterval( ). Test to see that the session does indeed expire after 5 seconds. If you do not have an existing servlet container, you will need to download, install, and run Tomcat from jakarta.apache.org in order to run servlets. - Create a
JSP page that prints a line of text using the <H1> tag. Set the color of this text randomly, using Java code embedded in the JSP page. If you do not have an existing JSP container, you will need to download, install, and run Tomcat from jakarta.apache.org in order to run JSPs. - Modify the
maximum age value in Cookies.jsp and observe the behavior under two different browsers. Also note the difference between just re-visiting the page, and shutting down and restarting the browser. If you do not have an existing JSP container, you will need to download, install, and run Tomcat from jakarta.apache.org in order to run JSPs. - Create a JSP
with a field that allows the user to enter the session expiration time and and a second field that holds data that is stored in the session. The submit button refreshes the page and fetches the current expiration time and session data and puts them in as default values of the aforementioned fields. If you do not have an existing JSP container, you will need to download, install, and run Tomcat from jakarta.apache.org in order to run JSPs. - (More
challenging) Take the VLookup.java program and modify it so that when you click on the resulting name it automatically takes that name and copies it to the clipboard (so you can simply paste it into your email). You’ll need to look back at Chapter 13 to remember how to use the clipboard in JFC.
|
 |
- Compiler et lancer les programmes JabberServer et
JabberClient de ce chapitre. Éditer ensuite les fichiers pour supprimer les
« buffering » d'entrée et de sortie, compiler et relancer, observer le
résultat.
- Créer un serveur qui demande un mot de passe avant d'ouvrir un fichier et
de l'envoyer sur la connexion réseau. Créer un client qui se connecte à ce serveur, donne le mot de
passe requis, puis capture et sauve le fichier. Tester la paire de programmes sur votre machine en
utilisant localhost (l'adresse IP de boucle locale 127.0.0.1
obtenue en appelant InetAddress.getByName(null)).
- Modifier le serveur de l' Exercice 2 afin qu'il utilise le multithreading
pour servir plusieurs clients.
- Modifier JabberClient.java afin qu'il n'y ait pas de
vidage du tampon de sortie, observer le résultat.
- Modifier MultiJabberServer afin qu'il utilise la technique
de « surveillance de thread » « thread pooling ». Au lieu que le
thread se termine lorsqu'un client se déconnecte, il intègre de lui-même un « pool « de
threads disponibles ». Lorsqu'un nouveau client demande à se connecter, le serveur cherche
d'abord dans le pool un thread existant capable de traiter la demande, et s'il n'en trouve pas, en
crée un. De cette manière le nombre de threads nécessaires va grossir naturellement jusqu'à la
quantité maximale nécessaire. L'intérêt du « thread pooling » est d'éviter l'overhead
engendré par la création et la destruction d'un nouveau thread pour chaque client.
- À partir de ShowHTML.java, créer une applet qui fournisse
un accès protégé par mot de passe à un sous-ensemble particulier de votre site Web.
- Modifier CIDCreateTables.java afin qu'il lise les chaînes
SQL depuis un fichier texte plutôt que depuis CIDSQL.
- Configurer votre système afin d'exécuter avec succès
CIDCreateTables.java et LoadDB.java.
- Modifier ServletsRule.java en surchargeant la méthode
destroy( ) afin qu'elle sauvegarde la valeur de i dans un
fichier, et la méthode init( ) pour qu'elle restaure cette valeur. Montrer
que cela fonctionne en rechargeant le conteneur de servlet. Si vous ne possédez pas de conteneur de
servlet, il vous faudra télécharger, installer, et exécuter Tomcat depuis
jakarta.apache.org afin de travailler avec les servlets.
- Créer une servlet qui ajoute un cookie à l'objet réponse, lequel sera
stocké sur le site client. Ajouter à la servlet le code qui récupère et affiche le cookie. Si vous
n'avez pas de conteneur de servlet, il vous faudra télécharger, installer, et exécuter Tomcat
depuis jakarta.apache.org afin de travailler avec les servlets.
- Créer une servlet utilisant un objet Session stockant
l'information de session de votre choix. Dans la même servlet, récupérer et afficher cette
information de session. Si vous ne possédez pas de conteneur de servlet, il vous faudra
télécharger, installer, et exécuter Tomcat depuis jakarta.apache.org afin de travailler
avec les servlets.
- Créer une servlet qui change la valeur de « inactive interval »
de l'objet session pour la valeur 5 secondes en appelant
getMaxInactiveInterval( ). Tester pour voir si la session se termine
naturellement après 5 secondes. Si vous n'avez pas de conteneur de servlet, il vous faudra
télécharger, installer, et exécuter Tomcat depuis jakarta.apache.org afin de travailler
avec les servlets.
- Créer une page JSP qui imprime une ligne de texte en utilisant le tag
<H1>. Générer la couleur de ce texte aléatoirement, au moyen du code Java inclus dans la page
JSP. Si vous ne possédez pas de conteneur JSP, il vous faudra télécharger, installer, et exécuter
Tomcat depuis jakarta.apache.org afin de travailler avec JSP.
- Modifier la date d'expiration dans Cookies.jsp et observer
l'effet avec deux navigateurs différents. Constater également les différences entre le fait de
visiter à nouveau la même page, et celui de fermer puis réouvrir le navigateur. Si vous ne possédez
pas de conteneur JSP, il vous faudra télécharger, installer, et exécuter Tomcat depuis
jakarta.apache.org afin de travailler avec JSP.
- Créer une page JSP contenant un champ autorisant l'utilisateur à définir
l'heure de fin de session ainsi qu'un second champ contenant les données stockées dans cette
session. Le bouton de soumission rafraîchit la page, prend les valeurs courantes de l'heure de fin
et les données de la session, et les garde en tant que valeurs par défaut des champs susmentionnés.
Si vous ne possédez pas de conteneur JSP, il vous faudra télécharger, installer, et exécuter Tomcat
depuis jakarta.apache.org afin de travailler avec JSP.
- (Encore plus difficile). Modifier le programme
VLookup.java de telle manière qu'un clic sur le nom résultat copie automatiquement
ce nom dans les presse-papier (ce qui vous permet de le coller facilement dans votre email). Vous
aurez peut-être besoin de revenir en arrière sur le chapitre 13 pour vous remémorer l'utilisation
du presse-papier dans les JFC.
|
 |
 |
 |
|
 |
[68]Ce qui représente un peu plus de 4
milliards de valeurs, ce qui sera vite épuisé. Le nouveau standard pour les adresses IP utilisera
des nombres de 128 octets, qui devraient produire assez d'adresses IP pour le futur
proche.
|
 |
 |
 |
|
 |
[69]Beaucoup de neurones sont morts après
une atroce agonie pour découvrir cette information.
|
 |
 |
 |
|
 |
[70]Cette section a été réalisée par
Robert Castaneda, avec l'aide de Dave Bartlett.
|
 |
 |
 |
|
 |
[71]Cette section a
été réalisée par Bill Venners (www.artima.com).
|
 |
 |
 |
[72] This means a maximum of just over four billion numbers, which is rapidly running out. The new standard for IP addresses will use a 128-bit number, which should produce enough unique IP addresses for the foreseeable future.
|
 |
[72]Cela signifie un nombre maximum
légèrement supérieur à quatre milliards, ce qui s'avère rapidement insuffisant. Le nouveau standard
des adresses IP utilisera un nombre représenté sur 128 bits, ce qui devrait fournir suffisamment
d'adresses IP uniques pour le futur prévisible.
|
 |
 |
 |
[73] Created by Dave Bartlett.
|
 |
[73]Créé par Dave Bartlett.
|
 |
 |
 |
[74] Dave Bartlett was instrumental in the development of this material, and also the JSP section.
|
 |
[74]Dave Bartlett participa activement à
ce développement, ainsi qu'à la section JSP.
|
 |
 |
 |
[75] A primary tenet of Extreme Programming (XP). See www.xprogramming.com.
|
 |
[75]« A primary tenet of Extreme
Programming (XP) ». Voir www.xprogramming.com.
|
 |
 |
 |
[76] Many brain cells died in agony to discover this information.
|
 |
|
 |
 |
 |
[77] This section was contributed by Robert Castaneda, with help from Dave Bartlett.
|
 |
|
 |
 |
 |
[78] This section was contributed by Bill Venners (www.artima.com).
[ Previous Chapter ] [ Short TOC ] [ Table of Contents ] [ Index ] [ Next Chapter ] Last Update:04/24/2000
|
 |
|
 |
 |
 |
 |
 |
 |
 |
 |
|
 |
 |
 |
|
 |