579 lines
24 KiB
Plaintext
579 lines
24 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<!-- Copyright Bob Jacobsen 2008 -->
|
|
<!-- Updated by Blorec Hervé 2013-09-26-->
|
|
|
|
<title>JMRI: FAQ Scripts</title>
|
|
<!--#include virtual="/help/fr/parts/Style.shtml" -->
|
|
</head>
|
|
|
|
<body>
|
|
<!--#include virtual="/help/fr/parts/Header_fr.shtml" -->
|
|
<div id="mBody">
|
|
<!--#include virtual="Sidebar.shtml" -->
|
|
<div id="mainContent">
|
|
<!-- Page Body -->
|
|
|
|
<h1>JMRI: FAQ Scripts</h1>
|
|
|
|
<p class="subtitle">Foire aux questions sur les scripts JMRI
|
|
avec Jython</p>
|
|
|
|
<h2>Où puis-je en apprendre davantage sur le langage
|
|
Jython?</h2>
|
|
|
|
<div class="para">
|
|
Voir la page
|
|
|
|
<p><a href="Python.shtml">Python & JMRI</a> pour plus
|
|
d'informations, y compris sur les pointeurs vers des
|
|
articles, etc Voir aussi les liens de navigation à
|
|
gauche.</p>
|
|
</div>
|
|
|
|
<h2>En quoi Jython et Python diffèrent-ils?</h2>
|
|
|
|
<div class="para">
|
|
<p>Aux fins de la rédaction de scripts JMRI, ils ne
|
|
diffèrent pas beaucoup. La plupart des
|
|
différences impliquent ce qui se passe en cas
|
|
d'erreur . Il y a aussi quelques restrictions sur ce que
|
|
vous pouvez faire avec les informations de configuration de
|
|
l'ordinateur , etc, en Jython, mais ce ne sont pas des
|
|
choses qu'un script JMRI est susceptible d'avoir
|
|
besoin.</p>
|
|
|
|
<p>Quelques informations supplémentaires sur les
|
|
différences sont <a href=
|
|
"http://jython.sourceforge.net/docs/differences.html">disponibles
|
|
ici</a>.</p>
|
|
</div>
|
|
|
|
<h2>Où puis-je trouver des exemples de scripts
|
|
JMRI?</h2>
|
|
|
|
<div class="para">
|
|
Voir la <a href="Examples.shtml">page exemples</a> . En
|
|
outre, la page <a href="Start.shtml">introduction</a>
|
|
montre quelques-unes des commandes de base.
|
|
</div>
|
|
|
|
<h2>Qu'est-ce que des mots comme " <code>import</code> ",
|
|
" <code>"classe</code> ", etc, dans les fichiers
|
|
d'exemple veulent dire?</h2>
|
|
|
|
<div class="para">
|
|
Ils font partie du langage utilisé pour les
|
|
scripts jython.
|
|
|
|
<p>Les importations permettent de se
|
|
référer à des choses par des noms
|
|
plus courts, essentiellement raconter jython
|
|
"rechercher Jarray, les paquets JMRI reconnaître
|
|
tous les noms là-bas ". Pour quelqu'un essayant
|
|
de comprendre ce script, vous pouvez simplement les
|
|
traiter comme des "assurer que le programme peut
|
|
trouver les pièces que nous voulons ".</p>
|
|
|
|
<p>"Classe" signifie "commencer la définition
|
|
d'un groupe de choses qui vont ensemble "( A vous tous
|
|
les autres experts, s'il vous plaît ne me sauter
|
|
pas dessus au sujet de cela, je comprends à la
|
|
fois le polymorphisme
|
|
intrinsèque/extrinsèque, j'ai juste
|
|
essayer d'obtenir l'idée
|
|
générale).</p>
|
|
|
|
<p>Par exemple, dans le fichier SigletExample.py il y a
|
|
une description d'une "Classe" appelée
|
|
SigletExample, qui contient deux
|
|
routines/fonctions/membres: Un sous-programme
|
|
appelé "defineIO", et un appelé
|
|
"setOutput"</p>
|
|
|
|
<p>Cette "classe" est associée à une
|
|
autre classe appelé "Siglet" (en fait
|
|
jmri.jmrit.automat.Siglet; c'est encore une chose avec
|
|
une longue désignation), qui sait quand il faut
|
|
appeler les routines par ces deux noms pour obtenir
|
|
qu'elles fassent ce que vous voulez.</p>
|
|
|
|
<p>Essentiellement, vous définissez deux parties
|
|
("defineIO" & "setOutput") qui se branchent dans
|
|
une structure pré-existante pour piloter les
|
|
signaux. Cette structure pré-existante est
|
|
très puissante, et vous permet de faire toutes
|
|
sortes de choses, mais fournit également cette
|
|
méthode pour essayer de le garder simple.</p>
|
|
|
|
<p>OK, à ce point les yeux de la plupart des
|
|
gens sont entièrement retournés. Votre
|
|
meilleur pari quand à commencer par ce truc est
|
|
d'utiliser la copie et "modifier " l'approche du
|
|
développement logiciel. Il est bon d'essayer de
|
|
comprendre le contenu entier du fichier, mais ne vous
|
|
inquiétez pas si vous ne le comprenez pas assez
|
|
bien pour être capable de le recréer
|
|
à partir de zéro. Au lieu de cela, il
|
|
suffit de modifier de petits morceaux et jouer
|
|
avec.</p>
|
|
</div>
|
|
|
|
<h2>Y at-il besoin de conventions de
|
|
dénomination?</h2>
|
|
|
|
<div class="para">
|
|
Dans de nombreux fichiers d'exemple, les aiguillages
|
|
sont visés par des noms comme "to 12", les
|
|
signaux par des noms comme "si21", et les capteurs par
|
|
des noms comme "bo45". Ces conventions sont nées
|
|
de la façon de coder héritée de
|
|
certains vieux code, et ils peuvent rendre le code plus
|
|
clair. Mais ils ne sont en aucun cas nécessaire;
|
|
le programme ne se soucie pas ce que vous appelez les
|
|
variables.
|
|
|
|
<p>Par exemple, "self.to12" est juste le nom d'une
|
|
variable. Vous pouvez appeler ça comme vous
|
|
voulez, par exemple
|
|
self.MyBigFatNameForTheLeftTurnout</p>
|
|
|
|
<p>Le "self" est une partie complètement locale;
|
|
"self" se réfère à "un objet de la
|
|
classe particulière j'ai bien défini
|
|
dès maintenant ". Alternativement, vous pouvez
|
|
définir une variable globale, mais ce n'est pas
|
|
recommandé. Si vous avez plusieurs scripts qui
|
|
fonctionnent (et vous pouvez en avoir autant que vous
|
|
voulez comme nous vous recommandons de placer chaque
|
|
tête de signal dans un script distinct), les
|
|
variables peuvent se confondre si vous utilisez le
|
|
même nom de variable pour dire des choses trop
|
|
différentes. En utilisant le "self" comme
|
|
celui-ci vous vous s'assurer que cela n'arrive pas.</p>
|
|
|
|
<p>Notez que les aiguillages, etc, ont des "Noms
|
|
systèmes" qui ressemblent à "LT12". Vous
|
|
verrez ceci occasionnellement, mais c'est quelque chose
|
|
de différent de celui des noms de variables dans
|
|
un fichier de script.</p>
|
|
</div>
|
|
|
|
<a name="windows" id="windows"></a>
|
|
<h2>Un Script Peut-il
|
|
accéder à une application fenêtres de
|
|
JMRI ?</h2>
|
|
|
|
<div class="para">
|
|
Vos scripts peuvent modifier les
|
|
propriétés de tous les fenêtres
|
|
principales JMRI. Elles sont toutes des objets
|
|
jmri.util.JmriJFrame, elles ont donc toutes les
|
|
différentes méthodes d'une JFrame Swing.
|
|
Par exemple, cet extrait de code
|
|
|
|
<p><code>window =
|
|
jmri.util.JmriJFrame.getFrameList()[1]<br>
|
|
window.setLocation(java.awt.Point(0,0))</code></p>
|
|
|
|
<p>localise la fenêtre principale de
|
|
l'application, et définit sa situation dans le
|
|
coin supérieur gauche de l'écran.</p>
|
|
|
|
<p>Le <code>jmri.util.JmriJFrame.getFrameList( )</code>
|
|
appelé dans la première ligne renvoie une
|
|
liste des fenêtres existantes.
|
|
L'élément [0] de cette liste est
|
|
l'écran original de démarrage et
|
|
l'élément [1] est la fenêtre
|
|
principale; après cela, ce sont les
|
|
différentes fenêtres dans l'ordre
|
|
où elles sont créées. Pour trouver
|
|
une en particulier, vous pouvez l'indexée
|
|
à travers la liste en vérifiant par
|
|
exemple Titre de la fenêtre avec le
|
|
<code>getTitle ()</code> .</p>
|
|
</div>
|
|
|
|
<h2>Quelle est la différence entre les classes
|
|
"Siglet" et "AbstractAutomaton" ?</h2>
|
|
|
|
<div class="para">
|
|
(Peut-être pas une question
|
|
<em>fréquemment</em> demandée, mais elle
|
|
a besoin d'être posée quelque part)
|
|
|
|
<p>Certains exemples utilisent la classe <a href=
|
|
"https://jmri.org/JavaDoc/doc/jmri/jmrit/automat/AbstractAutomaton.html">
|
|
AbstractAutomaton</a> comme une base, tandis que
|
|
d'autres utilisent la classe <a href=
|
|
"https://jmri.org/JavaDoc/doc/jmri/jmrit/automat/Siglet.html">
|
|
Siglet</a> . C'est parce que ceux-ci sont
|
|
destinés à des fins différentes
|
|
.</p>
|
|
|
|
<p>"Siglet" est destinée à être
|
|
utilisée pour piloter les signaux. Vous fournir
|
|
deux morceaux de code:</p>
|
|
|
|
<dl>
|
|
<dt>defineIO</dt>
|
|
|
|
<dd>qui définit les différents
|
|
capteurs, les aiguillages et signale que le signal de
|
|
sortie dépend de tant d'entrée
|
|
lorsqu'il faut calculer l'apparence de ce
|
|
signal.</dd>
|
|
|
|
<dt>setOutout</dt>
|
|
|
|
<dd>qui recalcule l'apparence du signal avec les
|
|
entrées définies.</dd>
|
|
</dl>
|
|
|
|
<p>La classe de base Siglet gère alors
|
|
l'ensemble de l'écoute des changements, la mise
|
|
en place pour l'exécution en parallèle,
|
|
etc. Votre routine defineIO sera appelé une fois
|
|
au début, et tout le temps après qu'une
|
|
ou plusieurs des entrées seront
|
|
modifiées, votre routine setOutput sera
|
|
appelée à recalculer l'apparence du
|
|
signal.</p>
|
|
|
|
<p>Bien sûr, vous pouvez utiliser cette classe
|
|
pour calculer d'autres choses que les apparences de
|
|
signaux. Mais l'élément clé est
|
|
que le calcul est refait quand les entrées
|
|
changent, et seulement lors du changement des
|
|
entrées.</p>
|
|
|
|
<p>AbstractAutomaton est une classe plus
|
|
générale qui vise à permettre des
|
|
opérations plus puissantes (et Siglet en
|
|
réalité utilise cette base plus
|
|
puissante). Vous définissez deux fonctions:</p>
|
|
|
|
<dl>
|
|
<dd>Init qui est appelé une seule fois pour
|
|
accomplir un temps de configuration dont vous avez
|
|
besoin</dd>
|
|
|
|
<dd>handle</dd>
|
|
|
|
<dt>qui est appelé à plusieurs
|
|
reprises, encore et encore jusqu'à ce qu'il
|
|
retourne FALSE.</dt>
|
|
</dl>
|
|
|
|
<p>Utiliser AbstractAutomoton vous fournit un certain
|
|
nombre d' outils: vous pouvez attendre d'un capteur
|
|
particulier qu'il soit actif, faire quelque chose, puis
|
|
attendre qu'un autre capteur passe à inactif,
|
|
etc. Cela vous permet beaucoup plus de liberté
|
|
pour créer des séquences plus
|
|
complexes& et puissantes que la classe Siglet,
|
|
parce les Siglets sont limités à faire
|
|
une seule chose (ils n'ont pas pour objectif de faire
|
|
des séquences d'opérations).</p>
|
|
|
|
<p>Pour plus d'infos sur le changement de routines que
|
|
fournit AbstractAutomaton pour vous aider, consultez
|
|
les <a href=
|
|
"https://jmri.org/JavaDoc/doc/jmri/jmrit/automat/AbstractAutomaton.html#method_summary">
|
|
Javadocs</a> pour la classe. (Faites défiler
|
|
jusqu'à la section intitulée
|
|
"Résumé de la méthode")</p>
|
|
</div>
|
|
|
|
<h2>Comment puis-je limiter la priorité d'un
|
|
script?</h2>
|
|
|
|
<div class="para">
|
|
<p>Si le script exécute une boucle qui est
|
|
censée mettre à jour quelque chose, il
|
|
ne peut pas être écrit pour fonctionner
|
|
en continu ou bien il va juste utiliser du temps
|
|
d'ordinateur autant qu'il peut. Il devrait
|
|
plutôt attendre.</p>
|
|
|
|
<p>La meilleure chose à faire est d'attendre
|
|
que quelque chose change. Pour Par exemple, si votre
|
|
script observe certains capteurs pour décider
|
|
quoi faire, attendre que l'un de ces capteurs change
|
|
(voir les exemples de scripts pour les exemples)</p>
|
|
|
|
<p>Plus simple, mais pas aussi efficace, est
|
|
d'attendre un peu de temps avant de vérifier
|
|
à nouveau. Par exemple</p>
|
|
<pre>
|
|
waitMsec (1000)
|
|
</pre>provoque un script automate ou Siglet pour attendre 1000
|
|
millisecondes (une seconde) avant de continuer.
|
|
|
|
<p>Pour juste un simple script, ce qui n'use pas le
|
|
les classes Automat ou Siglets , vous pouvez dormir
|
|
en faisant</p>
|
|
<pre>
|
|
du sommeil à l'importation du temps
|
|
le sommeil (10)
|
|
</pre>La première ligne définit le "sommeil" de
|
|
routine, et ne doit être fait qu'une fois. La deuxième
|
|
ligne, puis dort pendant 10 secondes. Notez que la précision
|
|
de cette méthode n'est pas aussi bonne que celle utilisant
|
|
l'une des classes spéciales.
|
|
</div>
|
|
|
|
<h2>Comment puis je invoquer un autre fichier script
|
|
depuis un script?</h2>
|
|
|
|
<div class="para">
|
|
<pre>
|
|
execfile("filename.py");
|
|
</pre>
|
|
</div>
|
|
|
|
<h2>Comment puis je charger un fichier de panneau de
|
|
partir d'un script?</h2>
|
|
|
|
<div class="para">
|
|
<div class="wide">
|
|
<pre>
|
|
<code>jmri.InstanceManager.getDefault(jmri.ConfigureManager).load(java.io.File("filename.xml "))</code>
|
|
</pre>
|
|
</div>
|
|
<p>Cela ressemble à "filename.xml" dans le
|
|
répertoire du programme JMRI, qui n'est pas un
|
|
bon endroit pour conserver vos fichiers. (Ils ont
|
|
tendance à être perdus ou
|
|
endommagés quand JMRI est mis à jour).
|
|
Voir la question suivante pour une solution à
|
|
cela.</p>
|
|
|
|
<h2>Comment puis-je trouver un fichier dans le
|
|
répertoire des préférences?</h2>
|
|
|
|
<p>Vous pouvez toujours
|
|
spécifier le chemin complet vers un fichier, par
|
|
exemple <code>C:\Documents and Files\
|
|
mine\JMRI\filename.xml</code> ou <code>/Users
|
|
/mine/.jmri/filename.xml</code> . Ce n'est pas
|
|
très portable, d'ordinateur à ordinateur,
|
|
cependant, et peut devenir un handicap pour continuer
|
|
plus loin.</p>
|
|
|
|
<p>JMRI fournit des routines pour convertir les noms
|
|
"portables" en des noms que votre ordinateur
|
|
reconnaîtra:</p>
|
|
|
|
<pre>
|
|
<code> fullname jmri.util.FileUtil.getExternalFilename = ("préférence: filename.xml") </code>
|
|
</pre>
|
|
Le "<code>:préférence</code>"
|
|
signifie regarder quel fichier démarre dans le
|
|
répertoire préférences sur
|
|
l'ordinateur actuel. D'autres choix sont "le
|
|
programme:" et "home".
|
|
</div>
|
|
|
|
<h2>Puis je communiquer entre les scripts?</h2>
|
|
|
|
<div class="para">
|
|
Tous les scripts partagent un espace d'adressage
|
|
unique, ce qui signifie qu'une variable comme le "x"
|
|
se réfère au même endroit dans
|
|
tous les scripts. Cela vous permet de définir
|
|
un procédure, par exemple, dans un script, et
|
|
l'utiliser ailleurs. Par exemple, si un fichier
|
|
"definitions.py" contient:
|
|
<pre>
|
|
def printStatus ():
|
|
print "x est", x
|
|
print "y est", y
|
|
print "z est", z
|
|
retour
|
|
|
|
a
|
|
x = 0
|
|
y = 0
|
|
z = 0
|
|
</pre>
|
|
<p>Une fois que le fichier a été
|
|
exécuté,plus tard des script pourront invoquer la
|
|
routine <code>printStatus ()</code> en cas de besoin.</p>
|
|
|
|
Vous pouvez également partager des variables,
|
|
ce qui permet à deux routines de partager
|
|
l'information. Dans l'exemple ci-dessus, les
|
|
variables <code>x</code> , <code>y</code> , et
|
|
<code>z</code> sont disponibles pour n'importe qui.
|
|
Cela peut conduire à des bugs obscures, si
|
|
deux routines différentes utilisent une
|
|
variable du même nom, sans se rendre compte
|
|
qu'ils partagent les données avec les autres.
|
|
Mettre votre code en "classes" est un moyen
|
|
d'éviter cela.
|
|
</div>
|
|
|
|
<h2>Un script peut-il attendre plus d'une chose
|
|
à changer?</h2>
|
|
|
|
<div class="para">
|
|
Si votre script est basé sur une classe Siglet
|
|
ou AbstractAutomaton (par exemple si vous
|
|
écrivez une "poignée" de routine ", il
|
|
y a une routine général" waitChange"
|
|
qui attend que plusieurs capteurs aient changer avant
|
|
de revenir vers vous. Notez que plusieurs peuvent
|
|
changer dans le même temps, de sorte que vous
|
|
pouvez supposer seulement qu'il y a une seule valeur
|
|
différente! Et vous aurez alors à
|
|
vérifier si elles sont devenues des
|
|
états particuliers. Il est écrit que:
|
|
<pre>
|
|
self.waitChange ([self.sensorA, self.sensorB, self.sensorC])
|
|
</pre>
|
|
où vous avez précédemment défini
|
|
chacun de ces "self.sensorA" et les choses via une ligne comme:
|
|
<pre>
|
|
self.sensorA = sensors.provideSensor ("21")
|
|
</pre>
|
|
Vous pouvez ensuite vérifier pour diverses
|
|
combinaisons comme:
|
|
<pre>
|
|
si self.sensorA.knownState == ACTIF:
|
|
print "L'avion! L'avion!"
|
|
elif self.sensorB.knownState == INACTIF:
|
|
print "Croiriez-vous à un oiseau très rapide?"
|
|
d'autre
|
|
print "Rien à voir ici, se déplacer le long ..."
|
|
</pre>
|
|
(Je n'ai pas vraiment saisi ce script et ni exécuter,
|
|
alors il pourrait y avoir des fautes de frappe,
|
|
désolé)
|
|
</div>
|
|
|
|
<h2>Un script peut il entendre plus d'un
|
|
aiguillage?</h2>
|
|
|
|
<div class="para">
|
|
Les Objets JMRI (aiguillages, capteurs, etc) peuvent
|
|
avoir des "Auditeurs" qui leur sont attachés.
|
|
Ces derniers sont ensuite avertis lorsque le statut
|
|
de l'objet change. Si vous utilisez les classes ou
|
|
les Siglet Automat, vous n'avez pas besoin d'utiliser
|
|
cette possibilité, et les classes
|
|
gèrent toutes les créations et
|
|
enregistrements des auditeurs. Mais si vous voulez
|
|
faire quelque chose de spécial, vous devrez
|
|
peut-être utiliser cette possibilité
|
|
|
|
<p>Une routine simple peut écouter plus d'un
|
|
aiguillage, capteur, etc</p>
|
|
|
|
<p>Si vous conservez une référence de
|
|
votre objet écouteur, vous pouvez le joindre
|
|
à plusieurs objets:</p>
|
|
<pre>
|
|
m = MyListener ()
|
|
turnouts.provideTurnout ("12"). addPropertyChangeListener (m)
|
|
turnouts.provideTurnout ("13"). addPropertyChangeListener (m)
|
|
turnouts.provideTurnout ("14"). addPropertyChangeListener (m)
|
|
</pre>
|
|
|
|
<p>Mais comment l'auditeur sait ce qui a
|
|
changé?</p>
|
|
|
|
<p>Une routine auditeur ressemble à
|
|
ceci:</p>Paroles de classe MyListener
|
|
(java.beans.PropertyChangeListener): def
|
|
propertyChange (auto, événement): print
|
|
"le changement", event.propertyName a print "à
|
|
partir", event.oldValue, "à", event.newValue
|
|
print "SystemName source", event.source.systemName a
|
|
print "userName source", event.source.userName
|
|
|
|
<p>Lorsque l'écouteur est appelé, il
|
|
donne un objet (appelé event ci-dessus) qui
|
|
contient le nom de la propriété qui a
|
|
changé, ainsi que les valeurs anciennes et
|
|
nouvelles de cette propriété.</p>
|
|
|
|
<p>Vous pouvez également obtenir une
|
|
référence de l'objet original qui a
|
|
changé par "nom", et ensuite faire tout ce que
|
|
vous voulez par là. Dans l'exemple ci-dessus,
|
|
vous pouvez récupérer les SystemName,
|
|
nom d'utilisateur (ou même d'autres types de
|
|
statut).</p>
|
|
</div>
|
|
|
|
<h2>Comment puis-je obtenir un script pour jouer un
|
|
son?</h2>
|
|
<div class="para">
|
|
<p>Le fichier Jython/SampleSound.py montre
|
|
comment jouer un son dans un script. En bref, vous
|
|
charger un son dans une variable ("snd" dans ce cas),
|
|
puis appelez "play ()" pour y jouer une fois, etc</p>
|
|
|
|
<p>Notez que si plus d'un son est joué
|
|
à un moment, le programme les combine entre
|
|
eux du mieux qu'il peut. Généralement,
|
|
il fait un assez bon travail.</p>a
|
|
|
|
<p>Vous pouvez combiner le jeu () avec une autre
|
|
logique de jouer un son quand un capteur change, etc
|
|
Ron McKinnon a fourni un exemple pour faire cela. Il
|
|
joue une cloche passage à niveau lorsque le
|
|
capteur devient actif.</p>
|
|
<div class="wide">
|
|
<pre>
|
|
# Il écoute les modifications apportées à un capteur,
|
|
# Puis joue un fichier son quand le capteur est actif
|
|
|
|
Importation Jarray
|
|
Importation JMRI
|
|
|
|
# Créer l'objet sonore en chargeant un fichier
|
|
snd = jmri.jmrit.Sound ("ressources/sons/Crossing.wav")
|
|
|
|
Classe SensndExample (jmri.jmrit.automat.Siglet):
|
|
|
|
# Modifier ceci pour définir tous vos aiguillages, les capteurs et
|
|
# têtes de Signal.
|
|
def defineIO (auto):
|
|
|
|
# Obtenir le capteur de
|
|
self.Sen1Sensor = sensors.provideSensor ("473")
|
|
|
|
# Enregistrer les entrées de sorte que setOutput sera appelé en cas de besoin.
|
|
self.setInputs (jarray.array ([self.Sen1Sensor], jmri.NamedBean))
|
|
|
|
Retour
|
|
|
|
# setOutput est appelée lorsque d'un changements des entrées, et est
|
|
# responsable de l'établissement la sortie correcte
|
|
#
|
|
# Modifier cela pour faire votre calcul.
|
|
def setOutput (auto):
|
|
|
|
Si self.Sen1Sensor.knownState == ACTIVE:
|
|
snd.play ()
|
|
|
|
Retour
|
|
|
|
# Fin de définition de la classe
|
|
|
|
# Lancer une de ceux ci-dessus
|
|
SensndExample (). Start ()
|
|
</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!--#include virtual="/help/fr/parts/Footer_fr.shtml" -->
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|