Welcome to the Zope Tutorial

  This tutorial shows you the basics of using Zope. You will learn how
  to create and manage Zope resources by building a web site devoted
  to tracking Elvis sightings. Each lesson includes working examples
  that allow you to learn by hands-on experimentation.
  
  The tutorial assumes that you are familiar with basic Internet
  technologies such as HTML (http://www.w3.org/MarkUp/Guide/), URLs, and web browsers.
  
  The "Back" and "Next" buttons on the bottom of each tutorial
  page allow you to navigate the tutorial.
  
  If you get lost you can use your browser's back button to
  return to an earlier lesson.
  
  If you want to quit the tutorial close your browser window.
  You can return to the tutorial later by visiting the tutorial
  object you created in the Zope management screen, and viewing
  its "README" document.
  
  <dtml-unless expr="checkInstallation(REQUEST)">
  
  Install Tutorial Examples  
  
    Before you can begin the tutorial you must install the tutorial
    examples.
  
      1. Go to the Zope management screen and choose 'Zope Tutorial' from
      the "Select type to add..." list.
  
      2. Choose an id for the tutorial and click the 'Add' button.
  
      3. Now you should be taken to the tutorial.
      
  </dtml-unless>
  
Lesson 1. "Elvis Lives" Home Page

  <dtml-var "tutorialShowLesson(1, REQUEST)">

  Let's create a home page for "Elvis Lives", an organization that
  tracks Elvis sightings.
  
  First you need to create a [Page Template]
  for the home page. Zope uses 'Page Templates' for web pages.
  
    1. Select 'Page Template' from the "Select type to add..." list.

    2. Type 'home.html' for the template [id].
    
    3. Click the 'Add and Edit' button.
  
  You should now see a screen
  where you can edit your web page.
  
    1. Change the title of the template to 'Elvis Lives'.

    1. Change the contents of the template to::
      
      <html>

      <img tal:replace="structure container/header.gif">

      <p>
      Welcome to <i tal:content="template/title">title</i>,
      your source for information about Elvis and
      Elvis sightings.
      </p>

      </html>
      
    2. Click the 'Save Changes' button.
    
  The contents of the template is HTML along with special attributes
  called [Page Template Statements].
  
  The [tal:content] and [tal:replace] statements inserts things into
  tags.  In this page we use these statement to insert an image and
  a title.
  
  Now let's see what our page
  looks like.
  
    1. Click the 'Test' tab at the top of the screen.
  
  Congratulations you've created
  a web page with Zope.

  Summary
  
    Zope allows you to create and manage objects through
    the web.

    * Zope uses [Page Template]s
    for web pages.

    * You can create Zope objects by choosing them from the "Select
      type to add..." list.

    * You can insert content in web pages with the
    [tal:content] and [tal:replace] statements.

  In the next lesson you'll expand
  your web site.

Lesson 2. Going to Graceland

  <dtml-var "tutorialShowLesson(2, REQUEST)">

  Elvis loved his home, Graceland.  Let's link an existing 
  page to our web site with information about Graceland.
  
    1. Click on the 'graceland' [Folder].
    
    2. Inside you should see a number of objects including an
    'index_html' page.
    
  If a [Folder] contains an object named [index_html], that object
  provides the folder's default view. This is just like how an
  'index.html' or a 'default.htm' file works with a conventional
  web server.

  At the top of the management screen, you will find a folder icon
  followed by "Folder at", and the URL of the current folder. In
  addition to being informative, this URL is a navigation aid. Each
  part of this URL is a link, and can be used to go to the management
  screens of parent folders.
      
    3. Return to the enclosing folder by clicking the 'lesson2' link
    in the folder's URL.
    
    4. Click on the 'home.html' template to edit it.
    
    5. Change the contents of the 'home.html' template to::
    
      <html>

      <img tal:replace="structure container/header.gif">

      <p>
      Welcome to <i tal:content="template/title">title</i>,
      your source for information about Elvis and
      Elvis sightings.
      </p>

      <p>
      Elvis was born in
      <a href="graceland">Graceland</a>.
      </p>

      </html>
      
    6. Click the 'Save Changes' button.
  
  This adds a link the the 'graceland' folder. Now let's test
  out the link.
  
    7. Click the 'Test' tab.
  
  You've successfully created a multi-page site with a link between two
  Zope objects.

  Summary
    
    Zope files and templates have a lot in common with conventional
    web pages--they have names, are arranged in hierarchies, and have
    URLs that correspond to their locations.
    
    * [Folder]s contain other Zope objects.

    * The default object for a Folder is named [index_html].

    * The Zope management screens allow you to navigate between folders
      and determine the URLs of objects.

  In the next lesson you'll learn about moving
  pages around in Zope.

Lesson 3. Elvis's Favorite Foods

  <dtml-var "tutorialShowLesson(3, REQUEST)">

  Elvis really liked to eat. Right now we have a of couple pages about
  foods Elvis liked. But as our web site grows we'll need a whole area
  devoted to food. Let's create a [Folder] for food information.
  
    1. Select 'Folder' from the "Select type to add..." list.
    
    2. Type 'food' for the folder id.
    
    3. Type 'Elvis and Food' for the folder title.
    
    4. Click the 'Add' button.
    
  Now we've got some place to put our food related resources. Let's
  move some objects into this folder.
  
    1. Select the 'sandwiches.html', 'pie.html', and 'meatloaf.html'
    templates by clicking their check boxes.
    
    2. Click the 'Cut' button.

    3. Click the 'food' folder to enter it.
    
    4. Click the 'Paste' button.
    
  Now that we've moved some objects, we need to update the links to
  them because an object's URL is related to its location.
  
    1. Return to the 'home.html' template in the 'lesson3' folder,
    by clicking on the 'lesson3' location link and then clicking 
    on the 'home.html' page.
    
    2. Change the links to the sandwiches, pie and cake templates
    to::
    
      <p>
      Elvis liked to eat
      <a href="food/sandwiches.html">sandwiches</a>,
      <a href="food/pie.html">pie</a>, and 
      <a href="food/meatloaf.html">meatloaf</a>.
      </p>
      
    3. Click the 'Save Changes' button.
    
    4. Click the 'Test' tab at the top of the screen.
  
  Notice that the food resources are now correctly linked from the home
  page in their new location.
  
  Congratulations you've performed your first
  web site overhaul! 

  Summary

    You can organize Zope object in folders. You can create
    new folders and move objects between folders.

    * Move Zope objects around with [Cut] and [Paste].

    * Folders contain other Zope objects.

    * Moving a Zope object between folders changes its URL. 

  In the next lesson you'll learn how to change
  the look and feel of your site.
    
Lesson 4. Site Contact Information

  <dtml-var "tutorialShowLesson(4, REQUEST)">

  Part of running an Elvis web site is getting in touch with Elvis
  fans the world over. One way to do this is to provide contact
  information on your site so that visitors can email you. Let's
  create an email link at the bottom of each page on your site that
  lets people send you feedback.
  
    1. Click the 'Properties' tab.
    
    2. Type 'mail_link' in the Name field.
    
    3. Type a mail link to your email address
    (e.g. 'mailto:me@example.com') in the Value field.
    
    4. Click the 'Add' button.
    
  You have created a property that holds your e-mail address and that
  can be used throughout your site.  Let's see how we can use this
  address on each web page by changing the standard web page footer.
  
    1. Click the 'Contents' tab to return to the list of items in the
      folder, then click the 'standard_template.pt' [Page Template] to
      edit it.
    
    2. Change the contents of the template to add a mail to link at
    the bottom of the page::
    
      <html metal:define-macro="page">
        <body> 
          <div metal:define-slot="body">
          This is where the page's body text goes.
          </div>
          <hr>
          <a tal:attributes="href container/mail_link">mail
            webmaster</a>
        </body>
      </html>
   
    3. Click the 'Save Changes' button.

  We've change the standard Zope page macro. Now let's verify that
  this change is reflected in our web pages.
    
    1. Navigate to the 'home.html' template in the 'lesson4' folder
    by clicking on the 'lesson4' location link and then clicking 
    on the 'home.html' page.
    
    2. Now click the 'Test' tab to view the web site.
    
  Notice that there is now an email link at the bottom of every web
  page. The email link uses the property you defined and includes the
  title of the web page as the email subject.
  
  The email link appears on every page because every page template
  uses a [Page Template Macro] defined in the 'standard_template.pt'
  template. Macros provide a way of sharing presentation elements
  between pages. The 'standard_template.pt' template gives you a
  convention for making pages share a common structure.

  Summary

    By consolidating content into components such as a common footer
    you can provide a uniform look and feel for your web site.
  
    * [Properties] contain small pieces of content.
    
    * Use the [tal:attributes] statement to change tag attributes.
    
    * [standard_template.pt] is used to provide shared look and feel
    between templates.

  In the next lesson you'll see how to organize content
  with a collection of Zope objects.

Lesson 5. Recent Elvis Sightings

  <dtml-var "tutorialShowLesson(5, REQUEST)">
  Elvis sightings happen all the time. You'd like to record them and
  list them on your web site. Let's look at a simple system for
  organizing sightings and displaying them on your web site.
  
    1. Click the 'sightings.html' web page.
  
    2. Click the 'Test' tab to view it.
    
  Notice how the page lists a number of Elvis sightings. Also notice
  that these sightings weren't specifically listed in the contents of
  the web page. Where did they come from?
  
    1. Click the 'sightingsFolder' folder to enter it.
    
    2. Click on the 'sighting2' file to examine it.
  
    3. Go back the 'sightingsFolder' folder by clicking the
    'sightingsFolder' location link.
    
    4. Select the 'sighting2' file by clicking its check box.
  
    5. Click the 'Delete' button.
    
  You just deleted a Zope object that describes an Elvis sighting.
  Let's see how this affects the 'sightings' web page.
  
    1. Click the 'sightings.html' web page.
    
    2. Click the 'Test' tab to view it.
    
  The Shelbyville sighting is not longer listed. So the list of
  sightings is somehow built from the files in the 'sightingsFolder'
  folder.
  
  What if you want the Shelbyville sighting back? Since you deleted
  it, you can't just paste it back. You need to [Undo] your action.
  
    1. Click the 'Undo' tab.
    
    2. Select the first transaction (ending with "manage_delObjects")
    by clicking its check box.
    
    3. Click the 'Undo' button.
    
    4. Click the 'sightingsFolder' folder to enter it.
    
  Sure enough the 'sighting2' sighting has returned.  
  
  Summary
  
    Multiple Zope objects can be combined to form complex web pages.
  
    * [File]s contain chunks of textual or binary content.
  
    * Web pages can insert content from 'Files'.
  
    * You can recover from mistakes with [Undo].

  In the next lesson you'll learn about
  looping over lists of Zope objects.
  
Lesson 6. Recent Elvis Sightings, cont.
  
  <dtml-var "tutorialShowLesson(6, REQUEST)">
  So we've seen that the 'sightings.html' page is built from objects
  in the 'sightingsFolder' folder. How does it work?
  
    1. Click the 'sightings.html' template to edit it.
  
    2. Change the contents of the template to::

      <html>

      <h1 tal:content="template/title">title</h1>

      <table border="1">
        <tr>
        <td>
        <div tal:repeat="sighting container/sightingsFolder/objectValues"
             tal:content="structure sighting">
        Sighting goes here
        </div>
        </td>
        </tr>
      </table>

      </html>
      
    3. Click the 'Save Changes' button.
    
    4. Click the 'Test' tab.
    
  Notice how each sighting now has a box drawn around it.
  
  What's going on? The [tal:repeat] statement iterates over a list of
  sightings. The list is defined by the expression
  'container/sightingsFolder/objectValues'. The expression calls the
  'objectValues' method of the 'sightingsFolder' folder. It returns
  all the objects contained by a folder.

  Notice the 'sighting' part of the repeat statement. It is a local
  variable that takes the value of each object in the list in
  turn. This variable is used by the the [tal:content] statement to
  insert the contents of each file object inside the table.
  
  Summary

    You can programmatically build web pages with groups of objects
    by looping over them and inserting them.
  
    * [tal:repeat] iterates over a list of objects.
    
    * [tal:repeat] defines a local variable that you can use to get
    access to objects in the list.
    
    * You can get the contents of a folder by calling its
    'objectValues' method.

  In the next lesson you'll learn about how to
  manage and display pictures.
    
Lesson 7. Elvis Photo Archive

  <dtml-var "tutorialShowLesson(7, REQUEST)">
  The King had many faces. We can offer our site visitors a peek at
  the many sides of Elvis with a photo archive.
  
    1. Click the 'photos.html' template.
  
    2. Click the 'Test' tab to view it.
  
  This page shows the photos in the archive one after another. It uses
  Image objects stored in the 'photoArchive' folder. It's not very
  fancy.  Let's improve it to display the title and size of the
  photos.
  
    1. Click your browser's back button to return to the 'photos.html'
    template to edit it.
    
    2. Change the contents to::
    
      <html>

      <p tal:repeat="photo container/photoArchive/objectValues"> 
        <img tal:replace="structure photo">
        <span tal:replace="photo/title">title</span>
        (<span tal:replace="photo/getSize">size</span> bytes)
      </p>

      </html>
     
    3. Click the 'Save Changes' button.
    
    4. Click the 'Test' tab.
    
  Notice how each photo now includes a title
  and size information.
  
  Summary

    [Image]s can display themselves and can also provide useful
    information such as size, title, and URL.
  
    * Get the contents of a Folder with the 'objectValues' method.
  
    * Get the size of an [Image] with the 'getSize' method.
    
  In the next lesson you'll learn how to create
  pictures with Python scripting.
  
Lesson 8. Elvis Photo Archive, cont. 

  <dtml-var "tutorialShowLesson(8, REQUEST)">
  Now that we have a working photo archive, let's enhance it to handle
  submissions from site visitors.
  
    1. Click the 'form.html' template.
    
    2. Click the 'Test' tab to view it.
    
    3. Upload a picture (JPG, GIF, PNG or other graphics format supported
    by your browser.)
    
    4. Now return to the 'lesson8' folder in the Zope management screen
    using your browser's back button.
    
    5. Click the 'photoArchive' folder to enter it.
  
  Notice that there is now a new [Image] object in the folder. This
  image was created when you uploaded your photo.
  
  Let's investigate how this works, and add the ability to give our
  uploaded photo a title.
  
    1. Click the 'form.html' template.
    
    2. Change the contents to::
    
      <html>

      <h1 tal:content="template/title">title</h1>

      <p>Upload a picture to the Elvis Photo Archive.</p>

      <form action="action.py" method="post"
      enctype="multipart/form-data">
      <p>File: <input type="file" name="file"></p>
      <p>Title: <input type="text" name="title"></p>
      <input type="submit">
      </form>

      </html>

    3. Click the 'Save Changes' button.
    
  This page collects data needed to create an Image. It calls the
  'action.py' script with that data. The 'action.py' script actually
  creates the Image. Now let's customize the script to handle the
  image title.
    
    1. Click the 'action.py' script to edit it. 
   
    2. Change the parameter list to 'file, title'.

    3. Change the contents of the script to::
    
      """
      Create a new image in the photo archive folder.
      Then return a confirmation page.
      """
      folder=container['photoArchive']
      folder.manage_addImage(id='', file=file, title=title)
      page=container['thanks.html']
      return page()
      
  The script collects the form data, creates an image object in a
  folder and then returns a thanks page. It gets access to form data
  through its parameters. It calls the 'manage_addImage' folder method
  on the photo archive folder to create a new image there. Finally it
  locates the thanks page and renders and returns it.
  
  Summary
  
    * You can use forms to pass information between Zope objects.
    You can programmatically create new Zope objects.
  
    * Scripts can be the action of HTML forms.
  
    * Create new [Image]s in folder with the 'manage_addImage' method. 

    * Scripts can render and return templates.

  In the next lesson you'll learn about [HTTP Cookies] and
  personalizing your web site.

Lesson 9. Elvis, Up Close and Personal
  
  <dtml-var "tutorialShowLesson(9, REQUEST)"> People who come to your
  site want a personal relationship with Elvis. You can provide this
  by tailoring your site to the needs and preferences of your viewers.
  Let's add the ability to bring new Elvis sightings to the attention
  of site visitors. This way when a visitor comes to your site they'll
  immediately know which sightings are new since they last visited.
  
    1. Click the 'sightings.html' template to edit it.
    
    2. Click the 'Test' tab to view it.
    
  All the sightings should be
  marked as new.
  
    3. Reload the page.
    
  Now none of the sightings should be marked as new. This is because
  you've already seen them.
  
    4. Click the 'sightingsFolder' folder to enter it.
    
    5. Choose 'File' from the "Select type to add..." list.
    
    6. Type 'Seattle' for the id. 
    
    7. Click the 'Add' button.

    8. Now click on the new file to edit it.

    9. Change the content type to "text/html'.
    
    10. Change the contents of the file to::
    
      <p>6/1/2003 -- Seattle</p>
      <p>Elvis spotted spare changing on Broadway.
      He denied being the King.</p>
    
    11. Click the 'Save Changes' button.
    
  Now you've created a new sighting. Let's see if it is marked as new
  by the sightings page.
  
    12. Click the 'sightings.html' page in the 'lesson9' folder.
    
    13. Click the 'Test' tab.
    
  Sure enough our new sighting is marked new.
  
  How does this work? It uses [HTTP Cookies]. When you visit the
  'sightings.html' page a cookie is set that records the current
  time. Then each time you return to the page sightings that are newer
  than the cookie will be marked as new.
  
  Let's look at 
  how this works.
  
    1. Click the 'sightings.html' template to view its contents.
    
  Notice that the page uses the [tal:define] statement to defines a
  'lastVisit' variable. It is defined by calling the 'lastVisit.py'
  script. This variable holds the time that the user last visited the
  page as recorded in a cookie.

  Later in the template this time is compared to the modification time
  of each sighting object. If the sighting is new then it is marked as
  such by including a bold tag.  The bold tag uses the [tal:condition]
  statement to optionally include its contents. In this case the
  condition checks to see whether the 'bobobase_modification_date' of
  the sighting is newer than the last visit. This strangely named
  method keeps track of the last modification date of Zope objects.

  Now let's examine the 
  'lastVisit.py' script.

    2. Click on the 'lastVisit.py' script to view it.

  Notice how it includes comments explaining its functioning. Comments
  begin with a number sign. The script does two things: it retrieves a
  cookie from the request, and it sets a new cookie using the
  response.
  
  Summary
  
    You can use cookies to personalize a web page. Zope templates
    can dynamically control their presentation.
  
    * You can set cookies with the response 'setCookie' method.
    
    * The [tal:condition] statement allows you to test conditions.
    
    * The [DateTime] function allows you to get the current time.

    * The 'bobobase_modification_date' method returns the last
    modification time of an object.
 
  In the next lesson you'll learn how to create
  a mail feedback form.
 
Lesson 10. So You've Seen Elvis

  <dtml-var "tutorialShowLesson(10, REQUEST)">
  What's the first thing you do when you spot Elvis? Report it at the
  "Elvis Lives" web site! Let's enhance our site to allow visitors to
  report their Elvis sightings.
  
    1. Click the 'mailhost' [Mail Host] object to edit it.
    
    2. Type the name of your mail server in the 'SMTP Host' field.
    
  Your mail server is typically named 'mail' or 'smtp'. For example,
  'mail.elvislives.com'. If you don't know the name of your mail
  server, ask your system administrator, or check the configuration of
  your mail client.
  
    3. Click the 'Save Changes' button.
    
  Now Zope can send mail. Next let's edit the mail 
  sending script.
  
    1. Click the 'action.py' script to edit it.
    
  This script is called when a site visitor fills out an Elvis
  sighting form. It sends you mail telling you about the
  sighting. Mail is sent by calling the 'simple_send' method of the
  Mail Host object.
  
  To get this script to work you need to change the 'recipient' and
  'sender' variables.
 
    2. Change the 'recipient' and 'sender' variables to your email
    address in place of 'user@host'.
    
    3. Click the 'Save Changes' button.
    
    4. Now go to the 'form.html' page in the 'lesson10' folder.
    
    5. Click the 'Test' tab to view it.
    
    6. Fill out the Elvis sighting form and submit it.
    
  You should soon receive a piece of email describing the Elvis
  sighting.
  
  Congratulations, you've built a mail form. If you receive a Zope
  error, there is a good chance that you haven't set the 'SMTP Host'
  setting on your mail host object correctly.
 
  Summary
  
    After you create a mail host, you can send mail from any
    script by calling its 'simple_send' method.
  
    * [Mail Host]s allow you to send email.
    
    * The scripts format email messages and pass them to the Mail
      Host.

  In the next lesson you'll learn how to use Zope
  to put a database on the web.

Lesson 11. The Elvis Files

  <dtml-var "tutorialShowLesson(11, REQUEST)">
  Everyone knows that serious web sites use databases. We agree. Let's
  convert our Elvis sightings system to use a relational database.
  This will provide us with scalability and interoperability.
  
  Let's see how Zope gets data
  from a database.
  
    1. Click the 'connection' [Database Connection] to edit it.
    
  A [Database Connection] tells Zope how to access a relational
  database. 
  
    2. Click the 'Browse' tab to examine the database tables.
    
    3. Click the plus box next to the 'ELVIS_SIGHTINGS' table to
    expand it.
    
  Now you can see the column names and types for this table. Now let's
  see how to get information out of this table.

    1. Click the 'getSightings' [ZSQL Method] in the 'lesson11' folder
    to edit it.
 
  Notice that the SQL statement used to fetch information about Elvis
  sightings is editable in the 'Query template' field.
  
    2. Click the 'Test' tab.
    
    3. Click the 'Submit  Query' button.
    
  This shows you what data the ZSQL Method returns.
  
  A [ZSQL Method] is used to get information out of or into a relational
  database.
  
  Now let's see how to use
  this ZSQL Method in a web page.
  
    1. Click the 'sightings.html' template in the 'lesson11' folder
    to edit it. 

  Notice that the sightings are generated by iterating over the
  results of the 'getSightings' ZSQL Method with the [tal:repeat]
  statement.
  
    2. Add a line after each sighting by changing the contents of
    the 'sightings.html' template to::
    
      <html>

      <div tal:repeat="sighting container/getSightings">

      <p><span tal:replace="sighting/date">date</span> -- 
         <span tal:replace="sighting/location">location</span>
      </p>

      <p>Reported by <span tal:replace="sighting/name">name</span>
      </p>

      <p tal:content="sighting/description">description
      </p>

      <hr>
      </div>

      </html>
      
    3. Click the 'Save Changes' button.
    
    4. Click the 'Test' tab to view the page.
    
  Summary
  
    Zope can work with data from relational databases in the
    same way it treats other Zope objects.
  
    * [Database Connection]s tell Zope about relational databases.
 
    * [ZSQL Method]s get information out of or into a relational
    database.

Lesson 12. The Elvis Files, cont.

  <dtml-var "tutorialShowLesson(12, REQUEST)"> In the last lesson you
  created an Elvis sightings database. Now let's adapt the this
  database to allow site visitors to submit their own sightings.

  This lesson builds on your experience from the last two lessons. To
  allow folks to report sightings you'll need a report form just like
  you used in lesson 10. 

    1. Click on the 'form.html' template to view its contents.

  This page is almost exactly like the report form used in Lesson
  10. It collects data and calls the 'action.py' script to
  process the data.

    2. Click on the 'action.py' Python Script to view its contents.

  It calls the 'insertSighting' ZSQL Method with this
  code::

    insert(name=name, location=location, date=date,
           description=description)

  Then it returns a confirmation page.

  The real work is done by the
  'insertSighting' ZSQL Method. Let's see how.

    3. Click on the 'insertSighting' ZSQL Method to view its contents.

  The query template contains the following SQL code::

    insert into elvis_sightings
      values(
    <dtml-sqlvar location type="string">,
    <dtml-sqlvar date type="string">,
    <dtml-sqlvar name type="string">,
    <dtml-sqlvar description type="string"> 
    )
  
  This code inserts a row into the 'elvis_sightings' table. Notice how
  the arguments of this ZSQL Method correspond to the form elements in
  the 'form.html' template.

  You can test this SQL code to make sure it
  works correctly.

    1. Click on the 'Test' tab.

    2. Enter some sample data into the automatically generated form.

    3. Click the 'Submit Query' button.

  Zope will send the SQL code to the database and will tell you the
  SQL code that was sent, and the results that the database
  returned. In this case the database will not return anything, since
  the SQL 'INSERT' command produces no results.

  Now return to the 'sightings.html' page to see if the sample data
  was added to the list of sightings. Play with the system a little
  bit and see how the links between the 'sightings.html', 'form.html',
  and 'action.py' objects allow a visitor to navigate the site.

  Summary

    You can easily change data in a relational database with Zope. The
    process for inserting data is very similar to the process for
    querying a database; you use a ZSQL Method in both cases.

    * [ZSQL Method]s can change information in a relational
    database.

    * You can pass arguments to ZSQL Methods from scripts. 

    * Many ZSQL Methods can use the same [Database Connection].

Congratulations

  Well done! You've finished the Zope Tutorial.
  
  You can return to lesson examples and use these objects as the
  basis of your own experiments. Just copy and paste them and start
  changing them.
  
  To find out more about Zope visit
  Zope.org (http://www.zope.org).
  
  You may be especially interested in the Zope Book (http://www.zope.org/Documentation/Books/ZopeBook), How-Tos (http://www.zope.org/Documentation/How-To), mailing lists (http://www.zope.org/Resources/MailingLists), example applications (available in
  the 'Examples' folder in the root folder, and the Zope Documentation
  Project (http://zdp.zope.org).
  
