<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//FR">

<HTML>
  <HEAD>
    <!-- this stylesheet will later on be added by lfparser automatically: -->
<STYLE type="text/css">
<!--
  pre { font-familiy:monospace,Courier }
  p.code { width:80%; alignment:center; background-color:#aedbe8; border-style:no ne; border-width:medium; border-color:#aedbe8; padding:0.1cm ; text-align:left }
-->
</STYLE>

    <TITLE></TITLE>
  </HEAD>

  <BODY>
    <H1>D&eacute;velopper des Applications Gnome avec Python (Partie
    2)</H1>

    <H4>ArticleCategory:</H4>
    Software Development 

    <H4>AuthorImage:</H4>
    <IMG src="../../common/images/HilaireFernandes_color.png" width=
    "124" height="172" alt="Hilaire Fernandes"> 

    <H4>TranslationInfo:[Author + translation history. mailto: or
    http://homepage]</H4>

    <P>original in fr <A href="mailto:hilaire@ofset.org">Hilaire
    Fernandes</A></P>


    <H4>AboutTheAuthor</H4>

    <P>Hilaire Fernandes est le vice-pr&eacute;sident d'<A href=
    "http://www.ofset.org">OFSET</A>, une organisation pour promouvoir
    le d&eacute;veloppement de logiciels &eacute;ducatifs libres pour
    le bureau Gnome. Il a aussi &eacute;crit Dr.&nbsp;Geo, un logiciel
    prim&eacute; de g&eacute;om&eacute;trie dynamique, et il est
    actuellement occup&eacute; avec Dr.&nbsp;Genius un autre logiciel
    &eacute;ducatif de math&eacute;matiques pour le bureau Gnome.</P>

    <H4>Abstract:</H4>

    <P>Cette s&eacute;rie d'articles est sp&eacute;cialement
    &eacute;crite pour des d&eacute;butants en programmation sous Gnome
    et GNU/Linux. Le langage de d&eacute;veloppement choisi, Python,
    &eacute;vite la surcharge habituelle avec des langages
    compil&eacute;s comme le C. Avant d'&eacute;tudier cet article
    quelques notions de programmation sous Python sont
    n&eacute;cessaires.</P>

    <H4>ArticleIllustration:</H4>
    <IMG src="../../common/images/article160/gnome.png" width="48"
    height="48" alt="Gnome" hspace="10"> 

    <H4>ArticleBody:</H4>

    <H2>Outils n�cessaires</H2>

    <P>Pour les besoins logiciels &agrave; l'ex&eacute;cution du
    programme d&eacute;crit dans cet article, vous pouvez vous
    r&eacute;f&eacute;rer &agrave; la liste de la m&ecirc;me rubrique
    de la <A href="../July2000/article160.shtml">partie I</a> de cette s&eacute;rie d'articles.</P>

    <P>Vous aurez aussi besoin :</P>

    <UL>
      <LI>du fichier .glade original [ <A href=
      "../../common/images/article160/drill.glade.txt">drill.glade</A>
      ] ;</LI>

      <LI>du code source en Python [ <A href=
      "../../common/images/article160/drill.py.txt">drill.py</A>
      ].</LI>
    </UL>

    <P>Pour l'installation et l'utilisation de Pyhton-Gnome et LibGlade
    vous pouvez aussi vous r&eacute;f&eacute;rer &agrave; la partie
    I.</P>
    <BR clear="all">
     

    <H2><STRONG>Drill</STRONG>, notre support</H2>

    <P>La premi&egrave;re partie avait pour objectif de montrer les
    m&eacute;canismes et les modes d'interactions entre les
    diff&eacute;rents composants d'un programme &eacute;crit sous une
    configuration de type Gnome, Glade, LibGlade et Python.</P>

    <P>L'exemple utilisait le widget <TT>GnomeCanvas</TT>. Celui-ci
    nous a offert une illustration riche en couleur montrant
    l'int&eacute;r&ecirc;t et la facilit&eacute; de
    d&eacute;veloppement sous cette configuration.</P>

    <P>Pour les parties suivantes, je vous propose de mettre en place
    un cadre logiciel dans lequel nous illustrerons les
    diff&eacute;rents widgets de Gnome. Le pr&eacute;sent article
    s'attache principalement &agrave; mettre en place ce cadre. Les
    articles suivants s'appuieront sur celui-ci, en lui ajoutant des
    fonctionnalit&eacute;s, pour illustrer les diff&eacute;rents
    widgets de Gnome.</P>

    <P>Notre cadre logiciel s'appelle <STRONG>Drill</STRONG>. C'est une
    plate-forme &agrave; caract&egrave;re &eacute;ducatif sur laquelle
    nous grefferons des exercices. Attention, les exercices ont pour
    seule pr&eacute;tention p&eacute;dagogique d'illustrer l'usage des
    widgets !</P>

    <H3>Construction de l'interface avec Glade</H3>

    <P><B>Les widgets</B></P>

    <P>La fen&ecirc;tre de l'application est cr&eacute;&eacute;e
    &agrave; l'aide de Glade. Comme dans l'article
    pr&eacute;c&eacute;dent, vous cr&eacute;ez dans un premier temps
    une fen&ecirc;tre d'une application Gnome. Dans celle-ci vous
    supprimez les menus et ic&ocirc;nes inutiles.</P>

    <P>La zone principale de <STRONG>Drill</STRONG> est
    subdivis&eacute;e en deux espaces gr&acirc;ce au widget
    <TT>GtkPaned</TT>.</P>

    <CENTER>
      <IMG src="../../common/images/article160/python2-0.png" width=
      "361" height="407"><BR>
      <STRONG>Fig. 1 - Fen&ecirc;tre principale de Drill</STRONG>
    </CENTER>

    <P>Ils sont s&eacute;par&eacute;s verticalement par une
    poign&eacute;e permettant d'ajuster la subdivision. L'espace de
    gauche est occup&eacute; par un arbre (widget <TT>GtkTree</TT>)
    dans lequel seront rang&eacute;s par cat&eacute;gorie les
    intitul&eacute;s des exercices. L'espace &agrave; droite est vide,
    c'est ici que nous grefferons les exercices eux-m&ecirc;mes en
    fonction du choix de l'utilisateur.</P>

    <P>Depuis Glade, la vue de l'interface de <STRONG>Drill</STRONG>
    sous forme d'arbre permet de comprendre son agencement :</P>

    <CENTER>
      <IMG src="../../common/images/article160/python2-1.png" width=
      "262" height="345"><BR>
      <STRONG>Fig. 2 - Vue en arbre de l'interface de Drill</STRONG>
    </CENTER>

    <P>Dans la Fig. 2, nous voyons que le widget nomm&eacute;
    <TT>hpanedTree</TT> (de type <TT>GtkPaned</TT>) ne contient qu'un
    seul widget, <TT>frame2</TT> (de type <TT>GtkFrame</TT>), c'est
    celui-ci qui est &agrave; gauche. <TT>frame2</TT> contient
    lui-m&ecirc;me le widget <TT>exerciceTree</TT>. En effet, il est
    pr&eacute;f&eacute;rable de placer d'abord un widget
    <TT>GtkFrame</TT> avec une ombre de type <TT>GTK_SHADOW_IN</TT>
    dans un widget <TT>GtkPaned</TT>, cela &eacute;vite de mordre sur
    la poign&eacute;e.</P>

    <P>Pour finir la bo&icirc;te de dialogue Gnome "&Agrave; propos" de
    <STRONG>Drill</STRONG> peut ressembler &agrave; celle-ci</P>

    <CENTER>
      <IMG src="../../common/images/article160/python2-2.png" width=
      "246" height="258" alt="[Bo&icirc;te de dialogue]"><BR>
      <STRONG>Fig. 3 - Bo&icirc;te de dialogue "&Agrave; propos" de
      Drill</STRONG>
    </CENTER>

    <P>Ses diff&eacute;rentes rubriques sont &eacute;dit&eacute;es
    depuis Glade, dans le feuillet <TT>Widget</TT> de la fen&ecirc;tre
    <TT>Propri&eacute;t&eacute;s</TT>.</P>

    <P><B>Les noms des widgets et des fonctions de traitement</B></P>

    <P>Appliquez les noms suivants &agrave; ces widgets afin de les
    manipuler sous ces noms depuis Pyhton.</P>

    <DL id="widgetname">
      <DT><B>Fen&ecirc;tre d'application Gnome :</B></DT>

      <DD><TT>drillApp</TT></DD>

      <DT><B>Poign&eacute;e s&eacute;parant l'arbre des exercices
      :</B></DT>

      <DD><TT>hpanedTree</TT></DD>

      <DT><B>Arbre des exercices :</B></DT>

      <DD><TT>exerciceTree</TT></DD>

      <DT><B>Bo&icirc;te de dialogue Gnome &Agrave;-propos :</B></DT>

      <DD><TT>about</TT></DD>
    </DL>

    <P>Ces widgets sont ceux dont les noms sont visibles sur la Fig.
    2</P>

    <P>Nous listons ici rapidement les noms des fonctions de
    traitement. Si vous avez besoin d'informations
    compl&eacute;mentaires sur le sujet r&eacute;f&eacute;rez-vous
    &agrave; <A href="../July2000/article160.shtml">la partie I.</a></P>

    <P></P>

    <TABLE border="1" cellpadding="8">
      <TR>
        <TH>Nom de widget</TH>

        <TH>Signal</TH>

        <TH>Traitement</TH>
      </TR>

      <TR>
        <TD>about</TD>

        <TD>clicked</TD>

        <TD>gtk_widget_destroy</TD>
      </TR>

      <TR>
        <TD>about</TD>

        <TD>close</TD>

        <TD>gtk_widget_destroy</TD>
      </TR>

      <TR>
        <TD>about</TD>

        <TD>destroy</TD>

        <TD>gtk_widget_destroy</TD>
      </TR>

      <TR>
        <TD>button1 (ic&ocirc;ne nouveau dans<BR>
         la barre &agrave; outils</TD>

        <TD>clicked</TD>

        <TD>on_new_activate</TD>
      </TR>

      <TR>
        <TD>new</TD>

        <TD>activate</TD>

        <TD>on_new_activate</TD>
      </TR>

      <TR>
        <TD>drillApp</TD>

        <TD>destroy</TD>

        <TD>on_exit_activate</TD>
      </TR>

      <TR>
        <TD>exit</TD>

        <TD>activate</TD>

        <TD>on_exit_activate</TD>
      </TR>

      <TR>
        <TD>about</TD>

        <TD>activate</TD>

        <TD>on_about_activate</TD>
      </TR>
    </TABLE>

    <P><B>Derniers ajustements</B></P>

    <P>Depuis Glade il est possible de sp&eacute;cifier la
    g&eacute;om&eacute;trie des widgets. Dans notre affaire, vous
    pouvez ajuster la taille de <TT>drillApp</TT> &agrave; 400 et 300
    depuis l'onglet <TT>Commun</TT> du panneau de
    <TT>Propri&eacute;t&eacute;s</TT>. Aussi, la position du diviseur
    des panneaux horizontaux peut &ecirc;tre ajust&eacute;e &agrave;
    100 au lieu de 1.</P>

    <P>Ensuite, le widget <TT>exerciceTree</TT> doit &ecirc;tre
    ajust&eacute; afin de ne permettre qu'une seule s&eacute;lection
    &agrave; la fois. En effet un seul exercice peut &ecirc;tre
    s&eacute;lectionn&eacute; &agrave; la fois. Depuis le panneau de
    <TT>Propri&eacute;t&eacute;s</TT>, choisir
    <TT>Selection-&gt;Single</TT>. Les autres options de ce widget sont
    de moindre importance.</P>

    <P>Voil&agrave;! C'est fini en ce qui concerne
    <STRONG>Drill</STRONG> lui-m&ecirc;me. Nous commencerons &agrave;
    d&eacute;velopper des exercices d&egrave;s le prochain article.
    Pour le moment nous allons voir comment utiliser l'interface depuis
    Python et nous int&eacute;resser &agrave; la manipulation du widget
    <TT>GtkTree</TT>.</P>

    <H3>Le code Python</H3>

    <P>Le code source complet se trouve &agrave; la fin de ce document.
    Il doit &ecirc;tre sauvegard&eacute; dans le m&ecirc;me dossier que
    le fichier <TT>drill.glade</TT>.</P>

    <H3>Les modules n&eacute;cessaires</H3>

    <P class="code">from gtk import * from gnome.ui import * from GDK
    import * from libglade import *</P>

    <H3>L'interface graphique avec LibGlade</H3>

    <P>La construction de l'interface graphique et la connection des
    fonctions de traitement avec LibGlade se fait de fa&ccedil;on
    analogue &agrave; l'exemple pr&eacute;c&eacute;dent. Nous ne
    revenons pas sur cet aspect l&agrave;.</P>

    <P>Dans le programme python nous d&eacute;finissons des variables
    globales :</P>

    <UL>
      <LI><TT>currentExercice</TT>: r&eacute;f&eacute;rence du widget
      repr&eacute;sentant l'exercice courant. Celui-ci est plac&eacute;
      dans la partie droite de la fen&ecirc;tre d'application de
      <STRONG>Drill</STRONG>. Les exercices seront &eacute;galement
      cr&eacute;&eacute;s &agrave; partir de Glade.</LI>

      <LI><TT>exerciceTree</TT> : r&eacute;f&eacute;rence de l'arbre
      &agrave; gauche dans la fen&ecirc;tre d'application de
      <STRONG>Drill</STRONG>.</LI>

      <LI><TT>label</TT> : r&eacute;f&eacute;rence un label
      (<TT>GtkLabel</TT>). Ce label est un palliatif &agrave; l'absence
      d'exercice pour le moment. Il sera donc plac&eacute; &agrave;
      droite de l'arbre -- o&ugrave; les exercices prendront place --
      et nous y afficherons les identifiants des exercices
      s&eacute;lectionn&eacute;s.</LI>
    </UL>
    <BR>
    <BR>
     

    <P>L'arbre est cr&eacute;&eacute; par LibGlade, sa
    r&eacute;f&eacute;rence est r&eacute;cup&eacute;r&eacute;e par
    l'appel suivant:</P>

    <P class="code">exerciceTree = wTree.get_widget
    ("exerciceTree")</P>

    <P>Nous avons &eacute;galement besoin de la r&eacute;f&eacute;rence
    des panneaux horizontaux, en fait la r&eacute;f&eacute;rence du
    conteneur (<TT>GtkPaned</TT>) des deux panneaux horizontaux
    s&eacute;par&eacute;s par une poign&eacute;e. Celui &agrave; gauche
    contient l'arbre ; celui &agrave; droite les exercices, nous y
    placerons pour le moment le label :</P>

    <P class="code">paned = wTree.get_widget ("hpanedTree") label =
    GtkLabel ("Aucun exercice de s&eacute;lectionn&eacute;") label.show
    () paned.pack2 (label)</P>

    <P>Une fois encore l'utilisation conjointe du <B>Manuel de
    r&eacute;f&eacute;rence de GTK+</B> -- sur les objets
    <TT>GtkLabel</TT> et <TT>GtkPaned</TT> -- et du source Python
    <TT>/usr/lib/python1.5/site-packages/gtk.py</TT> offre le
    discernement n&eacute;cessaire &agrave; la bonne utilisation des
    objets.</P>

    <H3>Le widget <TT>GtkTree</TT></H3>

    <P>Nous arrivons ici &agrave; l'&eacute;l&eacute;ment essentiel de
    notre article, &agrave; savoir l'utilisation d'un arbre de type
    <TT>GtkTree</TT>.</P>

    <P>L'arbre est rempli par les appels successifs aux fonctions
    <TT>addMathExercices()</TT>, <TT>addFrenchExercices()</TT>,
    <TT>addHistoryExercices()</TT> et <TT>addGeographyExercices()</TT>.
    Elles sont toutes semblables. Chacune de ces fonctions ajoutent une
    sous cat&eacute;gorie (un sous arbre) ainsi que des titres
    d'exercices (les items):</P>

    <P class="code">def addMathExercices (): <br>
    subtree = addSubtree ("Math&eacute;matiques")<br>
    addExercice (subtree, "Exercice 1", "Math.
    Ex1")<br> 
    addExercice (subtree, "Exercice 2", "Math. Ex2")</P>

    <P><B>Le sous-arbre</B></P>

    <P class="code">def addSubtree (name): <br>
    global exerciceTree <br>
    subTree = GtkTree ()<br> 
    item = GtkTreeItem (name) <br>
    exerciceTree.append (item)<br>
    item.set_subtree (subTree) <br>
    item.show () <br>
    item.connect ("select", selectSubtree) <br>
    return subTree</P>

    <P>Pour cr&eacute;er un sous-arbre dans un arbre existant, il faut
    cr&eacute;er deux choses : un arbre <TT>GtkTree</TT> et un item
    <TT>GtkTreeItem</TT> portant le nom du sous-arbre. Ensuite l'item
    est ajout&eacute; &agrave; l'arbre racine -- notre arbre contenant
    toutes les cat&eacute;gories -- puis nous greffons notre sous-arbre
    &agrave; l'item gr&acirc;ce &agrave; sa m&eacute;thode
    <TT>set_subtree()</TT>. Enfin, l'&eacute;v&eacute;nement
    <TT>select</TT> est connect&eacute; &agrave; l'item, ainsi lorsque
    la cat&eacute;gorie est s&eacute;lectionn&eacute;e, la fonction
    <TT>selectSubtree()</TT> est appel&eacute;e.</P>

    <P><B>GtkTreeItem</B></P>

    <P class="code">def addExercice (category, title, idValue): <br>
    item = GtkTreeItem (title) <br>
    item.set_data ("id", idValue) <br>
    category.append (item) <br>
    item.show () <br>
    item.connect ("select", selectTreeItem)<br>
    item.connect ("deselect", deselectTreeItem)</P>

    <P>Les items portent comme titre les noms des exercices, ici en
    g&eacute;n&eacute;ral simplement <TT>Exercice 1</TT>, <TT>2</TT>,
    ... &Agrave; chaque item nous associons un attribut
    suppl&eacute;mentaire, <TT>id</TT>. GTK+ offre en effet la
    possibilit&eacute; d'ajouter &agrave; tout objet de type
    <TT>GtkObject</TT> -- dont tous les widgets de GTK+ sont issus --
    des attributs. Pour ce faire il existe deux m&eacute;thodes
    <TT>set_data (key, value)</TT> et <TT>get_data (key)</TT> pour
    initialiser et r&eacute;cup&eacute;rer la valeur d'un attribut.
    L'item est ensuite ajout&eacute; &agrave; sa cat&eacute;gorie -- un
    sous arbre. Sa m&eacute;thode <TT>show()</TT> est appel&eacute;e,
    elle est n&eacute;cessaire pour forcer l'affichage. Enfin les
    &eacute;v&eacute;nements <TT>select</TT> et <TT>deselect</TT> sont
    connect&eacute;s, l'&eacute;v&eacute;nement <TT>deselect</TT> prend
    lieu lorsque l'item perd la s&eacute;lection. Chronologiquement, la
    m&eacute;thode <TT>deselectTreeItem()</TT> est appel&eacute;e sur
    l'item perdant la s&eacute;lection, puis <TT>selectTreeItem()</TT>
    est invoqu&eacute;e sur l'item prenant la s&eacute;lection.</P>

    <H3>Les fonctions de traitement</H3>

    <P>Nous avons d&eacute;fini trois fonctions de traitement
    <TT>selectTreeItem()</TT>, <TT>deselectTreeItem()</TT> et
    <TT>selectSubtree()</TT>. Ces m&eacute;thodes mettent &agrave; jour
    le texte du label -- plac&eacute; dans la zone de droite -- avec la
    valeur de l'attribut <TT>id</TT>. C'est tout pour le moment.</P>

    <H3>Le mot final</H3>

    <P>Nous avons ici mis en place l'infrastructure dans laquelle nous
    grefferons des exercices -- autant de nouveaux widgets que nous
    d&eacute;couvrirons. Nous avons principalement &eacute;tudi&eacute;
    le widget <TT>GtkTree</TT> et comment associer des attributs
    &agrave; des widgets. Ce dernier m&eacute;canisme est tr&egrave;s
    souvent utilis&eacute; pour r&eacute;cup&eacute;rer dans les
    fonctions de traitement des informations suppl&eacute;mentaires
    associ&eacute;es, ce que nous avons fait ici. En attendant le
    prochain article, vous pouvez essayer de transformer le jeu
    <STRONG>Couleur</STRONG>, &eacute;tudi&eacute; en partie 1, comme
    un exercice dans <STRONG>Drill</STRONG>.</P>

    <H3>Appendice: Le source complet</H3>

    <P class="code"><BR>
    #!/usr/bin/python<BR>
    # Drill - Teo Serie<BR>
    # Copyright Hilaire Fernandes 2001<BR>
    # Release under the terms of the GPL licence<BR>
    # You can get a copy of the license at http://www.gnu.org<BR>
    <BR>
    from gtk import *<BR>
    from gnome.ui import *<BR>
    from GDK import *<BR>
    from libglade import *<BR>
    <BR>
    exerciceTree = currentExercice = label = None<BR>
    <BR>
    def on_about_activate(obj):<BR>
     "display the about dialog"<BR>
     about = GladeXML ("drill.glade", "about").get_widget ("about")<BR>
     about.show ()<BR>
    <BR>
    def on_new_activate (obj):<BR>
     global exerciceTree, currentExercice<BR>
    <BR>
    <BR>
    def selectTreeItem (item):<BR>
     global label<BR>
     label.set_text ("L'exercice " +<BR>
     item.get_data ("id") + "est s&eacute;lectionn&eacute;.")<BR>
    <BR>
    def deselectTreeItem (item):<BR>
     global label<BR>
     label.set_text ("L'exercice " +<BR>
     item.get_data ("id") + "est
    d&eacute;s&eacute;lectionn&eacute;.")<BR>
    <BR>
    def selectSubtree (subtree):<BR>
     global label<BR>
     label.set_text ("Aucun exercice de s&eacute;lectionn&eacute;")<BR>
    <BR>
    def addSubtree (name):<BR>
     global exerciceTree<BR>
     subTree = GtkTree ()<BR>
     item = GtkTreeItem (name)<BR>
     exerciceTree.append (item)<BR>
     item.set_subtree (subTree)<BR>
     item.show ()<BR>
     item.connect ("select", selectSubtree)<BR>
     return subTree<BR>
    <BR>
    def addExercice (category, title, id):<BR>
     item = GtkTreeItem (title)<BR>
     item.set_data ("id", id)<BR>
     category.append (item)<BR>
     item.show ()<BR>
     item.connect ("select", selectTreeItem)<BR>
     item.connect ("deselect", deselectTreeItem)<BR>
    <BR>
    <BR>
    def addMathExercices ():<BR>
     subtree = addSubtree ("Math&eacute;matiques")<BR>
     addExercice (subtree, "Exercice 1", "Math. Ex1")<BR>
     addExercice (subtree, "Exercice 2", "Math. Ex2")<BR>
    <BR>
    def addFrenchExercices ():<BR>
     subtree = addSubtree ("Fran&ccedil;ais")<BR>
     addExercice (subtree, "Exercice 1", "Fran&ccedil;ais Ex1")<BR>
     addExercice (subtree, "Exercice 2", "Fran&ccedil;ais Ex2")<BR>
    <BR>
    def addHistoryExercices ():<BR>
     subtree = addSubtree ("Histoire")<BR>
     addExercice (subtree, "Exercice 1", "Histoire Ex1")<BR>
     addExercice (subtree, "Exercice 2", "Histoire Ex2")<BR>
    <BR>
    def addGeographyExercices ():<BR>
     subtree = addSubtree ("G&eacute;ographie")<BR>
     addExercice (subtree, "Exercice 1", "G&eacute;ographie Ex1")<BR>
     addExercice (subtree, "Exercice 2", "G&eacute;ographie Ex2")<BR>
    <BR>
    def initDrill ():<BR>
     global exerciceTree, label<BR>
     wTree = GladeXML ("drill.glade", "drillApp")<BR>
     dic = {"on_about_activate": on_about_activate,<BR>
     "on_exit_activate": mainquit,<BR>
     "on_new_activate": on_new_activate}<BR>
     wTree.signal_autoconnect (dic)<BR>
     exerciceTree = wTree.get_widget ("exerciceTree")<BR>
     # Temporary until we implement real exercice<BR>
     paned = wTree.get_widget ("hpanedTree")<BR>
     label = GtkLabel ("Aucun exercice de
    s&eacute;lectionn&eacute;")<BR>
     label.show ()<BR>
     paned.pack2 (label)<BR>
     # Free the GladeXML tree<BR>
     wTree.destroy ()<BR>
     # Add the exercices<BR>
     addMathExercices ()<BR>
     addFrenchExercices ()<BR>
     addHistoryExercices ()<BR>
     addGeographyExercices ()<BR>
    <BR>
    initDrill ()<BR>
    mainloop ()</P>
  </BODY>
</HTML>