[Checkins] SVN: zope2docs/branches/baijum-reorganize/ - Moved sources to zope2book directory

Baiju M baiju.m.mail at gmail.com
Sat Oct 10 01:47:19 EDT 2009


Log message for revision 104982:
  - Moved sources to zope2book directory
  - Removed buildout and Sphinx conf
  

Changed:
  U   zope2docs/branches/baijum-reorganize/index.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/Acquisition.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/AdvDTML.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/AdvZPT.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/AppendixA.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/AppendixB.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/AppendixC.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/AppendixD.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/AppendixE.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/BasicObject.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/BasicScripting.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/Contributions.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/DTML.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/ExternalTools.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/InstallingZope.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/IntroducingZope.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/MaintainingZope.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/Makefile
  A   zope2docs/branches/baijum-reorganize/zope2book/ObjectOrientation.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/Preface.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/RelationalDatabases.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/ScriptingZope.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/SearchingZCatalog.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/Security.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/Sessions.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/SimpleExamples.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/UsingZope.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/VirtualHosting.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/ZEO.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/ZPT.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/ZopeArchitecture.rst
  A   zope2docs/branches/baijum-reorganize/zope2book/ZopeServices.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/bootstrap.py
  D   zope2docs/branches/baijum-reorganize/zope2book/buildout.cfg
  A   zope2docs/branches/baijum-reorganize/zope2book/index.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/Acquisition.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/AdvDTML.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/AdvZPT.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/AppendixA.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/AppendixB.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/AppendixC.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/AppendixD.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/AppendixE.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/BasicObject.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/BasicScripting.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/Contributions.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/DTML.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/ExternalTools.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/InstallingZope.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/IntroducingZope.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/MaintainingZope.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/ObjectOrientation.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/Preface.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/RelationalDatabases.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/ScriptingZope.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/SearchingZCatalog.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/Security.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/Sessions.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/SimpleExamples.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/UsingZope.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/VirtualHosting.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/ZEO.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/ZPT.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/ZopeArchitecture.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/ZopeServices.rst
  D   zope2docs/branches/baijum-reorganize/zope2book/source/conf.py
  D   zope2docs/branches/baijum-reorganize/zope2book/source/index.rst

-=-
Modified: zope2docs/branches/baijum-reorganize/index.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/index.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/index.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -5,7 +5,7 @@
 .. toctree::
    :maxdepth: 1
 
-   zope2book/source/index
+   zope2book/index
    zdgbook/source/index
 
 Release information

Copied: zope2docs/branches/baijum-reorganize/zope2book/Acquisition.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/Acquisition.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/Acquisition.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/Acquisition.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,287 @@
+Acquisition
+###########
+
+Acquisition is the technology that allows dynamic behavior to be
+shared between Zope objects via *containment*.
+
+Acquisition's flavor permeates Zope and can be used almost everywhere within
+Zope: in Zope Page Templates, in Script (Python) objects, and even in Zope
+URLs. Because of its ubiquity in Zope, a basic understanding of acquisition is
+important.
+
+Over the years Acquisition has been proven to be a very powerful but often
+too complex technology to use. While it is predictable in simple interactions,
+it gets increasingly complicated to understand its behavior in most
+real-world-sized projects.
+
+In order to understand Zope, you will still need an understanding of
+Acquisition today. Basing your application logic on it is highly
+discouraged, though.
+
+
+Acquisition vs. Inheritance
+===========================
+
+The chapter entitled `Object Orientation <ObjectOrientation.html>`_
+describes a concept called *inheritance*.  Using inheritance, an
+object can *inherit* some of the behaviors of a specific class,
+*overriding* or adding other behaviors as necessary.  Behaviors of
+a class are nearly always defined by its *methods*, although
+attributes can be inherited as well.
+
+In a typical object-oriented language, there are rules that define the way
+a *subclass* inherits behavior from its *superclasses*.  For
+example, in Python (a *multiple-inheritance* language), a class
+may have more than one superclass, and rules are used to determine
+which of a class' superclasses is used to define behavior in any
+given circumstance.
+
+We'll define a few Python classes here to demonstrate.  You don't
+really need to know Python inside and out to understand these
+examples.  Just know that a 'class' statement defines a class, and
+a 'def' statement inside of a class statement defines a method.
+A class statement followed by one or more words inside (parentheses)
+causes that class to *inherit* behavior from the classes named in
+the parentheses (you can play along at home if you like, using the
+Python interpreter).::
+
+  >>> class SuperA:
+  ...     def amethod(self):
+  ...         print "I am the 'amethod' method of the SuperA class"
+  ...     def anothermethod(self):
+  ...         print "I am the 'anothermethod' method of the SuperA class"
+  ...
+  >>> class SuperB:
+  ...     def amethod(self):
+  ...         print "I am the 'amethod' method of the SuperB class"
+  ...     def anothermethod(self):
+  ...         print "I am the 'anothermethod' method of the SuperB class"
+  ...     def athirdmethod(self):
+  ...         print "I am the 'athirdmethod' method of the SuperB class"
+  ...
+  >>> class Sub(SuperA, SuperB):
+  ...     def amethod(self):
+  ...         print "I am the 'amethod' method of the Sub class"
+  ...
+
+If we make an *instance* of the "Sub" class, and attempt to *call*
+one of its methods, there are rules in place to determine whether
+the behavior of the method will be defined by the Sub class
+itself, its SuperA superclass, or its SuperB superclass.  The
+rules are fairly simple: if the Sub class has itself defined the
+named method, that method definition will be used.  Otherwise, the
+*inheritance hierarchy* will be searched for a method definition.
+
+The *inheritance hierarchy* is defined by the class' superclass
+definitions.  The case of the Sub class above has a simple
+inheritance hierarchy: it inherits first from the SuperA
+superclass, then it inherits from the SuperB superclass.  This
+means that if you call a method on an instance of the Sub class,
+and that method is not defined as part of the Sub class'
+definition, it will first search for the method in the SuperA
+class.  If it doesn't find it there, it will search in the
+SuperB class.  Python performs this search of the base classes
+using an order derived from the order of declaration.  Note that for
+complex cases (e.g., where the same method is defined in several
+ancestors of base classes), the lookup order is too complicated to
+explain within the scope of this book.  Please see the online
+Python documentation for the "method resolution order",
+http://www.python.org/download/releases/2.3/mro/
+
+Here is an example of calling methods on an instance of the
+above-defined Sub class::
+
+  >>> instance = Sub()
+  >>> instance.amethod()
+  I am the 'amethod' method of the Sub class
+  >>> instance.anothermethod()
+  I am the 'anothermethod' method of the SuperA class
+  >>> instance.athirdmethod()
+  I am the 'athirdmethod' method of the SuperB class
+
+Note that when we called the 'anothermethod' method on the Sub
+instance, we got the return value of SuperA's method definition
+for that method, even though both SuperA and SuperB defined that
+method.  This is because the inheritance hierarchy specifies that
+the first superclass (SuperA) is searched first.
+
+The point of this example is that instances of objects use their
+*inheritance hierarchy* to determine their behavior.  In non-Zope
+applications, this is the only way that object instances know
+about their set of behaviors.  However, in Zope, objects make use
+of another facility to search for their behaviors: *acquisition*.
+
+Acquisition Is about Containment
+================================
+
+The concept behind acquisition is simple:
+
+- Objects are situated inside other objects, and these objects act as
+  their "containers".  For example, the container of a Page Template
+  named "apage" inside a Folder "afolder" is the
+  "afolder" folder.
+
+- Objects may acquire behavior from their containers.
+
+Inheritance stipulates that an object can learn about its behavior
+from its superclasses via an *inheritance hierarchy*.
+*Acquisition*, on the other hand, stipulates that an object can
+additionally learn about its behavior through its *containment
+hierarchy*.  In Zope, an object's inheritance hierarchy is always
+searched for behavior before its acquisition hierarchy.  If the
+method or attribute is not found in the object's inheritance
+hierarchy, then the acquisition hierarchy is searched.
+
+Say What?
+=========
+
+Let's toss aside the formal explanations.  Acquisition can be
+best explained with a simple example.
+
+Place a Page Template named 'acquisition_test' in your Zope root
+folder.  Give it the following body::
+
+  <html>
+  <body>
+    <p>
+     I am being called from within the
+     <span tal:replace="context/title" />
+     Folder!
+    </p>
+  </body>
+  </html>
+
+Save it, and then use the Page Template "View" tab to see the result
+of the template in your Workspace frame.  You will see
+something not unlike the following::
+
+  I am being called from within the Zope Folder!
+
+The 'title' of the Zope root folder is 'Zope', so this makes
+sense.  Now create a Folder inside your Zope root folder
+named 'AcquisitionTestFolder' and a title of
+"TheAcquisitionTest".  We're going to invoke the
+'acquisition_test' page *in the context of* the
+AcquisitionTestFolder folder.  To do this, assuming your
+Zope is running on your local machine on port 8080, visit
+the URL
+'http://localhost:8080/AcquisitionTestFolder/acquisition_test'.
+You will see something not unlike the following::
+
+  I am being called from within the TheAcquisitionTest Folder!
+
+Note that even though an object named 'acquisition_test' does not
+"live" inside the AcquisitionTestFolder folder, Zope found the
+page and displayed a result anyway!  Not only did Zope display a
+result, instead of inserting the 'title' of the Zope root folder, it
+inserted the 'title' of the AcquisitionTestFolder folder!
+
+This is an example of acquisition in action.  The concept is simple:
+if a named object is not found as an attribute of the object you're
+searching, its containers are searched until the object is found.
+In this way, acquisition can *add behavior* to objects.  In this
+case, we added a behavior to the AcqusitionTestFolder folder that
+it didn't have before (by way of adding an 'acquisition_test' page).
+
+Providing Services
+==================
+
+It can be said that acquisition allows objects to acquire
+*services* by way of containment.  For example, our
+AcquisitionTestFolder folder acquired the services of the
+'acquisition_test' page.
+
+Not only do objects *acquire* services, but they also *provide* them. For
+example, adding a Mail Host object to a Folder named 'AFolder'
+provides other objects in that folder with the ability to send
+mail.  But it also provides objects contained in *subfolders* of
+that folder with the capability to send mail.  If you create
+subfolders of 'AFolder' named 'AnotherFolder' and 'AThirdFolder',
+you can be assured that objects placed in *these* folders will
+also be able to send mail in exactly the same way as objects
+placed in 'AFolder'.
+
+Acquisition "goes both ways": when you create an object in Zope,
+it has the capability to automatically acquire services.
+Additionally, it automatically provides services that other
+objects can acquire. This makes reuse of services very easy, since
+you don't have to do anything special in order to make services available
+to other objects.
+
+Getting Deeper with Multiple Levels
+===================================
+
+If you place a method in the root folder, and create a subfolder
+in the root folder, you can acquire the method's behaviors. So
+what happens if things get more complex?  Perhaps you have a
+method that needs to be acquired from within a couple of
+folders. Is it acquired from its parent, or its parent's parent,
+or what?
+
+The answer is that acquisition works on the entire object
+hierarchy. If, for example, you have a Page Template, "HappySong",
+in the root folder, and also in the root folder you have three
+nested Folders named "Users", "Barney" and "Songs",
+you may call this URL::
+
+  /Users/Barney/Songs/HappySong
+
+The HappySong page is found in the root folder, unless one of the
+other folders "Users", "Barney" or "Songs" happens to also have a
+page named "HappySong", in which case *that* page is used instead.
+The HappySong page is searched for first directly in the "Songs"
+folder.  If it is not found, the acquisition hierarchy is searched
+starting at the first container in the hierarchy: "Barney".  If it
+is not found in "Barney", the "Users" folder is searched.  If it
+is not found in the "Users" folder, the root folder is searched.
+This search is called *searching the acquisition path* or
+alternately *searching the containment hierarchy*.
+
+Acquisition is not limited to searching a containment hierarchy: it
+can also search a *context hierarchy*.  Acquisition by context is
+terribly difficult to explain, and you should avoid it if at all
+possible.
+
+In the example above, for instance, in order to find and publish
+the "HappySong" template at the end of the URL, acquisition searches
+the *containment hierarchy* of the "Songs" folder first.  Because
+"Songs" is contained within "Barney", and "Barney" within "Users",
+the *containment hierarchy* for "Songs" consists of each folder "up"
+from "Users" to the root.
+
+Once the "HappySongs" template is found, there are two hierarchies of
+interest:
+
+- Because "HappySongs" is located directly within the root, its
+  *containment hierarchy* consists of only itself and the root.
+
+- Because "HappySongs" was found by traversing first through the
+  "Users", "Barney", and "Songs" folders, its *context hierarchy*
+  includes those objects.
+
+Acquisition searches the *context hierarchy* only after failing
+to find the named object in the *containment hierarchy*.
+
+As with understanding Python's concept of multiple inheritance, explaining
+the exact strategy used to order that search is not within the scope of this
+book.
+
+Summary
+=======
+
+Acquisition allows behavior to be distributed hierarchically throughout the
+system. When you add a new object to Zope, you don't need to
+specify all of its behavior, only the part of its behavior that is
+unique to that object. For the rest of its behavior, it relies on other
+objects. This means that you can change an object's behavior by
+changing where it is located in the object hierarchy. This is a
+very powerful function that gives your Zope applications
+flexibility.
+
+Acquisition is useful for providing objects with behavior that
+doesn't need to be specified by their own methods or methods found
+in their inheritance hierarchies.  Acquisition is particularly
+useful for sharing information (such as headers and footers)
+between objects in different folders as well.  You will see how
+you can make use of acquisition within different Zope technologies
+in upcoming chapters.

Copied: zope2docs/branches/baijum-reorganize/zope2book/AdvDTML.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/AdvDTML.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/AdvDTML.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/AdvDTML.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,1440 @@
+Advanced DTML
+=============
+
+DTML is the kind of language that appears to "do what you mean."
+That is good when it does what you actually want it to do, but when
+it does something you don't want to do, well, it's no fun at all.
+This chapter tells you how to make DTML do what you *really* mean.
+When you're done reading this chapter you will be able to write DTML
+that will accomplish a number of complex tasks including:
+
+- Inspect and Modify the REQUEST object
+
+- Modify the current namespace
+
+- Call other scripts from within DTML
+
+- Send email with or without MIME attachments
+
+- Handle exceptions within DTML    
+
+A few of caveats before getting started:
+
+- It's a good idea to know something about Python before diving into
+  advanced DTML or any other advanced area of Zope.
+
+- Understand the Zope acquisition model and how it works.
+
+- If you are writing very complex functionality in DTML, consider
+  using a Python Script.  This will ease maintenance, not to mention
+  readability.
+
+- Understand the difference between a DTML Document and a DTML
+  Method before embarking on building a huge site. See the explanation
+  included in this chapter.
+
+It's no lie that DTML has a reputation for complexity.  While it is true
+that DTML is really simple if all you want to do is simple layout,
+using DTML for more advanced tasks requires an understanding of where 
+DTML variables come from.
+
+Here's a very tricky error that almost all newbies encounter.
+Imagine you have a DTML Document called *zooName*.  This
+document contains an HTML form like the following::
+
+  <dtml-var standard_html_header>
+
+    <dtml-if zooName>
+
+      <p><dtml-var zooName></p>
+
+    <dtml-else>
+
+      <form action="<dtml-var URL>" method="GET">
+        <input name="zooName">
+        <input type="submit" value="What is zooName?">
+      </form>
+
+    </dtml-if>  
+
+  <dtml-var standard_html_footer>
+
+This looks simple enough, the idea is, this is an HTML page that calls
+itself.  This is because the HTML action is the *URL* variable, which
+will become the URL of the DTML Document.  
+
+If there is a 'zooName' variable, then the page will print it, if there
+isn't, it shows a form that asks for it.  When you click submit, the data
+you enter will make the "if" evaluate to true, and this code should print
+what was entered in the form.
+
+But unfortunately, this is one of those instances where DTML will not do
+what you mean, because the name of the DTML Document that contains this
+DTML is also named *zooName*, and it doesn't use the variable out of the
+request, it uses itself, which causes it to call itself and call itself, ad
+infinitum, until you get an "excessive recursion" error.  So instead of
+doing what you really meant, you got an error. This is what confuses
+beginners.  In the next couple of sections, we'll show you how to fix this
+example to do what you mean.
+
+How Variables are Looked up
+---------------------------
+
+There are actually two ways to fix the DTML error in the
+*zooName* document.  The first is that you can rename the document
+to something like *zopeNameFormOrReply* and always remember this
+special exception and never do it; never knowing why it happens.
+The second is to understand how names are looked up, and to be
+explicit about where you want the name to come from in the
+*namespace*.
+
+The DTML namespace is a collection of objects arranged in a *stack*.  A
+stack is a list of objects that can be manipulated by *pushing* and
+*popping* objects on to and off of the stack. 
+
+When a DTML Document or DTML Method is executed, Zope creates a
+DTML namespace to resolve DTML variable names. It's important to
+understand the workings of the DTML namespace so that you can
+accurately predict how Zope will locate variables. Some of the
+trickiest problems you will run into with DTML can be resolved by
+understanding the DTML namespace.
+
+When Zope looks for names in the DTML namespace stack it first looks at
+the topmost object in the stack.  If the name can't be found
+there, then the next item down is introspected.  Zope will work its way
+down the stack, checking each object in turn until it finds the name
+that it is looking for.
+
+If Zope gets all the way down to the bottom of the stack and
+can't find what it is looking for, then an error is generated.  For
+example, try looking for the non-existent name, *unicorn*::
+
+  <dtml-var unicorn>
+
+As long as there is no variable named *unicorn* viewing this
+DTML will return an error, as shown in the figure below.
+
+.. figure:: Figures/7-1.png
+
+   DTML error message indicating that it cannot find a variable
+
+But the DTML stack is not all there is to names because DTML
+doesn't start with an empty stack, before you even begin executing
+DTML in Zope there are already a number of objects pushed on the
+namespace stack.
+
+DTML Namespaces
+---------------
+
+DTML namespaces are built dynamically for every request in Zope. When
+you call a DTML Method or DTML Document through the web, the DTML
+namespace starts with the same first two stack elements; the client
+object and the request, as shown in the figure below.
+
+.. figure:: Figures/7-2.png
+
+   Initial DTML namespace stack
+
+The client object is the first object on the top of the DTML namespace
+stack when entering a transaction (note:  commands exist to push 
+additional parameters onto the namespace stack during a thread of 
+execution).  What the client object is depends on whether you are
+executing a DTML Method or a DTML Document.  In our example above, this
+means that the client object is named *zooName*.  Which is why it
+breaks.  The form input that we really wanted comes from the web
+request, but the client is looked at first.
+
+The request namespace is always on the bottom of the DTML namespace
+stack, and is therefore the last namespace to be looked in for names.
+This means that we must be explicit in our example about which
+namespace we want.  We can do this with the DTML 'with' tag::
+
+  <dtml-var standard_html_header>
+
+    <dtml-with REQUEST only>
+      <dtml-if zooName>
+        <p><dtml-var zooName></p>
+      <dtml-else>
+        <form action="<dtml-var URL>" method="GET">
+          <input name="zooName">
+          <input type="submit" value="What is zooName?">
+        </form>
+      </dtml-if>
+    </dtml-with>
+
+  <dtml-var standard_html_footer>
+
+Here, the with tag says to look in the 'REQUEST' namespace, and *only*
+the 'REQUEST' namespace, for the name "zooName".
+
+DTML Client Object  
+~~~~~~~~~~~~~~~~~~
+
+The client object in DTML depends on whether or not you are executing a
+DTML Method or a DTML Document.  In the case of a Document, the client
+object is always the document itself, or in other words, a DTML
+Document is its own client object.
+
+A DTML Method however can have different kinds of client objects
+depending on how it is called.  For example, if you had a DTML Method
+that displayed all of the contents of a folder then the client object
+would be the folder that is being displayed.  This client object can
+change depending on which folder the method in question is
+displaying.  For example, consider the following DTML Method named
+*list* in the root folder::
+
+  <dtml-var standard_html_header>
+
+  <ul>
+  <dtml-in objectValues>
+    <li><dtml-var title_or_id></li>
+  </dtml-in>
+  </ul>
+
+  <dtml-var standard_html_footer>
+
+Now, what this method displays depends upon how it is used.  If
+you apply this method to the *Reptiles* folder with the URL
+'http://localhost:8080/Reptiles/list', then you will get
+something that looks like the figure below.
+
+.. figure:: Figures/7-3.png
+
+   Applying the *list* method to the *Reptiles* folder
+
+But if you were to apply the method to the *Birds* folder with
+the URL *http://localhost:8080/Birds/list* then you would get
+something different, only two items in the list, *Parrot* and
+*Raptors*.
+
+Same DTML Method, different results. In the first example, the client
+object of the *list* method was the *Reptiles* folder.  In the second
+example, the client object was the *Birds* folder. When Zope looked
+up the *objectValues* variable, in the first case it called the
+*objectValues* method of the *Reptiles* folder, in the second case it
+called the *objectValues* method of the *Birds* folder.
+
+In other words, the client object is where variables such as
+methods, and properties are looked up first.
+
+As you saw in "Dynamic Content with DTML", if Zope
+cannot find a variable in the client object, it searches through
+the object's containers.  Zope uses acquisition to automatically
+inherit variables from the client object's containers.  So when
+Zope walks up the object hierarchy looking for variables it
+always starts at the client object, and works its way up from
+there.
+
+DTML Method vs. DTML Document
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One of the most potentially confusing choices to make for Zope
+newbies is the choice between a DTML Method and a DTML Document.
+Unfortunately, many Zope newbies develop entire sites using one 
+type of object only to discover that they should have used the 
+other type. In general, keep the following items in mind when 
+deciding upon which type to use:
+
+- **Does the object require properties of its own?** If so,
+    use a DTML Document since DTML Methods have no inherent
+    properties.
+
+- **Does the object need to be called as a "page"?** If so,
+    consider using a DTML Document since it will be easier
+    to control such items as page title by using properties.
+
+- **Does the object need transparency to its context?** If so, 
+    you should probably use a DTML Method since these objects
+    act as though they are directly attached to their calling, 
+    or containing object.
+
+DTML Request Object
+~~~~~~~~~~~~~~~~~~~
+
+The request object is the bottom object on the DTML
+namespace stack.  The request contains all of the information
+specific to the current web request.
+
+Just as the client object uses acquisition to look in a number
+of places for variables, so too the request looks up variables
+in a number of places. When the request looks for a variable it
+consults these sources in order:
+
+1. The CGI environment. The `Common Gateway Interface
+   <http://www.w3.org/CGI/>`_, or CGI interface defines
+   a standard set of environment variables to be used by
+   dynamic web scripts.  These variables are provided by Zope
+   in the REQUEST namespace.
+
+2. Form data. If the current request is a form action, then
+   any form input data that was submitted with the request can
+   be found in the REQUEST object.
+
+3. Cookies. If the client of the current request has any cookies
+   these can be found in the current REQUEST object.
+
+4. Additional variables. The REQUEST namespace provides you
+   with lots of other useful information, such as the URL of
+   the current object and all of its parents.
+
+The request namespace is very useful in Zope since it is the
+primary way that clients (in this case, web browsers)
+communicate with Zope by providing form data, cookies and other
+information about themselves. For more information about the
+request object, see Appendix B.
+
+A very simple and enlightening example is to simply render the REQUEST
+object in a DTML Document or Method::
+
+  <dtml-var standard_html_header>
+
+  <dtml-var REQUEST>
+
+  <dtml-var standard_html_footer>
+
+Try this yourself, you should get something that looks like
+the figure below.
+
+.. figure:: Figures/7-4.png
+
+   Displaying the request
+
+Since the request comes after the client object, if there are names
+that exist in both the request and the client object, DTML will
+always find them first in the client object. This can be a
+problem. Next, let's look at some ways to get around this problem by
+controlling more directly how DTML looks up variables.
+
+Rendering Variables
+-------------------
+
+When you insert a variable using the *var* tag, Zope first looks
+up the variable using the DTML namespace, it then *renders* it
+and inserts the results. Rendering means turning an object or
+value into a string suitable for inserting into the output. Zope
+renders simple variables by using Python's standard method for
+coercing objects to strings. For complex objects such as DTML
+Methods and SQL Methods, Zope will call the object instead of
+just trying to turn it into a string. This allows you to insert
+DTML Methods into other DTML Methods.
+
+In general Zope renders variables in the way you would
+expect. It's only when you start doing more advanced tricks that
+you become aware of the rendering process. Later in this chapter
+we'll look at some examples of how to control rendering using
+the 'getitem' DTML utility function.
+
+Modifying the DTML Namespace
+----------------------------
+
+Now that you know the DTML namespace is a stack, you may
+be wondering how, or even why, new objects get pushed onto it.
+
+Some DTML tags modify the DTML namespace while they are executing.
+A tag may push some object onto the namespace stack during the
+course of execution.  These tags include the *in* tag, the *with*
+tag, and the *let* tag.
+
+*In* Tag Namespace Modifications
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When the *in* tag iterates over a sequence it pushes the current
+item in the sequence onto the top of the namespace stack::
+
+  <dtml-var getId> <!-- This is the id of the client object -->
+
+  <dtml-in objectValues>
+
+    <dtml-var getId> <!-- this is the id of the current item in the 
+                       objectValues sequence -->
+  </dtml-in>
+
+You've seen this many times throughout the examples in this
+book.  While the *in* tag is iterating over a sequence, each item
+is pushed onto the namespace stack for the duration of the
+contents of the in tag block.  When the block is finished
+executing, the current item in the sequence is popped off the
+DTML namespace stack and the next item in the sequence is pushed
+on.
+
+Additional Notes
+%%%%%%%%%%%%%%%%
+
+To be more accurate, the *in* tag pushes a number of items
+onto the namespace stack.  These include sequence variables,
+grouping variables, and batch variables in addition to the
+object itself.  Some of those variables are:
+
+- sequence-item: The current item within the iteration.
+
+- sequence-start: True if the current item is the first item
+  in the sequence.
+
+- sequence-end: True if the current item is the last item in
+   the sequence.
+
+- sequence-length: The length of the sequence. 
+
+- previous-sequence: True on the first iteration if the
+  current batch is not the first one. Batch size is set with the
+  size attribute.
+
+- next-sequence: True on the last iteration if the current
+  batch is not the last batch.
+
+There are many more variables available when using the *in*
+tag.  See `Appendix A <AppendixA.html>`_ for more detail.
+
+The *With* Tag
+~~~~~~~~~~~~~~
+
+The *with* tag pushes an object that you specify onto 
+the namespace stack for the duration of the with block. This
+allows you to specify where variables should be looked up first.
+When the with block closes, the object is popped off the
+namespace stack.
+
+Consider a folder that contains a bunch of methods and
+properties that you are interested in.  You could access those
+names with Python expressions like this::
+
+  <dtml-var standard_html_header>
+
+  <dtml-var expr="Reptiles.getReptileInfo()">
+  <dtml-var expr="Reptiles.reptileHouseMaintainer">
+
+  <dtml-in expr="Reptiles.getReptiles()">
+    <dtml-var species>
+  </dtml-in>
+
+  <dtml-var standard_html_footer>
+
+Notice that a lot of complexity is added to the code just to get
+things out of the *Reptiles* folder. Using the *with* tag you can
+make this example much easier to read::
+
+  <dtml-var standard_html_header>
+
+  <dtml-with Reptiles>
+
+    <dtml-var getReptileInfo>
+    <dtml-var reptileHouseMaintainer>
+
+    <dtml-in getReptiles>
+      <dtml-var species>
+    </dtml-in>
+
+  </dtml-with>
+
+  <dtml-var standard_html_footer>
+
+Another reason you might want to use the *with* tag is to put the
+request, or some part of the request on top of the namespace
+stack. For example suppose you have a form that includes an input
+named *id*. If you try to process this form by looking up the
+*id* variable like so::
+
+  <dtml-var id>
+
+You will not get your form's id variable, but the client
+object's id. One solution is to push the web request's form on
+to the top of the DTML namespace stack using the *with* tag::
+
+  <dtml-with expr="REQUEST.form">
+    <dtml-var id>
+  </dtml-with>
+
+This will ensure that you get the form's id first. See Appendix
+B for complete API documentation of the request object.
+
+If you submit your form without supplying a value for the *id* input,
+the form on top of the namespace stack will do you no good, since the
+form doesn't contain an *id* variable. You'll still get the client
+object's id since DTML will search the client object after failing to
+find the *id* variable in the form. The *with* tag has an attribute
+that lets you trim the DTML namespace to only include the object you
+pushed onto the namespace stack::
+
+  <dtml-with expr="REQUEST.form" only>
+    <dtml-if id>
+      <dtml-var id>
+    <dtml-else>
+      <p>The form didn't contain an "id" variable.</p>
+    </dtml-if>
+  </dtml-with>
+
+Using the *only* attribute allows you to be sure about where
+your variables are being looked up.
+
+The *Let* Tag
+~~~~~~~~~~~~~
+
+The *let* tag lets you push a new namespace onto the namespace stack.
+This namespace is defined by the tag attributes to the *let* tag::
+
+  <dtml-let person="'Bob'" relation="'uncle'">
+    <p><dtml-var person>'s your <dtml-var relation>.</p>
+  </dtml-let>
+
+This would display::
+
+  <p>Bob's your uncle.</p>
+
+The *let* tag accomplishes much of the same goals as the *with*
+tag. The main advantage of the let tag is that you can use it to
+define multiple variables to be used in a block. The *let* tag
+creates one or more new name-value pairs and pushes a
+namespace object containing those variables and their values on
+to the top of the DTML namespace stack. In general the *with*
+tag is more useful to push existing objects onto the namespace
+stack, while the *let* tag is better suited for defining new
+variables for a block.
+
+When you find yourself writing complex DTML that requires things
+like new variables, there's a good chance that you could do the
+same thing better with Python or Perl. Advanced scripting is
+covered in the chapter entitled `Advanced Zope Scripting
+<ScriptingZope.html>`_ .
+
+The DTML namespace is a complex place, and this complexity evolved
+over a lot of time.  Although it helps to understand where names come
+from, it is much more helpful to always be specific about where you
+are looking for a name.  The 'with' and 'let' tags let you alter
+the namespace in order to obtain references to the objects you
+need.
+
+DTML Namespace Utility Functions 
+--------------------------------
+
+Like all things in Zope, the DTML namespace is an object, and it can
+be accessed directly in DTML with the *_* (underscore) object.  The
+*_* namespace is often referred to as "the under namespace".
+
+The under namespace provides you with many useful methods for certain
+programming tasks.  Let's look at a few of them.
+
+Say you wanted to print your name three times.  This can be done
+with the *in* tag, but how do you explicitly tell the *in* tag to
+loop three times?  Just pass it a sequence with three items::
+
+  <dtml-var standard_html_header>
+
+  <ul>
+  <dtml-in expr="_.range(3)">
+    <li><dtml-var sequence-item>: My name is Bob.</li>
+  </dtml-in>
+  </ul>
+
+  <dtml-var standard_html_footer>
+
+The '_.range(3)' Python expression will return a sequence of the
+first three integers, 0, 1, and 2.  The *range* function is a
+*standard Python built-in* and many of Python's built-in functions
+can be accessed through the *_* namespace, including:
+
+'range([start,], stop, [step])'
+  Returns a list of integers
+  from 'start' to 'stop' counting 'step' integers at a
+  time. 'start' defaults to 0 and 'step' defaults to 1.  For example:
+
+'_.range(3,10,2)'
+    gives '[3,5,7,9]'.
+
+'_.len(sequence)'
+  'len' returns the size of *sequence* as an integer.
+
+Many of these names come from the Python language, which contains
+a set of special functions called 'built-ins'.  The Python
+philosophy is to have a small number of built-in names.  The Zope
+philosophy can be thought of as having a large, complex array of
+built-in names.
+
+The under namespace can also be used to explicitly control variable
+look up.  There is a very common usage of this syntax.  As mentioned 
+above the in tag defines a number of special variables, like
+*sequence-item* and *sequence-key* that you can use inside a loop to
+help you display and control it.  What if you wanted to use one of
+these variables inside a Python expression?::
+
+  <dtml-var standard_html_header>
+
+  <h1>The squares of the first three integers:</h1>
+  <ul>
+  <dtml-in expr="_.range(3)">
+    <li>The square of <dtml-var sequence-item> is: 
+      <dtml-var expr="sequence-item * sequence-item">
+    </li>
+  </dtml-in>  
+  </ul>  
+
+  <dtml-var standard_html_footer>
+
+Try this, does it work?  No!  Why not?  The problem lies in this
+var tag::
+
+  <dtml-var expr="sequence-item * sequence-item">
+
+Remember, everything inside a Python expression attribute must be
+a *valid Python expression*.  In DTML, *sequence-item* is the name
+of a variable, but in Python this means "The object *sequence*
+minus the object *item*".  This is not what you want.
+
+What you really want is to look up the variable *sequence-item*.
+One way to solve this problem is to use the *in* tag *prefix*
+attribute. For example::
+
+  <dtml-var standard_html_header>
+
+  <h1>The squares of the first three integers:</h1>
+  <ul>
+  <dtml-in prefix="loop" expr="_.range(3)">
+    <li>The square of <dtml-var loop_item> is: 
+      <dtml-var expr="loop_item * loop_item">
+    </li>
+  </dtml-in>  
+  </ul>  
+
+  <dtml-var standard_html_footer>   
+
+The *prefix* attribute causes *in* tag variables to be renamed
+using the specified prefix and underscores, rather than using
+"sequence" and dashes. So in this example, "sequence-item" becomes
+"loop_item". See Appendix A for more information on the *prefix*
+attribute.
+
+Another way to look up the variable *sequence-item* in a DTML
+expression is to use the *getitem* utility function to explicitly
+look up a variable::
+
+  The square of <dtml-var sequence-item> is:
+  <dtml-var expr="_.getitem('sequence-item') * 
+                  _.getitem('sequence-item')">
+
+The *getitem* function takes the name to look up as its first
+argument. Now, the DTML Method will correctly display the square of the
+first three integers.  The *getitem* method takes an optional second
+argument which specifies whether or not to render the variable. Recall
+that rendering a DTML variable means turning it into a string. By
+default the *getitem* function does not render a variable.
+
+Here's how to insert a rendered variable named *myDoc*::
+
+  <dtml-var expr="_.getitem('myDoc', 1)">
+
+This example is in some ways rather pointless, since it's the
+functional equivalent to::
+
+  <dtml-var myDoc>
+
+However, suppose you had a form in which a user got to select
+which document they wanted to see from a list of choices. Suppose
+the form had an input named *selectedDoc* which contained the name
+of the document. You could then display the rendered document like
+so::
+
+  <dtml-var expr="_.getitem(selectedDoc, 1)">
+
+Notice in the above example that *selectedDoc* is not in
+quotes. We don't want to insert the text *selectedDoc*
+we want to insert the value of the variable named *selectedDoc*. For
+example, the value of *selectedDoc* might be 'chapterOne'. Using this
+method, you can look up an item using a dynamic value instead of 
+static text.
+
+If you are a python programmer and you begin using the more
+complex aspects of DTML, consider doing a lot of your work in
+Python scripts that you call *from* DTML.  This is explained more
+in the chapter entitled `Advanced Zope Scripting`_.
+Using Python sidesteps many of the issues in DTML.
+
+DTML Security
+-------------
+
+Zope can be used by many different kinds of users.  For example, the
+Zope site, `Zope.org <http://www.zope.org/>`_, has over 11,000 community
+members at the time of this writing.  Each member can log into Zope,
+add objects and news items, and manage their own personal area.
+
+Because DTML is a scripting language, it is very flexible about
+working with objects and their properties.  If there were no security
+system that constrained DTML then a user could potentially create
+malicious or privacy-invading DTML code.
+
+DTML is restricted by standard Zope security settings. So if you
+don't have permission to access an object by going to its URL you
+also don't have permission to access it via DTML. You can't use
+DTML to trick the Zope security system.
+
+For example, suppose you have a DTML Document named *Diary* which
+is private. Anonymous users can't access your diary via the
+web. If an anonymous user views DTML that tries to access your
+diary they will be denied::
+
+  <dtml-var Diary>
+
+DTML verifies that the current user is authorized to access all
+DTML variables.  If the user does not have authorization, then the
+security system will raise an *Unauthorized* error and the user
+will be asked to present more privileged authentication
+credentials.
+
+In the chapter entitled `Users and Security <Security.html>`_ , you
+read about security rules for executable content. There are ways
+to tailor the roles of a DTML Document or Method to allow it to
+access restricted variables regardless of the viewer's roles.
+
+Safe Scripting Limits
+---------------------
+
+DTML will not let you gobble up memory or execute infinite loops
+and recursions.  Because the restrictions on looping and memory
+use are relatively tight, DTML is not the right language for
+complex, expensive programming logic.  For example, you cannot
+create huge lists with the *_.range* utility function. You also
+have no way to access the filesystem directly in DTML.
+
+Keep in mind however that these safety limits are simple and can
+be outsmarted by a determined user.  It's generally not a good
+idea to let anyone you don't trust write DTML code on your site.
+
+Advanced DTML Tags
+------------------
+
+In the rest of this chapter we'll look at the many advanced DTML
+tags. These tags are summarized in Appendix A.  DTML has a set of
+built-in tags, as documented in this book, which can be counted on
+to be present in all Zope installations and perform the most
+common kinds of things. However, it is also possible to add new
+tags to a Zope installation. Instructions for doing this are
+provided at the Zope.org website, along with an interesting set
+of contributed DTML tags.
+
+This section covers what could be referred to as Zope
+*miscellaneous* tags.  These tags don't really fit into any broad
+categories except for one group of tags, the *exception handling*
+DTML tags which are discussed at the end of this chapter.
+
+The *Call* Tag
+--------------
+
+The *var* tag can call methods, but it also inserts the return
+value. Using the *call* tag you can call methods without inserting
+their return value into the output.  This is useful if you are
+more interested in the effect of calling a method rather than its
+return value.
+
+For example, when you want to change the value of a property,
+*animalName*, you are more interested in the effect of calling the
+*manage_changeProperties* method than the return value the method
+gives you.  Here's an example::
+
+  <dtml-if expr="REQUEST.has_key('animalName')">
+    <dtml-call expr="manage_changeProperties(animalName=REQUEST['animalName'])">
+    <h1>The property 'animalName' has changed</h1>
+  <dtml-else>
+    <h1>No properties were changed</h1>
+  </dtml-if>
+
+In this example, the page will change a property depending on whether
+a certain name exists.  The result of the *manage_changeProperties*
+method is not important and does not need to be shown to the user.
+
+Another common usage of the *call* tag is calling methods that affect
+client behavior, like the 'RESPONSE.redirect' method.  In this
+example, you make the client redirect to a different page, to
+change the page that gets redirected, change the value for the
+"target" variable defined in the *let* tag::
+
+  <dtml-var standard_html_header>
+
+  <dtml-let target="'http://example.com/new_location.html'">
+
+    <h1>This page has moved, you will now be redirected to the
+    correct location.  If your browser does not redirect, click <a
+    href="<dtml-var target>"><dtml-var target></a>.</h1>
+
+    <dtml-call expr="RESPONSE.redirect(target)">
+
+  </dtml-let>
+
+  <dtml-var standard_html_footer>  
+
+In short, the *call* tag works exactly like the *var* tag with the
+exception that it doesn't insert the results of calling the
+variable.
+
+Another possibility for use of the *call* tag would be to call a
+ZSQL Method or or preprocess the REQUEST.  Two examples of calling
+a ZSQL method::
+
+  <dtml-call "insertLogEntry(REQUEST)">
+
+or::
+
+  <dtml-call "insertLogEntry(logInfo=REQUEST.get('URL0'), severity=1)">
+
+To call a python script that might do any number of things,
+including preprocessing the REQUEST::
+
+  <dtml-call "preprocess(REQUEST)">
+
+The *Comment* Tag
+-----------------
+
+DTML can be documented with comments using the *comment* tag::
+
+  <dtml-var standard_html_header>
+
+  <dtml-comment>
+
+    This is a DTML comment and will be removed from the DTML code
+    before it is returned to the client.  This is useful for
+    documenting DTML code.  Unlike HTML comments, DTML comments
+    are NEVER sent to the client.
+
+  </dtml-comment>
+
+  <!-- 
+
+    This is an HTML comment, this is NOT DTML and will be treated
+    as HTML and like any other HTML code will get sent to the
+    client.  Although it is customary for an HTML browser to hide
+    these comments from the end user, they still get sent to the
+    client and can be easily seen by 'Viewing the Source' of a
+    document.
+
+  -->
+
+  <dtml-var standard_html_footer>        
+
+The *comment* block is removed from DTML output.
+
+In addition to documenting DTML you can use the *comment* tag to
+temporarily comment out other DTML tags. Later you can remove the
+*comment* tags to re-enable the DTML.
+
+The *Tree* Tag
+--------------
+
+The *tree* tag lets you easily build dynamic trees in HTML to
+display hierarchical data.  A *tree* is a graphical representation
+of data that starts with a "root" object that has objects
+underneath it often referred to as "branches".  Branches can have
+their own branches, just like a real tree.  This concept should be
+familiar to anyone who has used a file manager program like
+Microsoft Windows Explorer to navigate a file system.  And, in
+fact, the left hand "navigation" view of the Zope management
+interface is created using the tree tag.
+
+For example here's a tree that represents a collection of folders
+and sub-folders.
+
+.. figure:: Figures/7-5.png
+
+   HTML tree generated by the tree tag
+
+Here's the DTML that generated this tree display::
+
+  <dtml-var standard_html_header>
+
+  <dtml-tree>
+
+    <dtml-var getId>
+
+  </dtml-tree>
+
+  <dtml-var standard_html_footer>
+
+The *tree* tag queries objects to find their sub-objects and takes
+care of displaying the results as a tree. The *tree* tag block works
+as a template to display nodes of the tree.
+
+Now, since the basic protocol of the web, HTTP, is stateless, you
+need to somehow remember what state the tree is in every time you
+look at a page.  To do this, Zope stores the state of the tree in
+a *cookie*.  Because this tree state is stored in a cookie, only
+one tree can appear on a web page at a time, otherwise they will
+confusingly use the same cookie.
+
+You can tailor the behavior of the *tree* tag quite a bit with *tree*
+tag attributes and special variables. Here is a sampling of *tree*
+tag attributes.
+
+branches
+  The name of the method used to find sub-objects. This
+  defaults to *tpValues*, which is a method defined by a number of
+  standard Zope objects.
+
+leaves
+  The name of a method used to display objects that do
+  not have sub-object branches.
+
+nowrap
+  Either 0 or 1. If 0, then branch text will wrap to fit in
+  available space, otherwise, text may be truncated. The default
+  value is 0.
+
+sort
+  Sort branches before text insertion is performed. The
+  attribute value is the name of the attribute that items should be
+  sorted on.
+
+assume_children
+  Either 0 or 1. If 1, then all objects are
+  assumed to have sub-objects, and will therefore always have a
+  plus sign in front of them when they are collapsed. Only when an
+  item is expanded will sub-objects be looked for. This could be a
+  good option when the retrieval of sub-objects is a costly
+  process.  The defalt value is 0.
+
+single
+  Either 0 or 1. If 1, then only one branch of the tree can
+  be expanded. Any expanded branches will collapse when a new branch
+  is expanded.  The default value is 0.
+
+skip_unauthorized
+  Either 0 or 1. If 1, then no errors will be
+  raised trying to display sub-objects for which the user does not
+  have sufficient access. The protected sub-objects are not
+  displayed.  The default value is 0.
+
+Suppose you want to use the *tree* tag to create a dynamic site
+map. You don't want every page to show up in the site map. Let's
+say that you put a property on folders and documents that you want
+to show up in the site map.
+
+Let's first define a Script with the id of *publicObjects*
+that returns public objects::
+
+  ## Script (Python) "publicObjects"
+  ##
+  """
+  Returns sub-folders and DTML documents that have a
+  true 'siteMap' property.
+  """
+  results=[]
+  for object in context.objectValues(['Folder', 'DTML Document']):
+      if object.hasProperty('siteMap') and object.siteMap:
+          results.append(object)
+  return results
+
+Now we can create a DTML Method that uses the *tree* tag and our
+Scripts to draw a site map::
+
+  <dtml-var standard_html_header>
+
+  <h1>Site Map</h1>
+
+  <p><a href="&dtml-URL0;?expand_all=1">Expand All</a> |
+     <a href="&dtml-URL0;?collapse_all=1">Collapse All</a>
+  </p>
+
+  <dtml-tree branches="publicObjects" skip_unauthorized="1">
+    <a href="&dtml-absolute_url;"><dtml-var title_or_id></a>
+  </dtml-tree>
+
+  <dtml-var standard_html_footer>
+
+This DTML Method draws a link to all public resources and displays
+them in a tree. Here's what the resulting site map looks like.
+
+.. figure:: Figures/7-6.png
+
+   Dynamic site map using the tree tag
+
+For a summary of the *tree* tag arguments and special variables see
+Appendix A.
+
+The *Return* Tag
+----------------
+
+In general DTML creates textual output. You can however, make DTML
+return other values besides text. Using the *return* tag you can
+make a DTML Method return an arbitrary value just like a Python or
+Perl-based Script.
+
+Here's an example::
+
+  <p>This text is ignored.</p>
+
+  <dtml-return expr="42">
+
+This DTML Method returns the number 42.
+
+Another upshot of using the *return* tag is that DTML execution
+will stop after the *return* tag.
+
+If you find yourself using the *return* tag, you almost certainly
+should be using a Script instead. The *return* tag was developed
+before Scripts, and is largely useless now that you can easily
+write scripts in Python and Perl.
+
+The *Sendmail* Tag
+------------------
+
+The *sendmail* tag formats and sends a mail messages. You can use
+the *sendmail* tag to connect to an existing Mail Host, or you can
+manually specify your SMTP host.
+
+Here's an example of how to send an email message with the
+*sendmail* tag::
+
+  <dtml-sendmail>
+  To: <dtml-var recipient>
+  From: <dtml-var sender>
+  Subject: Make Money Fast!!!!
+
+  Take advantage of our exciting offer now! Using our exclusive method
+  you can build unimaginable wealth very quickly. Act now!
+  </dtml-sendmail>
+
+Notice that there is an extra blank line separating the mail
+headers from the body of the message.
+
+A common use of the *sendmail* tag is to send an email message
+generated by a feedback form. The *sendmail* tag can contain any
+DTML tags you wish, so it's easy to tailor your message with form
+data.
+
+The *Mime* Tag
+--------------
+
+The *mime* tag allows you to format data using MIME (Multipurpose
+Internet Mail Extensions). MIME is an Internet standard for
+encoding data in email message. Using the *mime* tag you can use
+Zope to send emails with attachments.
+
+Suppose you'd like to upload your resume to Zope and then have Zope
+email this file to a list of potential employers.
+
+Here's the upload form::
+
+  <dtml-var standard_html_header>
+
+  <p>Send you resume to potential employers</p>
+
+  <form method=post action="sendresume" ENCTYPE="multipart/form-data">
+  <p>Resume file: <input type="file" name="resume_file"></p>
+  <p>Send to:</p>
+  <p>
+  <input type="checkbox" name="send_to:list" value="jobs at yahoo.com">
+    Yahoo<br>
+
+  <input type="checkbox" name="send_to:list" value="jobs at microsoft.com">
+    Microsoft<br>
+
+  <input type="checkbox" name="send_to:list" value="jobs at mcdonalds.com">
+    McDonalds</p>
+
+  <input type=submit value="Send Resume">
+  </form>
+
+  <dtml-var standard_html_footer>
+
+Note:  The text *:list* added to the name of the input fields directs 
+Zope to treat the received information as a list type. For example if 
+the first two checkboxes were selected in the above upload form, the 
+REQUEST variable send_to would have the value [jobs at yahoo.com, jobs at microsoft.com]
+
+Create another DTML Method called *sendresume* to process the form
+and send the resume file::
+
+  <dtml-var standard_html_header>
+
+  <dtml-if send_to>
+
+    <dtml-in send_to> 
+
+      <dtml-sendmail smtphost="my.mailserver.com">
+      To: <dtml-var sequence-item>
+      Subject: Resume
+      <dtml-mime type=text/plain encode=7bit>
+
+      Hi, please take a look at my resume.
+
+      <dtml-boundary type=application/octet-stream disposition=attachment 
+      encode=base64><dtml-var expr="resume_file.read()"></dtml-mime>
+      </dtml-sendmail>
+
+    </dtml-in>
+
+    <p>Your resume was sent.</p>
+
+  <dtml-else>
+
+    <p>You didn't select any recipients.</p>
+
+  </dtml-if>
+
+  <dtml-var standard_html_footer>    
+
+This method iterates over the *sendto* variable and sends one
+email for each item.
+
+Notice that there is no blank line between the 'To:' header and
+the starting *mime* tag.  If a blank line is inserted between them
+then the message will not be interpreted as a *multipart* message
+by the receiving mail reader.
+
+Also notice that there is no newline between the *boundary* tag
+and the *var* tag, or the end of the *var* tag and the closing
+*mime* tag.  This is important, if you break the tags up with
+newlines then they will be encoded and included in the MIME part,
+which is probably not what you're after.
+
+As per the MIME spec, *mime* tags may be nested within *mime* tags
+arbitrarily.
+
+The *Unless* Tag
+----------------
+
+The *unless* tag executes a block of code unless the given condition is
+true. The *unless* tag is the opposite of the *if* tag.  The DTML
+code::
+
+  <dtml-if expr="not butter">
+    I can't believe it's not butter.
+  </dtml-if>
+
+is equivalent to::
+
+  <dtml-unless expr="butter">
+    I can't believe it's not butter.
+  </dtml-unless>
+
+What is the purpose of the *unless* tag? It is simply a convenience
+tag. The *unless* tag is more limited than the *if* tag, since it
+cannot contain an *else* or *elif* tag.
+
+Like the *if* tag, calling the *unless* tag by name does existence
+checking, so::
+
+  <dtml-unless the_easter_bunny>
+    The Easter Bunny does not exist or is not true.
+  </dtml-unless>
+
+Checks for the existence of *the_easter_bunny* as well as its
+truth. While this example only checks for the truth of
+*the_easter_bunny*::
+
+  <dtml-unless expr="the_easter_bunny">
+    The Easter Bunny is not true.
+  </dtml-unless>
+
+This example will raise an exception if *the_easter_bunny* does not
+exist.
+
+Anything that can be done by the *unless* tag can be done by the
+*if* tag.  Thus, its use is totally optional and a matter of
+style.
+
+Batch Processing With The *In* Tag
+----------------------------------
+
+Often you want to present a large list of information but only
+show it to the user one screen at a time.  For example, if a
+user queried your database and got 120 results, you will probably
+only want to show them to the user a small batch, say 10 or 20
+results per page.  Breaking up large lists into parts is called
+*batching*. Batching has a number of benefits.
+
+  o The user only needs to download a reasonably sized document
+  rather than a potentially huge document. This makes pages load
+  faster since they are smaller.
+
+  o Because smaller batches of results are being used, often less
+  memory is consumed by Zope.
+
+  o *Next* and *Previous* navigation interfaces makes scanning
+  large batches relatively easy.
+
+The *in* tag provides several variables to facilitate batch
+processing.  Let's look at a complete example that shows how to
+display 100 items in batches of 10 at a time::
+
+  <dtml-var standard_html_header>
+
+    <dtml-in expr="_.range(100)" size=10 start=query_start>
+
+      <dtml-if sequence-start>
+
+        <dtml-if previous-sequence>
+          <a href="<dtml-var URL><dtml-var sequence-query
+             >query_start=<dtml-var previous-sequence-start-number>">
+             (Previous <dtml-var previous-sequence-size> results)
+          </a>
+        </dtml-if>
+
+        <h1>These words are displayed at the top of a batch:</h1>
+        <ul>
+
+      </dtml-if>
+
+        <li>Iteration number: <dtml-var sequence-item></li>
+
+      <dtml-if sequence-end>
+
+        </ul>
+        <h4>These words are displayed at the bottom of a batch.</h4>
+
+        <dtml-if next-sequence>
+           <a href="<dtml-var URL><dtml-var sequence-query
+              >query_start=<dtml-var
+              next-sequence-start-number>">
+           (Next <dtml-var next-sequence-size> results)
+           </a>
+
+        </dtml-if>
+
+      </dtml-if>
+
+    </dtml-in>
+
+  <dtml-var standard_html_footer>
+
+Let's take a look at the DTML to get an idea of what's going
+on. First we have an *in* tag that iterates over 100 numbers that
+are generated by the *range* utility function. The *size*
+attribute tells the *in* tag to display only 10 items at a
+time. The *start* attribute tells the *in* tag which item number
+to display first.
+
+Inside the *in* tag there are two main *if* tags. The first one
+tests special variable 'sequence-start'. This variable is only
+true on the first pass through the in block. So the contents of
+this if tag will only be executed once at the beginning of the
+loop. The second *if* tag tests for the special variable
+'sequence-end'. This variable is only true on the last pass
+through the *in* tag. So the second *if* block will only be
+executed once at the end.  The paragraph between the *if* tags is
+executed each time through the loop.
+
+Inside each *if* tag there is another *if* tag that check for the
+special variables 'previous-sequence' and 'next-sequence'. The
+variables are true when the current batch has previous or further
+batches respectively. In other words 'previous-sequence' is true
+for all batches except the first, and 'next-sequence' is true for
+all batches except the last. So the DTML tests to see if there are
+additional batches available, and if so it draws navigation links.
+
+The batch navigation consists of links back to the document with a
+*query_start* variable set which indicates where the *in* tag should
+start when displaying the batch. To better get a feel for how this
+works, click the previous and next links a few times and watch how
+the URLs for the navigation links change.
+
+Finally some statistics about the previous and next batches are
+displayed using the 'next-sequence-size' and
+'previous-sequence-size' special variables.  All of this ends up
+generating the following HTML code::
+
+  <html>
+  <head><title>Zope</title>
+  </head>
+  <body bgcolor="#FFFFFF">
+
+    <h1>These words are displayed at the top of a batch:</h1>
+    <ul>
+      <li>Iteration number: 0</li>
+      <li>Iteration number: 1</li>
+      <li>Iteration number: 2</li>
+      <li>Iteration number: 3</li>
+      <li>Iteration number: 4</li>
+      <li>Iteration number: 5</li>
+      <li>Iteration number: 6</li>
+      <li>Iteration number: 7</li>
+      <li>Iteration number: 8</li>
+      <li>Iteration number: 9</li>
+    </ul>
+    <h4>These words are displayed at the bottom of a batch.</h4>
+
+       <a href="http://pdx:8090/batch?query_start=11">
+         (Next 10 results)
+       </a>
+
+  </body>
+  </html>
+
+Another example utilizes the commonly accepted navigation scheme
+of presenting the the user page numbers from which to select::
+
+   <dtml-in "_.range(1,101) "size=10 start=start>
+             <dtml-if sequence-start>
+               <p>Pages: 
+               <dtml-call "REQUEST.set('actual_page',1)">
+               <dtml-in previous-batches mapping>   
+                 <a href="<dtml-var URL><dtml-var sequence-query>start=<dtml-var "_['batch-start-index']+1">">
+                 <dtml-var sequence-number></a>&nbsp;
+                 <dtml-call "REQUEST.set('actual_page',_['sequence-number']+1)">     
+               </dtml-in>
+               <b><dtml-var "_['actual_page']"></b>  
+             </dtml-if>
+             <dtml-if sequence-end>
+               <dtml-in next-batches mapping>&nbsp;
+                  <a href="<dtml-var URL><dtml-var sequence-query>start=<dtml-var "_['batch-start-index']+1">">
+                  <dtml-var "_['sequence-number']+_['actual_page']"></a>
+                </dtml-in>
+             </dtml-if>
+    </dtml-in>
+
+    <dtml-in "_.range(1,101) "size=10 start=start>
+              <br><dtml-var sequence-item>
+    </dtml-in>      
+
+This quick and easy method to display pages is a nice navigational tool
+for larger batches.  It does present the drawback of having to utilize
+an additional *dtml-in* tag to iterate through the actual items, however.
+
+Batch processing can be complex. A good way to work with batches
+is to use the Searchable Interface object to create a batching
+search report for you. You can then modify the DTML to fit your
+needs.  This is explained more in the chapter entitled `Searching
+and Categorizing Content <SearchingZCatalog.html>`_.
+
+Other useful examples
+---------------------
+
+In this section are several useful examples of dtml code.  While
+many of these are most often better done in Python scripts, there
+are occasions when knowing how to accomplish this in dtml is
+worthwhile.
+
+Forwarding a REQUEST
+~~~~~~~~~~~~~~~~~~~~
+
+We have seen how to redirect the user's browser to another page
+with the help of the *call* directive.  However, there are times
+when a redirection is not necessary and a simple forwarding of a
+REQUEST from one dtml-method to another would suffice.  In this
+example, the dtml-method shown obtains a variable named *type*
+from the REQUEST object.  A lookup table is reference to obtain
+the name of the dtml-method to which the REQUEST should be
+forwarded.  The code below accomplishes this::
+
+  <dtml-let lookup="{'a' : 'form15', 'b' : 'form75', 'c' : 'form88'}">
+        <dtml-return "_[lookup[REQUEST.get('type')]]">
+  </dtml-let>
+
+This code looks up the name of the desired dtml-method in the
+lookup table (contained in the *let* statement) and in turn,
+looks up the name of this dtml-method in the current namespace.
+As long as the dtml-method exists, control will be passed to the
+method directly.  This example could be made more complete with
+the addition of exception handling which was discussed above.
+
+Sorting with the '<dtml-in>' tag
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are many times when sorting a result set is necessary.
+The *dtml-in* tag has some very interesting sort capabilities
+for both static and dynamic sorting.  In the example below, a
+ZSQL method is called that returns results from a log table.
+The columns returned are logTime, logType, and userName.  The
+dtml-method or document that contains this code will generate
+links back to itself to re-sort the query based upon certain
+search criteria::
+
+  <dtml-comment>
+
+  The sorting is accomplished by looking up a sort type
+  variable in the REQUEST that is comprised of two parts.  All
+  but the last character indicate the name of the column on
+  which to sort.  The last character of the sort type indicates
+  whether the sort should be ascending or descending.
+
+  </dtml-comment>
+
+  <table>
+    <tr>
+      <td>Time&nbsp;<a href="<dtml-var URL>?st=logTimea">A</a>&nbsp;<a href="<dtml-var URL>?st=logTimed">D</a></td>
+      <td>Type&nbsp;<a href="<dtml-var URL>?st=logTypea">A</a>&nbsp;<a href="<dtml-var URL>?st=logTyped">D</a></td>
+      <td>User&nbsp;<a href="<dtml-var URL>?st=userNamea">A</a>&nbsp;<a href="<dtml-var URL>?st=userNamed">D</a></td>
+    </tr>
+
+    <dtml-comment>The line below sets the default sort</dtml-comment>
+    <dtml-if "REQUEST.get('st')==None"><dtml-call "REQUEST.set('st', 'logTimed')"></dtml-if>
+    <dtml-in getLogData sort_expr="REQUEST.get('st')[0:-1]" reverse_expr="REQUEST.get('st')[-1]=='d'">
+      <tr>
+        <td><dtml-var logTime></td>
+        <td><dtml-var logType></td>
+        <td><dtml-var userName></td>
+      </tr>
+    </dtml-in>
+  </table>
+
+Calling a DTML object from a Python Script
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Although calling a DTML method from a Python script isn't really
+an advanced DTML technique, it deals with DTML, so it's being
+included here.  To call a DTML Method or DTML Document from a
+Python script, the following code is used::
+
+  dtmlMethodName = 'index_html'
+  return context[dtmlMethodName](container, container.REQUEST)
+
+It's as simple as that.  Often this is very useful if you wish
+to forward a request and significant processing is needed to
+determine which dtml object is the target.
+
+Explicit Lookups
+~~~~~~~~~~~~~~~~
+
+Occasionally it is useful to "turn off" acquisition when looking
+up an attribute.  In this example, you have a folder which
+contains sub-folders.  Each sub-folder contains Images.  The
+top-level folder, each subfolder, and each image contain a
+property named *desc*.
+
+If you were to query the Image for its *desc* property it would
+return the *desc* property of it's parent folder if the Image
+did not have the property.  This could cause confusion as the
+Image would appear to have the *desc* property when it really
+belonged to the parent folder.  In most cases, this behavior is
+desired.  However, in this case, the user would like to see
+which images have the *desc* property and which don't.  This is
+accomplished by utilizing *aq_explicit* in the call to the
+object in question.
+
+Given the following structure::
+
+ Folder 
+   |
+   |- Folder1 (desc='Folder one')
+   |- Folder2 (desc='Folder two')
+        |- Image1 (desc='Photo one')
+        |- Image2 
+        |- Image3 (desc='Photo three')
+
+when the second image is asked for its *desc* property it will
+return 'Folder two' based on acquisition rules::
+
+  <dtml-var "Image2.desc">
+
+However, utilizing *aq_explicit* will cause Zope to look only
+in the desired location for the property::
+
+  <dtml-var "Image2.aq_explicit.desc">
+
+This will, of course, raise an exception when the *desc*
+property does not exist.  A safer way to do this is::
+
+  <dtml-if "_.hasattr(Image2.aq_explicit, 'desc')">
+    <dtml-var "Image2.aq_explicit.desc">
+  <dtml-else>
+    No desc property.
+  </dtml-if>
+
+As you can see, this can be very useful.
+
+Conclusion
+----------
+
+DTML provides some very powerful functionality for designing web
+applications.  In this chapter, we looked at the more advanced
+DTML tags and some of their options.  A more complete reference
+can be found in Appendix A.
+
+The next chapter teaches you how to become a Page Template
+wizard. While DTML is a powerful tool, Page Templates provide a
+more elegant solution to HTML generation.

Copied: zope2docs/branches/baijum-reorganize/zope2book/AdvZPT.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/AdvZPT.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/AdvZPT.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/AdvZPT.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,1384 @@
+Advanced Page Templates
+=======================
+
+In the chapter entitled `Using Zope Page Templates <ZPT.html>`_ you
+learned the basic features of Page Templates. In this chapter
+you'll learn about advanced techniques including new types of
+expressions.
+
+Advanced TAL
+------------
+
+In this section we'll go over all TAL statements and their various
+options in depth.  This material is covered more concisely in
+`Appendix C: Zope Page Templates Reference <AppendixC.html>`_.
+
+In this chapter, the terms 'tag' and 'element' are used in the
+sense laid out by the `XHTML spec
+<http://www.w3.org/TR/2000/REC-xhtml1-20000126/#defs>`_.
+"&lt;p&gt;" is a *tag*, while the entire block
+"&lt;p&gt;stuff&lt;/p&gt;" from opening tag through the closing
+tag is an *element*.
+
+Advanced Content Insertion
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You've already seen how 'tal:content' and 'tal:replace' work in
+the chapter entitled `Using Zope Page Templates  <ZPT.html>`_. In
+this section you'll learn some advanced tricks for inserting
+content.
+
+Inserting Structure
+%%%%%%%%%%%%%%%%%%%
+
+Normally, the 'tal:replace' and 'tal:content' statements
+convert HTML tags and entities in the text that they insert
+into an "escaped" form that appears in the resulting document
+as plain text rather than HTML markup.
+For instance, the '<' character is "escaped" to '&amp;lt;'.
+If you want to insert text as part of the HTML structure of
+your document, avoiding this conversion , you need to
+precede the expression with the 'structure' keyword.
+
+This feature is useful when you are inserting a fragment of
+HTML or XML that is stored by an object or generated by
+another Zope object.  For instance, you may have news items
+that contain simple HTML markup such as bold and italic text
+when they are rendered, and you want to preserve this when
+inserting them into a "Top News" page.  In this case, you
+might write::
+
+  <p tal:repeat="newsItem context/topNews"
+     tal:content="structure newsItem">
+    A news item with<code>HTML</code> markup.
+  </p>
+
+This will insert the news items' HTML into a series of paragraphs. The built-in
+variable 'context' refers to the folder in which the template is rendered; See
+the "Expressions" section further below in this chapter for more information on
+'context'. In this case, we use 'context' as the starting point for finding the
+Zope object 'topNews', which is presumably a list of news items or a Script
+which fetches such a list.
+
+The 'structure' keyword prevents the text of each newsItem
+value from being escaped.  It doesn't matter whether the text
+actually contains any HTML markup, since 'structure' really
+means "leave this text alone".  This behavior
+is not the default because most of the text that you insert
+into a template will *not* contain HTML, but may contain
+characters that would interfere with the structure of your page.
+
+Dummy Elements
+%%%%%%%%%%%%%%
+
+You can include page elements that are visible in the template
+but not in generated text by using the built-in variable
+'nothing', like this::
+
+  <tr tal:replace="nothing">
+    <td>10213</td><td>Example Item</td><td>$15.34</td>
+  </tr>
+
+This can be useful for filling out parts of the page that will
+be populated with dynamic content.  For instance, a table that
+usually has ten rows will only have one row in the template.
+By adding nine dummy rows, the template's layout will look
+more like the final result.
+
+Default Content
+%%%%%%%%%%%%%%%
+
+You can leave the contents of an element alone by using the
+'default' expression with 'tal:content' or 'tal:replace'. For
+example::
+
+  <p tal:content="default">Spam</p>
+
+This renders to::
+
+  <p>Spam</p>
+
+Most often you will want to selectively include default
+content, rather than always including it. For example::
+
+  <p tal:content="python:context.getFood() or default">Spam</p>
+
+.. note:
+   
+   Python expressions are explained later in the chapter. If the
+   'getFood' method returns a true value then its result will be
+   inserted into the paragraph, otherwise it's Spam for dinner.
+
+Advanced Repetition
+~~~~~~~~~~~~~~~~~~~
+
+You've already seen most of what you can do with the
+'tal:repeat' statement in the chapter entitled `Using Zope Page
+Templates  <ZPT.html>`_. This section covers a few advanced features
+of the 'tal:repeat' statement.
+
+Repeat Variables
+%%%%%%%%%%%%%%%%
+
+One topic that bears more explanation are repeat
+variables. Repeat variables provide information about the
+current repetition. The following attributes are available on
+'repeat' variables:
+
+- *index* - repetition number, starting from zero.
+
+- *number* - repetition number, starting from one.
+
+- *even* - true for even-indexed repetitions (0, 2, 4, ...).
+
+- *odd* - true for odd-indexed repetitions (1, 3, 5, ...).
+
+- *start* - true for the starting repetition (index 0).
+
+- *end* - true for the ending, or final, repetition.
+
+- *length* - length of the sequence, which will be the total number
+  of repetitions.
+
+You can access the contents of a repeat variable using path
+expressions or Python expressions.  In path expressions, you
+write a three-part path consisting of the name 'repeat', the
+statement variable's name, and the name of the information you
+want, for example, 'repeat/item/start'.  In Python expressions,
+you use normal dictionary notation to get the repeat variable,
+then attribute access to get the information, for example,
+'python:repeat['item'].start'.  The reason that you can't
+simply write 'repeat/start' is that 'tal:repeat' statements
+can be nested, so you need to be able to specify which one you
+want information about.
+
+Repetition Tips
+%%%%%%%%%%%%%%%
+
+Here are a couple practical tips that you may find
+useful. Sometimes you'd like to repeat part of your template,
+but there is no naturally enclosing element.  In this case,
+you must add an enclosing element, but you want to prevent
+it from appearing in the rendered page. You can do this with
+the 'tal:omit-tag' statement::
+
+  <div tal:repeat="section context/getSections"
+       tal:omit-tag="">
+    <h4 tal:content="section/title">Title</h4>
+    <p tal:content="section/text">quotation</p>
+  </div>
+
+This is not just a matter of saving a few characters in the
+rendered output.  Including the 'div' tags in the output could
+affect the page layout, especially if it has stylesheets. We
+use the tal 'omit-tag' statement to disinclude the 'div' tag
+(and its pair closing tag) while leaving its contents
+unmolested.  The 'tal:omit-tag' statement is described in more
+detail later in this chapter.
+
+While it's been mentioned before, it's worth saying again: you
+can nest 'tal:repeat' statements inside each other. Each
+'tal:repeat' statement must have a different repeat variable
+name. Here's an example that shows a math times-table::
+
+  <table border="1">
+    <tr tal:repeat="x python:range(1, 13)">
+      <td tal:repeat="y python:range(1, 13)"
+          tal:content="python:'%d x %d = %d' % (x, y, x*y)">
+          X x Y = Z
+      </td>
+    </tr>
+  </table>
+
+This example uses Python expressions, which are covered later in this chapter.
+
+One useful feature that isn't supplied by 'tal:repeat' is sorting. If you want
+to sort a list you can either write your own sorting script (which is quite
+easy in Python) or you can use the 'sequence.sort' utility function. Here's an
+example of how to sort a list of objects by title::
+
+  <table tal:define="objects context/objectValues;
+                     sort_on python:(('title', 'nocase', 'asc'),);
+                     sorted_objects python:sequence.sort(objects, sort_on)">
+    <tr tal:repeat="item sorted_objects">
+      <td tal:content="item/title">title</td>
+    </tr>
+  </table>
+
+This example tries to make things clearer by defining the sort
+arguments outside the 'sort' function.  The 'sequence.sort'
+function takes a sequence and a description of how to sort
+it. In this example the description of how to sort the sequence
+is defined in the 'sort_on' variable.  See `Appendix B: API
+Reference <AppendixB.html>`_ for more information on the powerful
+'sequence.sort' function.
+
+Advanced Attribute Control
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You've already met the 'tal:attributes' statement. You can use
+it to dynamically replace tag attributes, for example, the
+'href' attribute on an 'a' element. You can replace more than
+one attribute on a tag by separating attributes with
+semicolons. For example, the code below will generate an
+"href" and a "class" attribute::
+
+  <a href="link"
+     tal:attributes="href context/getLink;
+                     class context/getClass">link</a>
+
+You can also define attributes with XML namespaces. For example::
+
+  <Description 
+      dc:Creator="creator name"
+      tal:attributes="dc:Creator context/owner/getUserName">
+    Description</Description>
+
+Simply put the XML namespace prefix before the attribute name
+and you can create attributes with XML namespaces.
+
+Defining Variables
+~~~~~~~~~~~~~~~~~~
+
+You can define your own variable using the 'tal:define'
+attribute. There are several reasons that you might want to do
+this. One reason is to avoid having to write long expressions
+repeatedly in a template. Another is to avoid having to call
+expensive methods repeatedly. You can define a variable once
+within an element on a tag and then use it many times within
+elements which are enclosed by this tag. For example, here's a
+list that defines a variable and later tests it and repeats over
+it::
+
+  <ul tal:define="items container/objectIds"
+      tal:condition="items">
+    <li tal:repeat="item items">
+      <p tal:content="item">id</p>
+    </li>
+  </ul>
+
+The 'tal:define' statement creates the variable 'items', which
+you can use anywhere in the 'ul' element.  Notice also how you
+can have two TAL statements on the same 'ul' tag.  See the
+section "Interactions Between TAL Statements" later in this
+chapter for more information about using more than one statement
+on a tag.  In this case the first statement assigns the variable
+'items' and the second uses 'items' in a condition to see
+whether it is false (in this case, an empty sequence) or
+true. If the 'items' variable is false, then the 'ul' element is not
+shown.
+
+Now, suppose that instead of simply removing the list when there
+are no items, you want to show a message.  To do this, place the
+following before the list::
+
+  <h4 tal:condition="not:container/objectIds">
+    There Are No Items
+  </h4>
+
+The expression, 'not:container/objectIds' is true when
+'container/objectIds' is false, and vice versa. See the section,
+"Not Expressions" later in this chapter for more information.
+
+You can't use your 'items' variable here, because it isn't defined yet. If you
+move the definition of 'items' to the 'h4' element, then you can't use it in
+the 'ul' element any more, because it becomes a *local* variable of the 'h4'
+element. To have it available on both tags, you can place the definition on
+some element that encloses both the 'h4' and the 'ul' for example the 'body'.
+
+You can define more than one variable using 'tal:define' by separating them
+with semicolons. For example::
+
+  <p tal:define="ids container/objectIds; 
+                 title container/title">
+
+You can define as many variables as you wish. Each variable can
+have its own global or local scope. You can also refer to
+earlier defined variables in later definitions. For example::
+
+  <p tal:define="title template/title;
+                 untitled not:title;
+                 tlen python:len(title);">
+
+With judicious use of 'tal:define' you can improve the efficiency and
+readability of your templates.
+
+Omitting Tags
+~~~~~~~~~~~~~
+
+You can remove tags with the 'tal:omit-tag' statement. You will
+seldom need to use this TAL statement, but occasionally it's
+useful. The omit-tag attribute removes opening and closing tags,
+but does not affect the contents of the element. For example::
+
+  <b tal:omit-tag=""><i>this</i> stays</b>
+
+Renders to::
+
+  <i>this</i> stays
+
+At this level of usage, 'tal:omit-tag' operates almost like
+'tal:replace="default"'. However, 'tal:omit-tag' can also be
+used with a true/false expression, in which case it only removes
+the tags if the expression is true. For example::
+
+  Friends: <span tal:repeat="friend friends">
+    <b tal:omit-tag="not:friend/best"
+       tal:content="friend/name">Fred</b>
+  </span>
+
+This will produce a list of friends, with our "best" friend's
+name in bold.
+
+Error Handling
+~~~~~~~~~~~~~~
+
+If an error occurs in your page template, you can catch that
+error and show a useful error message to your user.  For
+example, suppose your template defines a
+variable using form data::
+
+  ...
+  <span tal:define="prefs request/form/prefs"
+        tal:omit-tag="" />
+  ...
+
+If Zope encounters a problem, like not being able to find the
+'prefs' variable in the form data, the entire page will break;
+you'll get an error page instead. Happily, you can avoid this
+kind of thing with limited error handling using the
+'tal:on-error' statement::
+
+  ...
+  <span tal:define="prefs context/scriptToGetPreferences"
+        tal:omit-tag=""
+        tal:on-error="string:An error occurred">
+  ...
+
+When an error is raised while rendering a template, Zope looks
+for a 'tal:on-error' statement to handle the error. It first
+looks in the current element, then on its enclosing element, and so on
+until it reaches the top-level element. When it finds an error
+handler, it replaces the contents of that element with the error
+handling expression. In this case, the 'span' element will contain
+an error message.
+
+Typically you'll define an error handler on an element that encloses
+a logical page element, for example a table. If an error crops
+up drawing the table, then the error handler can simply omit the
+table from the page, or else replace it with an error message of
+some sort.
+
+For more flexible error handling you can call a script. For
+example::
+
+  <div tal:on-error="structure context/handleError">
+  ...
+  </div>
+
+Any error that occurs inside the 'div' will call the
+'handleError' script. Note that the 'structure' option allows
+the script to return HTML. Your error handling script can
+examine the error and take various actions depending on the
+error. Your script gets access to the error through the 'error'
+variable in the namespace. For example::
+
+  ## Script (Python) "handleError"
+  ##bind namespace=_
+  ##
+  error=_['error']
+  if error.type==ZeroDivisionError:
+      return "<p>Can't divide by zero.</p>"
+  else:
+      return """<p>An error occurred.</p>
+                <p>Error type: %s</p>
+                <p>Error value: %s</p>""" % (error.type,
+                                             error.value)
+
+Your error handling script can take all kinds of actions, for
+example, it might log the error by sending email.
+
+The 'tal:on-error' statement is not meant for general purpose
+exception handling. For example, you shouldn't validate form
+input with it. You should use a script for that, since scripts
+allow you to do powerful exception handling. The 'tal:on-error'
+statement is for dealing with unusual problems that can occur
+when rendering templates.
+
+Interactions Between TAL Statements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When there is only one TAL statement per element, the order in
+which they are executed is simple. Starting with the root
+element, each element's statements are executed, then each of
+its child elements are visited, in order, and their statements
+are executed, and so on.
+
+However, it's possible to have more than one TAL statement on
+the same element. Any combination of statements may appear on
+the same element, except that the 'tal:content' and
+'tal:replace' statements may not appear together.
+
+When an element has multiple statements, they are executed in
+this order:
+
+1. define
+
+2. condition
+
+3. repeat
+
+4. content or replace
+
+5. attributes
+
+6. omit-tag
+
+Since the 'tal:on-error' statement is only invoked when an error
+occurs, it does not appear in the list.
+
+The reasoning behind this ordering goes like this: you often
+want to set up variables for use in other statements, so define
+comes first. The very next thing to do is decide whether this
+element will be included at all, so condition is next; since the
+condition may depend on variables you just set, it comes after
+define. It is valuable to be able to replace various parts of an
+element with different values on each iteration of a repeat, so
+repeat comes before content, replace and attributes. Content and
+replace can't both be used on the same element so they occur at
+the same place. Omit-tag comes last since no other statements are
+likely to depend on it and since it should come after define and
+repeat.
+
+Here's an example element that includes several TAL 
+statements::
+
+  <p tal:define="x /root/a/long/path/x | nothing"
+     tal:condition="x"
+     tal:content="x/txt"
+     tal:attributes="class x/class">Ex Text</p>
+
+Notice how the 'tal:define' statement is executed first, and the
+other statements rely on its results.
+
+There are three limits you should be aware of when combining TAL
+statements on elements:
+
+1. Only one of each kind of statement can be used on a single
+   tag.  Since HTML does not allow multiple attributes with the
+   same name. For example, you can't have two 'tal:define' on the
+   same tag.
+
+2. Both of 'tal:content' and 'tal:replace' cannot be used on
+   the same tag, since their functions conflict.
+
+3. The order in which you write TAL attributes on a tag does
+   not affect the order in which they execute.  No matter how
+   you arrange them, the TAL statements on a tag always execute
+   in the fixed order described earlier.
+
+If you want to override the ordering of TAL statements, you must
+do so by enclosing the element in another element and placing
+some of the statements on this new element. For example suppose
+you want to loop over a series of items but skip some. Here's an
+attempt to write a template that loops over the numbers zero to
+nine and skips three::
+
+  <!-- broken template -->
+  <ul>
+    <li tal:repeat="n python:range(10)"
+        tal:condition="python:n != 3"
+        tal:content="n"> 
+      1
+    </li>
+  </ul>
+
+This template doesn't work due to TAL statement execution order.
+Despite the order in which they are written, the condition is
+always tested before the repeat is executed. This results in a
+situation in which the 'n' variable is not defined until after
+it is tested, which ultimately causes an error when you attempt
+to test or otherwise view the template. Here's a way around this
+problem::
+
+  <ul>
+    <div tal:repeat="n python:range(10)"
+         tal:omit-tag="">
+      <li tal:condition="python:n != 3"
+          tal:content="n"> 
+        1
+      </li>
+    </div>
+  </ul>
+
+This template solves the problem by defining the 'n' variable on
+an enclosing 'div' element. Notice that the 'div' tag will not
+appear in the output due to its 'tal:omit-tag' statement.
+
+Although 'span' and 'div' are natural choices for this in HTML,
+there is, in general, no equivalent natural element in XML.  In
+this case, you can use TAL's namespace in a new way: while TAL
+does not define any tags, it doesn't prohibit any either.  You
+can make up any tag name you like within the TAL namespace, and
+use it to make an element, like so::
+
+  <tal:series define="items context/getItems">
+    <tal:items repeat="item items">
+    <tal:parts repeat="part item">
+      <p tal:content="part">Part</p>
+    </tal:parts>
+    </tal:items>
+    <p tal:condition="not:items">No parts!</p>
+  </tal:series>
+
+The 'tal:series', 'tal:items', and 'tal:parts' tags in this
+example should be acceptable to tools that handle XML namespaces
+properly, and to many HTML tools.  This method has two
+additional advantages over a 'div'.  First, TAL tags are omitted
+just like TAL attributes, so no 'tal:omit-tag' is necessary.
+Second, TAL attributes in these tags don't require their
+own 'tal:' prefix, since they inherit the namespace of the tag.
+The METAL namespace can be used in exactly the same fashion.
+
+Form Processing
+~~~~~~~~~~~~~~~
+
+With Zope Page Templates you can use the form/action/response pattern. The form
+and response should be Page Templates and the action should be a script. The
+form template gathers the input and calls the action script. The action script
+should process the input and return a response template.
+
+For example here's a part of a form template::
+
+  ...
+  <form action="action">
+    <input type="text" name="name">
+    <input type="text" name="age:int">
+    <input type="submit">
+  </form>
+  ...
+
+This form could be processed by this script::
+
+  ## Script (Python) "action"
+  ##parameters=name, age
+  ##
+  container.addPerson(name, age)
+  return container.responseTemplate()
+
+This script calls a method to process the input and then
+returns another template, the response. You can render a Page
+Template from Python by calling it. The response template
+typically contains an acknowledgment that the form has been
+correctly processed.
+
+The action script can do all kinds of things. It can validate
+input, handle errors, send email, or whatever it needs to do to
+"get the job done".  Here's a sketch of how to validate input
+with a script::
+
+  ## Script (Python) "action"
+  ##
+  if not context.validateData(request):
+      # if there's a problem return the form page template
+      # along with an error message
+      return context.formTemplate(error_message='Invalid data')
+
+  # otherwise return the thanks page
+  return context.responseTemplate()
+
+This script validates the form input and returns the form
+template with an error message if there's a problem. The
+Script's 'context' variable is equivalent to 'context' in
+TALES. You can pass Page Templates extra information with
+keyword arguments. The keyword arguments are available to the
+template via the 'options' built-in variable. So the form
+template in this example might include a section like this::
+
+  <span tal:condition="options/error_message | nothing">
+  Error: <b tal:content="options/error_message">
+    Error message goes here.
+  </b></span>
+
+This example shows how you can display an error message that is
+passed to the template via keyword arguments. Notice the use of
+'| nothing' to handle the case where no 'error_message' argument
+has been passed to the template.
+
+Depending on your application you may choose to redirect the
+user to a response Page Template instead of returning it
+directly. This results in twice as much network activity, but
+might be useful because it changes the URL displayed in the
+user's browser to the URL of the Page Template, rather than that
+of the action script.
+
+If you need to set up a quick-and-dirty form, you can always
+create a version of the form-action pair using Page Templates
+alone. You should only do this when you don't care about error
+handling and when the response will always be the same, no
+matter what the user submits. You can use one of any number of
+hacks to call an input processing method without inserting its
+results. For example::
+
+  <span tal:define="unused context/processInputs" 
+        tal:omit-tag=""/>
+
+This sample calls the 'processInputs' method and assigns the
+result to the 'unused' variable.
+
+Expressions
+-----------
+
+You've already encountered Page Template expressions. Expressions
+provide values to template statements. For example, in the TAL
+statement '<td tal:content="request/form/age">Age</td>', the
+expression of the statement is 'request/form/age'.
+'request/form/age' is an example of a *path expression*.  Path
+expressions describe objects by giving them paths such as
+'request/form/age', or 'user/getUserName'. Expressions only work
+in the context of a TAL statement; they do not work in "normal"
+HTML inserted in your page templates.  In this section you'll
+learn about all the different types of expressions, and variables.
+
+Built-in Page Template Variables
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Variables are names that you can use in expressions. You have
+already seen some examples of the built-in variables such as
+'template', 'user', 'repeat', and 'request'.  Here is the
+complete list of the other built-in variables and their uses.
+Note that these variables are different than the built-in
+variables that you would use in a Script (Python), they are only
+effective for Page Templates:
+
+'nothing'
+  A false value, similar to a blank string, that you
+  can use in 'tal:replace' or 'tal:content' to erase an element or
+  its contents.  If you set an attribute to 'nothing', the
+  attribute is removed from the tag (or not inserted).  A blank
+  string, on the other hand, would insert the tag with an empty
+  value, as in 'alt=""'.
+
+'default'
+  A special value that doesn't change anything when
+  used in 'tal:replace', 'tal:content', or 'tal:attributes'.  It
+  leaves the template text in place.
+
+'options'
+  The keyword arguments, if any, that were passed to
+  the template. When a template is rendered from the web, no
+  options are present. Options are only available when a template
+  is called from Python or by similarly complex means.  For
+  example, when the template 't' is called by the Python expression
+  't(foo=1)', the path 'options/foo' equals '1'.
+
+'attrs'
+  A dictionary of attributes of the current tag in the
+  template.  The keys are the attributes names, and the values are
+  the original values of the attributes in the template. This
+  variable is rarely needed.
+
+'root'
+  The root Zope object.  Use this to get Zope objects
+  from fixed locations, no matter where your template is placed or
+  called.
+
+'context'
+  The object on which the template is being called.
+  This is often the same as the *container*, but can be different
+  if you are using acquisition.  Use this to get Zope objects that
+  you expect to find in different places depending on how the
+  template is called.
+
+'container'
+  The container (usually a Folder) in which the
+  template is kept.  Use this to get Zope objects from locations
+  relative to the template's permanent home. The 'container' and
+  'context' variables refer to the same object when a template is
+  called from its normal location. However, when a template is
+  applied to another object (for example, a ZSQL Method) the
+  'container' and 'context' will not refer to the same object.
+
+'modules'
+  The collection of Python modules available to
+  templates.  See the section on writing Python expressions.
+
+You'll find examples of how to use these variables throughout
+this chapter.
+
+String Expressions
+~~~~~~~~~~~~~~~~~~
+
+String expressions allow you to easily mix path expressions with
+text.  All of the text after the leading 'string:' is taken and
+searched for path expressions.  Each path expression must be
+preceded by a dollar sign ('$').  Here are some examples::
+
+  "string:Just text. There's no path here."
+  "string:copyright $year by Fred Flintstone."
+
+If the path expression has more than one part (if it contains a
+slash), or needs to be separated from the text that follows it,
+it must be surrounded by braces ('{}'). For example::
+
+  "string:Three ${vegetable}s, please."
+  "string:Your name is ${user/getUserName}!"
+
+Notice how in the example above, you need to surround the
+'vegetable' path with braces so that Zope doesn't mistake it for
+'vegetables'.
+
+Since the text is inside of an attribute value, you can only
+include a double quote by using the entity syntax '&quot;'.
+Since dollar signs are used to signal path expressions, a
+literal dollar sign must be written as two dollar signs
+('$$'). For example::
+
+  "string:Please pay $$$dollars_owed"
+  "string:She said, &quot;Hello world.&quot;"
+
+Some complex string formatting operations (such as search and
+replace or changing capitalization) can't easily be done with
+string expressions. For these cases, you should use Python
+expressions or Scripts.
+
+Path Expressions
+~~~~~~~~~~~~~~~~
+
+Path expressions refer to objects with a path that resembles a
+URL path. A path describes a traversal from object to
+object. All paths begin with a known object (such as a built-in
+variable, a repeat variable, or a user defined variable) and
+depart from there to the desired object. Here are some example
+paths expressions::
+
+  template/title
+  container/files/objectValues
+  user/getUserName
+  container/master.html/macros/header
+  request/form/address
+  root/standard_look_and_feel.html
+
+With path expressions you can traverse from an object to its
+sub-objects including properties and methods. You can also use
+acquisition in path expressions. See the section entitled
+"Calling Scripts from the Web" in the chapter entitled `Advanced
+Zope Scripting <ScriptingZope.html>`_ for more information on
+acquisition and path traversal.
+
+Zope restricts object traversal in path expressions in the same
+way that it restricts object access via URLs. You must have
+adequate permissions to access an object in order to refer to it
+with a path expression. See the chapter entitled `Users and
+Security <Security.html>`_ for more information about object access
+controls.
+
+Alternate Paths
+%%%%%%%%%%%%%%%
+
+The path 'template/title' is guaranteed to exist every time
+the template is used, although it may be a blank string.  Some
+paths, such as 'request/form/x', may not exist during some
+renderings of the template.  This normally causes an error
+when Zope evaluates the path expression.
+
+When a path doesn't exist, you may have a fall-back path or
+value that you would like to use instead.  For instance, if
+'request/form/x' doesn't exist, you might want to use 'context/x'
+instead.  You can do this by listing the paths in order of
+preference, separated by vertical bar characters ('|')::
+
+  <h4 tal:content="request/form/x | context/x">Header</h4>
+
+Two variables that are very useful as the last path in a list
+of alternates are 'nothing' and 'default'.  For example,
+'default' tells 'tal:content' to leave the dummy
+content. Different TAL statements interpret 'default' and
+'nothing' differently. See `Appendix C: Zope Page Templates
+Reference`_ for more information.
+
+You can also use a non-path expression as the final part in an
+alternate-path expression. For example::
+
+  <p tal:content="request/form/age|python:18">age</p>
+
+In this example, if the 'request/form/age' path doesn't exist,
+then the value is the number 18. This form allows you to
+specify default values to use which can't be expressed as
+paths. Note, you can only use a non-path expression as the
+last alternative.
+
+You can also test the existence of a path directly with the
+*exists* expression type prefix. See the section "Exists
+Expressions" below for more information on exists expressions.
+
+Not Expressions
+~~~~~~~~~~~~~~~
+
+`Not` expressions let you negate the value of other
+expressions. For example::
+
+  <p tal:condition="not:context/objectIds">
+    There are no contained objects.
+  </p>
+
+Not expressions return true when the expression they are applied
+to is false, and vice versa. In Zope, zero, empty strings, empty
+sequences, nothing, and None are considered false, while
+everything else is true.  Non-existent paths are neither true
+nor false, and applying a 'not:' to such a path will fail.
+
+There isn't much reason to use not expressions with Python
+expressions since you can use the Python 'not' keyword instead.
+
+Nocall Expressions
+~~~~~~~~~~~~~~~~~~
+
+An ordinary path expression tries to render the object
+that it fetches.  This means that if the object is a function,
+Script, Method, or some other kind of executable thing, then
+the expression will evaluate to the result of calling the object.
+This is usually what you want, but not always.  For example,
+if you want to put a page template into a variable so that
+you can refer to its properties, you can't use a normal path
+expression because it will render the template into a string.
+
+If you put the 'nocall:' expression type prefix in front of a
+path, it prevents the rendering and simply gives you the
+object.  For example::
+
+  <span tal:define="page nocall:context/aPage"
+        tal:content="string:${page/getId}: ${page/title}">
+  Id: Title</span>
+
+This expression type is also valuable when you want to define
+a variable to hold a function or class from a module, for use
+in a Python expression.
+
+Nocall expressions can also be used on functions, rather than
+objects::
+
+  <p tal:define="join nocall:modules/string/join">
+
+This expression defines the 'join' variable as a function
+('string.join'), rather than the result of calling a function.
+
+Exists Expressions
+~~~~~~~~~~~~~~~~~~
+
+An exists expression is true if its path exists, and otherwise
+is false.  For example here's one way to display an error
+message only if it is passed in the request::
+
+  <h4 tal:define="err request/form/errmsg | nothing"
+      tal:condition="err" 
+      tal:content="err">Error!</h4>
+
+You can do the same thing more easily with an exists
+expression::
+
+  <h4 tal:condition="exists:request/form/errmsg"
+      tal:content="request/form/errmsg">Error!</h4>
+
+You can combine exists expressions with not expressions, for
+example::
+
+  <p tal:condition="not:exists:request/form/number">Please enter
+  a number between 0 and 5</p>
+
+Note that in this example you can't use the expression,
+"not:request/form/number", since that expression will be true if
+the 'number' variable exists and is zero.
+
+Python Expressions
+~~~~~~~~~~~~~~~~~~
+
+The Python programming language is a simple and expressive one.
+If you have never encountered it before, you should read one of
+the excellent tutorials or introductions available at the
+`Python website <http://www.python.org>`_.
+
+A Page Template Python expression can contain anything that the
+Python language considers an expression.  You can't use
+statements such as 'if' and 'while'. In addition, Zope imposes
+some security restrictions to keep you from accessing protected
+information, changing secured data, and creating problems such
+as infinite loops. See the chapter entitled `Advanced Zope
+Scripting <ScriptingZope.html>`_ for more information on Python
+security restrictions.
+
+Comparisons
+%%%%%%%%%%%
+
+One place where Python expressions are practically necessary
+is in 'tal:condition' statements.  You usually want to compare
+two strings or numbers, and there is no support in TAL to do
+this without Python expressions.  In Python expressions, you
+can use the comparison operators '<' (less than), '>' (greater
+than), '==' (equal to), and '!=' (not equal to).  You can also
+use the boolean operators 'and', 'not', and 'or'.  For
+example::
+
+  <p tal:repeat="widget widgets">
+    <span tal:condition="python:widget.type == 'gear'">
+    Gear #<span tal:replace="repeat/widget/number>1</span>:
+    <span tal:replace="widget/name">Name</span>
+    </span>
+  </p>
+
+This example loops over a collection of objects, printing
+information about widgets which are of type 'gear'.
+
+Sometimes you want to choose different values inside a single
+statement based on one or more conditions.  You can do this
+with the and and or operators, like this::
+
+  You <span tal:define="name user/getUserName"
+       tal:replace="python:name=='Anonymous User' and
+                           'need to log in' or default">
+        are logged in as
+        <span tal:replace="name">Name</span>
+      </span>
+
+If the user is 'Anonymous', then the 'span' element is
+replaced with the text 'need to log in'.  Otherwise, the
+default content is used, which is in this case 'are logged in
+as ...'.
+
+This operator combinaion works like an if/then/else statement.
+Here's another example of how you can use this pattern::
+
+  <tr tal:define="oddrow repeat/item/odd"
+      tal:attributes="class python:oddrow and 'oddclass' or 'evenclass'">
+
+This assigns 'oddclass' and 'evenclass' class attributes to
+alternate rows of the table, allowing them to be styled
+differently in HTML output, for example.
+
+Without this pattern you could also write two 'tr'
+elements with different conditions, one for even rows,
+and the other for odd rows.
+
+Using other Expression Types
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+You can use other expression types inside of a Python
+expression.  Each expression type has a corresponding function
+with the same name, including: 'path()', 'string()',
+'exists()', and 'nocall()'.  This allows you to write
+expressions such as::
+
+  "python:path('context/%s/thing' % foldername)"
+  "python:path(string('context/$foldername/thing'))"
+  "python:path('request/form/x') or default"
+
+The final example has a slightly different meaning than the
+path expression, "request/form/x | default", since it will use
+the default text if "request/form/x" doesn't exists *or* if it
+is false.
+
+Getting at Zope Objects
+%%%%%%%%%%%%%%%%%%%%%%%
+
+Much of the power of Zope involves tying together specialized
+objects.  Your Page Templates can use Scripts, SQL Methods,
+Catalogs, and custom content objects.  In order to use these
+objects you have to know how to get access to them within Page
+Templates.
+
+Object properties are usually attributes, so you can get a
+template's title with the expression "template.title". Most
+Zope objects support acquisition, which allows you to get
+attributes from "parent" objects.  This means that the Python
+expression "context.Control_Panel" will acquire the Control Panel
+object from the root Folder.  Object methods are attributes,
+as in "context.objectIds" and "request.set".  Objects contained
+in a Folder can be accessed as attributes of the Folder, but
+since they often have Ids that are not valid Python
+identifiers, you can't use the normal notation.  For example,
+you cannot access the 'penguin.gif' object with the following
+Python expression::
+
+  "python:context.penguin.gif"
+
+Instead, you must write::
+
+  "python:getattr(context, 'penguin.gif')"
+
+since Python doesn't support attribute names with periods.
+
+Some objects, such as 'request', 'modules', and Zope Folders
+support Python item access, for example::
+
+  request['URL']
+  modules['math']
+  context['thing']
+
+When you use item access on a Folder, it doesn't try to
+acquire the name, so it will only succeed if there is actually
+an object with that Id contained in the Folder.
+
+As shown in previous chapters, path expressions allow you to
+ignore details of how you get from one object to the next.
+Zope tries attribute access, then item access.  You can
+write::
+
+  "context/images/penguin.gif"
+
+instead of::
+
+  "python:getattr(context.images, 'penguin.gif')"
+
+and::
+
+  "request/form/x" 
+
+instead of::
+
+  "python:request.form['x']"
+
+The trade-off is that path expressions don't allow you to
+specify those details.  For instance, if you have a form
+variable named "get", you must write::
+
+  "python:request.form['get']"
+
+since this path expression::
+
+  "request/form/get" 
+
+will evaluate to the "get" *method* of the form dictionary.
+
+If you prefer you can use path expressions inside Python
+expressions using the 'path()' function, as described above.
+
+Using Scripts
+%%%%%%%%%%%%%
+
+Script objects are often used to encapsulate business logic
+and complex data manipulation.  Any time that you find
+yourself writing lots of TAL statements with complicated
+expressions in them, you should consider whether you could do
+the work better in a Script. If you have trouble understanding your
+template statements and expressions, then it's better to
+simplify your Page Template and use Scripts for the complex
+stuff.
+
+Each Script has a list of parameters that it expects to be
+given when it is called.  If this list is empty, then you can
+use the Script by writing a path expression.  Otherwise, you
+will need to use a Python expression in order to supply the
+argument, like this::
+
+  "python:context.myscript(1, 2)"
+  "python:context.myscript('arg', foo=request.form['x'])"
+
+If you want to return more than one item of data from a Script
+to a Page Template, it is a good idea to return it in a
+dictionary.  That way, you can define a variable to hold all
+the data, and use path expressions to refer to each item.  For
+example, suppose the 'getPerson' script returns a dictionary
+with 'name' and 'age' keys::
+
+  <span tal:define="person context/getPerson"
+        tal:replace="string:${person/name} is ${person/age}">
+  Name is 30</span> years old.
+
+Of course, it's fine to return Zope objects and Python lists
+as well.
+
+Python Modules
+%%%%%%%%%%%%%%
+
+The Python language comes with a large number of modules,
+which provide a wide variety of capabilities to Python
+programs.  Each module is a collection of Python functions,
+data, and classes related to a single purpose, such as
+mathematical calculations or regular expressions.
+
+Several modules, including "math" and "string", are available
+in Python expressions by default.  For example, you can get
+the value of pi from the math module by writing
+"python:math.pi".  To access it from a path expression,
+however, you need to use the 'modules' variable,
+"modules/math/pi".
+
+The "string" module is hidden in Python expressions by the
+"string" expression type function, so you need to access it
+through the 'modules' variable.  You can do this directly in
+an expression in which you use it, or define a variable
+for it, like this::
+
+  tal:define="mstring modules/string"
+  tal:replace="python:mstring.join(slist, ':')"
+
+In practice you'll rarely need to do this since you can use
+string methods most of the time rather than having to rely on
+functions in the string module.
+
+Modules can be grouped into packages, which are simply a way
+of organizing and naming related modules.  For instance,
+Zope's Python-based Scripts are provided by a collection of
+modules in the "PythonScripts" subpackage of the Zope
+"Products" namespace package.  In particular, the "standard" module in
+this package provides a number of useful formatting functions. The full name
+of this module is "Products.PythonScripts.standard", so you could
+get access to it using either of the following statements::
+
+  tal:define="global pps modules/Products.PythonScripts.standard"
+  tal:define="global pps python:modules['Products.PythonScripts.standard']"
+
+Many Python modules cannot be accessed from Page Templates
+or Scripts unless you add Zope security assertions to
+them.  See the `Zope Developer's Guide's security
+chapter <http://www.zope.org/Documentation/Books/ZDG/current/Security.stx>`_
+for more information on making more Python modules available
+to your templates and scripts by using "ModuleSecurityInfo".
+
+Caching Templates
+-----------------
+
+While rendering Page Templates normally is quite fast, sometimes
+it's not fast enough. For frequently accessed pages, or pages that
+take a long time to render, you may want to trade some dynamic
+behavior for speed. Caching lets you do this. For more information
+on caching see the "Cache Manager" section of the chapter entitled
+`Zope Services <ZopeServices.html>`_.
+
+You can cache Page Templates using a cache manager in the same way
+that you cache other objects. To cache a Page Template, you must
+associate it with a cache manager. You can either do this by going
+to the *Cache* view of your Page Template and selecting the cache
+manager (there must be one in the acquisition path of the template
+for the *Cache* view to appear), or by going to the *Associate*
+view of your cache manager and locating your Page Template.
+
+Here's an example of how to cache a Page Template. First create a
+Python-based script name 'long.py' with these contents::
+
+  ## Script (Python) "long.py"
+  ##
+  for i in range(250):
+    for j in range(250):
+      for k in range(250):
+        pass
+  return 'Done'
+
+The purpose of this script is to take up a noticeable amount of
+execution time. Now create a Page Template that uses this script,
+for example::
+
+  <html>
+    <body>
+      <p tal:content="context/long.py">results</p>
+    </body>
+  </html>
+
+Now view this page. Notice how it takes a while to render. Now
+let's radically improve its rendering time with caching.  Create a
+Ram Cache Manager if you don't already have one. Make sure to
+create it within the same folder as your Page Template, or in a
+higher level. Now visit the *Cache* view of your Page
+Template. Choose the Ram Cache Manager you just created and click
+*Save Changes*.  Click the *Cache Settings* link to see how your
+Ram Cache Manager is configured.  By default, your cache stores
+objects for one hour (3600 seconds). You may want to adjust this
+number depending on your application. Now return to your Page
+Template and view it again. It should take a while for it to
+render. Now reload the page, and watch it render immediately. You
+can reload the page again and again, and it will always render
+immediately since the page is now cached.
+
+If you change your Page Template, then it will be removed from the
+cache. So the next time you view it, it will take a while to
+render. But after that it will render quickly since it will be
+cached again.
+
+Caching is a simple but very powerful technique for improving
+performance. You don't have to be a wizard to use caching, and it
+can provide great speed-ups. It's well worth your time to use
+caching for performance-critical applications.
+
+For more information on caching in the context of Zope, see the
+chapter entitled `Zope Services <ZopeServices.html>`_.
+
+Page Template Utilities
+-----------------------
+
+Zope Page Templates are powerful but simple.
+They don't give you a lot of convenience features for things
+like batching, drawing trees, sorting, etc. The creators of Page
+Templates wanted to keep them simple. To address these
+needs, Zope comes with utilities designed to enhance Page
+Templates.
+
+Batching Large Sets of Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When a user queries a database and gets hundreds of results, it's
+often better to show them several pages with only twenty results
+per page, rather than putting all the results on one
+page. Breaking up large lists into smaller lists is called
+*batching*.
+
+Page Templates support batching by using a special 'Batch'
+object that comes from the 'ZTUtils' utility module.  See
+`Appendix B: API Reference`_, for more information
+on the 'ZTUtils' Python module.
+
+Here's a simple example, showing how to create a 'Batch'
+object::
+
+  <ul tal:define="lots python:range(100);
+                  batch python:modules['ZTUtils'].Batch(lots, 
+                                                        size=10,
+                                                        start=0)">
+    <li tal:repeat="num batch"
+        tal:content="num">0
+    </li>
+  </ul>
+
+This example renders a list with 10 items (in this case, the
+numbers 0 through 9). The 'Batch' object chops a long list up
+into groups or batches. In this case it broke a one hundred item
+list up into batches of ten items.
+
+You can display a different batch of ten items by passing a
+different start number::
+
+  <ul tal:define="lots python:range(100);
+                  batch python:modules['ZTUtils'].Batch(lots, 
+                                                        size=10,
+                                                        start=13)">
+
+This batch starts with the fourteenth item and ends with the
+twenty third item. In other words, it displays the numbers 13
+through 22. It's important to notice that the batch 'start'
+argument is the *index* of the first item. Indexes count from
+zero, rather than from one. So index 13 points to the fourteenth
+item in the sequence. Python uses indexes to refer to list
+items. 
+
+Normally when you use batches you'll want to include navigation
+elements on the page to allow users to go from batch to batch.
+Here's a full-blow batching example that shows how to navigate
+between batches::
+
+  <html>
+    <head>
+      <title tal:content="template/title">The title</title>
+    </head>
+    <body tal:define="employees context/getEmployees;
+           start python:int(path('request/start | nothing') or 0);
+           batch python:modules['ZTUtils'].Batch(employees, 
+                                                 size=3, 
+                                                 start=start);
+           previous python:batch.previous;
+           next python:batch.next">
+
+    <p>
+      <a tal:condition="previous"
+         tal:attributes="href string:${request/URL0}?start:int=${previous/first}"
+         href="previous_url">previous</a>
+      <a tal:condition="next"
+         tal:attributes="href string:${request/URL0}?start:int=${next/first}"
+         href="next_url">next</a>
+    </p>
+
+    <ul tal:repeat="employee batch" >
+      <li>
+        <span tal:replace="employee/name">Bob Jones</span>
+        makes $<span tal:replace="employee/salary">100,000</span>
+        a year.
+      </li>
+    </ul>
+
+    </body>
+  </html>
+
+Define a Script (Python) with the name getEmployees in the same
+folder with the following body (no parameters are necessary)::
+
+  return [  {'name': 'Chris McDonough', 'salary':'5'},
+            {'name': 'Guido van Rossum', 'salary': '10'},
+            {'name': 'Casey Duncan', 'salary':'20' },
+            {'name': 'Andrew Sawyers', 'salary':'30' },
+            {'name': 'Evan Simpson', 'salary':'35' }, 
+            {'name': 'Stephanie Hand', 'salary':'40' }, ]
+
+This example iterates over batches of results from the
+'getEmployees' method. It draws a *previous* and a *next* link
+as necessary to allow you to page through all the results a
+batch at a time.  The batch size in this case is 3.
+
+Take a look at the 'tal:define' statement on the 'body'
+element. It defines a bunch of batching variables. The
+'employees' variable is a list of employee objects returned by
+the 'getEmployees' Script.  It is not very big now, but it could
+grow fairly large (especially if it were a call into a SQL
+Method of *real* employees). The second variable, 'start', is
+either set to the value of 'request/start' or to zero if there
+is no 'start' variable in the request.  The 'start' variable
+keeps track of where you are in the list of employees. The
+'batch' variable is a batch of ten items from the lists of
+employees. The batch starts at the location specified by the
+'start' variable. The 'previous' and 'next' variables refer to
+the previous and next batches (if any). Since all these
+variables are defined on the 'body' element, they are available
+to all elements inside the body.
+
+Next let's look at the navigation links. They create hyper links
+to browse previous and next batches. The 'tal:condition'
+statement first tests to see if there is a previous and next
+batch. If there is a previous or next batch, then the link is
+rendered, otherwise there is no link. The 'tal:attributes'
+statement creates a link to the previous and next batches. The
+link is simply the URL or the current page ('request/URL0')
+along with a query string indicating the start index of the
+batch. For example, if the current batch starts with index 10,
+then the previous batch will start with an index of 0. The
+'first' variable of a batch gives its starting index, so in this
+case, 'previous.start' would be 0.
+
+It's not important to fully understand the workings of this
+example. Simply copy it, or use a batching example created by
+the *Z Search Interface*. Later when you want to do more complex
+batching you can experiment by changing the example code. Don't
+forget to consult `Appendix B: API Reference`_ for
+more information on the 'ZTUtils' module and 'Batch' objects.
+
+Miscellaneous Utilities
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Zope provides a couple Python modules which may come in handy
+when using Page Templates. The 'string', 'math', and 'random'
+modules can be used in Python expressions for string formatting,
+math function, and pseudo-random number generation. These same
+modules are available in Python-based scripts.
+
+The 'Products.PythonScripts.standard' module is designed to
+provide utilities to Python-based scripts, but it's also useful
+for Page Templates. It includes various string and number
+formatting functions.
+
+As mentioned earlier in the chapter, the 'sequence' module
+provides a handy 'sort' function.
+
+Finally the 'AccessControl' module includes a function and a
+class which you'll need if you want to test access and to get
+the authenticated user.
+
+See `Appendix B: API Reference`_ for more
+information on these utilities.
+
+Conclusion
+----------
+
+This chapter covers some useful and some obscure nooks and
+crannies of Page Templates, and after reading it you may feel a
+bit overwhelmed. Don't worry, you don't need to know everything
+in this chapter to effectively use Page Templates. You should
+understand the different path types and macros, but you can come
+back to the rest of the material when you need it. The advanced
+features that you've learned about in this chapter are there for
+you if and when you need them.

Copied: zope2docs/branches/baijum-reorganize/zope2book/AppendixA.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/AppendixA.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/AppendixA.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/AppendixA.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,1655 @@
+##########################
+Appendix A: DTML Reference
+##########################
+
+DTML is the *Document Template Markup Language*, a handy presentation and
+templating language that comes with Zope. This Appendix is a reference to all
+of DTMLs markup tags and how they work.
+
+call: Call a method
+===================
+
+The 'call' tag lets you call a method without inserting the results into the
+DTML output.
+
+Syntax
+------
+
+'call' tag syntax::
+
+  <dtml-call Variable|expr="Expression">
+
+If the call tag uses a variable, the methods arguments are passed automatically
+by DTML just as with the 'var' tag. If the method is specified in a expression,
+then you must pass the arguments yourself.
+
+Examples
+--------
+
+Calling by variable name::
+
+  <dtml-call UpdateInfo>
+
+This calls the 'UpdateInfo' object automatically passing arguments.
+
+Calling by expression::
+
+  <dtml-call expr="RESPONSE.setHeader('content-type', 'text/plain')">
+
+See Also
+--------
+
+- var tag
+
+
+comment: Comments DTML
+======================
+
+The comment tag lets you document your DTML with comments. You can also use it
+to temporarily disable DTML tags by commenting them out.
+
+Syntax
+------
+
+'comment' tag syntax::
+
+  <dtml-comment>
+  </dtml-comment>
+
+The 'comment' tag is a block tag. The contents of the block are not executed,
+nor are they inserted into the DTML output.
+
+Examples
+--------
+
+Documenting DTML::
+
+  <dtml-comment>
+    This content is not executed and does not appear in the output.
+  </dtml-comment>
+
+Commenting out DTML::
+
+  <dtml-comment>
+    This DTML is disabled and will not be executed.
+    <dtml-call someMethod>
+  </dtml-comment>
+
+Zope still validates the DTML inside the comment block and will not save any
+comments that are not valid DTML. It is also not possible to comment in a way
+that breaks code flow, for example you cannot inproperly nest a comment and a
+dtml-in.
+
+
+functions: DTML Functions
+=========================
+
+DTML utility functions provide some Python built-in functions and some
+DTML-specific functions.
+
+Functions
+---------
+
+abs(number)
+  Return the absolute value of a number. The argument may be a plain or long
+  integer or a floating point number. If the argument is a complex number, its
+  magnitude is returned.
+
+chr(integer)
+  Return a string of one character whose ASCII code is the integer, e.g.,
+  'chr(97)' returns the string 'a'. This is the inverse of ord(). The argument
+  must be in the range 0 to 255, inclusive; 'ValueError' will be raised if the
+  integer is outside that range.
+
+DateTime()
+  Returns a Zope 'DateTime' object given constructor arguments. See the
+  DateTime API reference for more information on constructor arguments.
+
+divmod(number, number)
+  Take two numbers as arguments and return a pair of numbers consisting of
+  their quotient and remainder when using long division. With mixed operand
+  types, the rules for binary arithmetic operators apply. For plain and long
+  integers, the result is the same as '(a / b, a % b)'. For floating point
+  numbers the result is '(q, a % b)', where *q* is usually 'math.floor(a / b)'
+  but may be 1 less than that. In any case 'q * b + a % b' is very close to
+  *a*, if 'a % b' is non-zero it has the same sign as *b*, and '0 <= abs(a % b)
+  < abs(b)'.
+
+float(number)
+  Convert a string or a number to floating point. If the argument is a string,
+  it must contain a possibly signed decimal or floating point number, possibly
+  embedded in whitespace; this behaves identical to 'string.atof(number)'.
+  Otherwise, the argument may be a plain or long integer or a floating point
+  number, and a floating point number with the same value (within Python's
+  floating point precision) is returned.
+
+getattr(object, string)
+  Return the value of the named attributed of object. name must be a string. If
+  the string is the name of one of the object's attributes, the result is the
+  value of that attribute. For example, 'getattr(x, "foobar")' is equivalent to
+  'x.foobar'. If the named attribute does not exist, default is returned if
+  provided, otherwise 'AttributeError' is raised.
+
+getitem(variable, render=0)
+  Returns the value of a DTML variable. If 'render' is true, the variable is
+  rendered. See the 'render' function.
+
+hasattr(object, string)
+  The arguments are an object and a string. The result is 1 if the string is
+  the name of one of the object's attributes, 0 if not. (This is implemented by
+  calling getattr(object, name) and seeing whether it raises an exception or
+  not.)
+
+hash(object)
+  Return the hash value of the object (if it has one). Hash values are
+  integers. They are used to quickly compare dictionary keys during a
+  dictionary lookup. Numeric values that compare equal have the same hash value
+  (even if they are of different types, e.g. 1 and 1.0).
+
+has_key(variable)
+  Returns true if the DTML namespace contains the named variable.
+
+hex(integer)
+  Convert an integer number (of any size) to a hexadecimal string. The result
+  is a valid Python expression. Note: this always yields an unsigned literal,
+  e.g. on a 32-bit machine, 'hex(-1)' yields '0xffffffff'. When evaluated on a
+  machine with the same word size, this literal is evaluated as -1; at a
+  different word size, it may turn up as a large positive number or raise an
+  'OverflowError' exception.
+
+int(number)
+  Convert a string or number to a plain integer. If the argument is a string,
+  it must contain a possibly signed decimal number representable as a Python
+  integer, possibly embedded in whitespace; this behaves identical to
+  'string.atoi(number[, radix]'). The 'radix' parameter gives the base for the
+  conversion and may be any integer in the range 2 to 36. If 'radix' is
+  specified and the number is not a string, 'TypeError' is raised. Otherwise,
+  the argument may be a plain or long integer or a floating point number.
+  Conversion of floating point numbers to integers is defined by the C
+  semantics; normally the conversion truncates towards zero.
+
+len(sequence)
+  Return the length (the number of items) of an object. The argument may be a
+  sequence (string, tuple or list) or a mapping (dictionary).
+
+max(s)
+  With a single argument s, return the largest item of a non-empty sequence
+  (e.g., a string, tuple or list). With more than one argument, return the
+  largest of the arguments.
+
+min(s)
+  With a single argument s, return the smallest item of a non-empty sequence
+  (e.g., a string, tuple or list). With more than one argument, return the
+  smallest of the arguments.
+
+namespace([name=value]...)
+  Returns a new DTML namespace object. Keyword argument 'name=value' pairs are
+  pushed into the new namespace.
+
+oct(integer)
+  Convert an integer number (of any size) to an octal string. The result is a
+  valid Python expression. Note: this always yields an unsigned literal, e.g.
+  on a 32-bit machine, 'oct(-1)' yields '037777777777'. When evaluated on a
+  machine with the same word size, this literal is evaluated as -1; at a
+  different word size, it may turn up as a large positive number or raise an
+  OverflowError exception.
+
+ord(character)
+  Return the ASCII value of a string of one character. E.g., 'ord("a")' returns
+  the integer 97. This is the inverse of 'chr()'.
+
+pow(x, y [,z])
+  Return *x* to the power *y*; if *z* is present, return *x* to the power *y*,
+  modulo *z* (computed more efficiently than 'pow(x, y) % z'). The arguments
+  must have numeric types. With mixed operand types, the rules for binary
+  arithmetic operators apply. The effective operand type is also the type of
+  the result; if the result is not expressible in this type, the function
+  raises an exception; e.g., 'pow(2, -1)' or 'pow(2, 35000)' is not allowed.
+
+range([start,] stop [,step])
+  This is a versatile function to create lists containing arithmetic
+  progressions. The arguments must be plain integers. If the step argument is
+  omitted, it defaults to 1. If the start argument is omitted, it defaults to
+  0. The full form returns a list of plain integers '[start, start + step,
+  start + 2 * step, ...]'. If step is positive, the last element is the largest
+  'start + i * step' less than *stop*; if *step* is negative, the last element
+  is the largest 'start + i * step' greater than *stop*. *step* must not be
+  zero (or else 'ValueError' is raised).
+
+round(x [,n])
+  Return the floating point value *x* rounded to *n* digits after the decimal
+  point. If n is omitted, it defaults to zero. The result is a floating point
+  number. Values are rounded to the closest multiple of 10 to the power minus
+  n; if two multiples are equally close, rounding is done away from 0 (so e.g.
+  round(0.5) is 1.0 and round(-0.5) is -1.0).
+
+render(object)
+  Render 'object'. For DTML objects this evaluates the DTML code with the
+  current namespace. For other objects, this is equivalent to 'str(object)'.
+
+reorder(s [,with] [,without])
+  Reorder the items in s according to the order given in 'with' and without the
+  items mentioned in 'without'. Items from s not mentioned in with are removed.
+  s, with, and without are all either sequences of strings or sequences of
+  key-value tuples, with ordering done on the keys. This function is useful for
+  constructing ordered select lists.
+
+SecurityCalledByExecutable()
+  Return a true if the current object (e.g. DTML document or method) is being
+  called by an executable (e.g. another DTML document or method, a script or a
+  SQL method).
+
+SecurityCheckPermission(permission, object)
+  Check whether the security context allows the given permission on the given
+  object. For example, 'SecurityCheckPermission("Add Documents, Images, and
+  Files", this())' would return true if the current user was authorized to
+  create documents, images, and files in the current location.
+
+SecurityGetUser()
+  Return the current user object. This is normally the same as the
+  'REQUEST.AUTHENTICATED_USER' object. However, the 'AUTHENTICATED_USER' object
+  is insecure since it can be replaced.
+
+SecurityValidate([object] [,parent] [,name] [,value])
+  Return true if the value is accessible to the current user. 'object' is the
+  object the value was accessed in, 'parent' is the container of the value, and
+  'name' is the named used to access the value (for example, if it was obtained
+  via 'getattr'). You may omit some of the arguments, however it is best to
+  provide all available arguments.
+
+SecurityValidateValue(object)
+  Return true if the object is accessible to the current user. This function is
+  the same as calling 'SecurityValidate(None, None, None, object)'.
+
+str(object)
+  Return a string containing a nicely printable representation of an object.
+  For strings, this returns the string itself.
+
+test(condition, result [,condition, result]... [,default])
+  Takes one or more condition, result pairs and returns the result of the first
+  true condition. Only one result is returned, even if more than one condition
+  is true. If no condition is true and a default is given, the default is
+  returned. If no condition is true and there is no default, None is returned.
+
+unichr(number)
+  Return a unicode string representing the value of number as a unicode
+  character. This is the inverse of ord() for unicode characters.
+
+unicode(string[, encoding[, errors ] ])
+  Decodes string using the codec for encoding. Error handling is done according
+  to errors. The default behavior is to decode UTF-8 in strict mode, meaning
+  that encoding errors raise ValueError.
+
+Attributes
+----------
+
+None
+  The 'None' object is equivalent to the Python built-in object 'None'. This is
+  usually used to represent a Null or false value.
+
+See Also
+--------
+
+- `string module <http://docs.python.org/library/string.html>`_
+
+- `random module <http://docs.python.org/library/random.html>`_
+
+- `math module <http://docs.python.org/library/math.html>`_
+
+- `sequence module <http://docs.python.org/library/functions.html>`_
+
+
+if: Tests Conditions
+====================
+
+The 'if' tags allows you to test conditions and to take different actions
+depending on the conditions. The 'if' tag mirrors Python's 'if/elif/else'
+condition testing statements.
+
+Syntax
+------
+
+If tag syntax::
+
+  <dtml-if ConditionVariable|expr="ConditionExpression">
+  [<dtml-elif ConditionVariable|expr="ConditionExpression">]
+   ...
+  [<dtml-else>]
+  </dtml-if>
+
+The 'if' tag is a block tag. The 'if' tag and optional 'elif' tags
+take a condition variable name or a condition expression, but not
+both. If the condition name or expression evaluates to true then
+the 'if' block is executed. True means not zero, an empty string
+or an empty list.  If the condition variable is not found then the
+condition is considered false.
+
+If the initial condition is false, each 'elif' condition is tested
+in turn. If any 'elif' condition is true, its block is
+executed. Finally the optional 'else' block is executed if none of
+the 'if' and 'elif' conditions were true. Only one block will be
+executed.
+
+Examples
+--------
+
+Testing for a variable::
+
+  <dtml-if snake>
+    The snake variable is true
+  </dtml-if>
+
+Testing for expression conditions::
+
+  <dtml-if expr="num > 5">
+    num is greater than five
+  <dtml-elif expr="num < 5">
+    num is less than five
+  <dtml-else>
+    num must be five
+  </dtml-if>
+
+See Also
+--------
+
+`Python Tutorial If Statements <http://docs.python.org/tutorial/controlflow.html#if-statements>`_
+
+
+in: Loops over sequences
+========================
+
+The 'in' tag gives you powerful controls for looping over sequences
+and performing batch processing.
+
+Syntax
+------
+
+'in' tag syntax::
+
+  <dtml-in SequenceVariable|expr="SequenceExpression">
+  [<dtml-else>]
+  </dtml-in>
+
+a commenting identifier at the end tag is allowed and will be ignored like::
+
+  </dtml-in my_short_sequ_name>
+
+same for '</dtml-if>' and '</dtml-let>'
+
+The 'in' block is repeated once for each item in the sequence
+variable or sequence expression. The current item is pushed on to
+the DTML namespace during each executing of the 'in' block.
+
+If there are no items in the sequence variable or expression, the
+optional 'else' block is executed.
+
+Attributes
+----------
+
+mapping
+  Iterates over mapping objects rather than instances. This allows values of
+  the mapping objects to be accessed as DTML variables.
+
+reverse
+  Reverses the sequence.
+
+sort=string
+  Sorts the sequence by the given attribute name.
+
+start=int
+  The number of the first item to be shown, where items are numbered from 1.
+
+end=int
+  The number of the last item to be shown, where items are numbered from 1.
+
+size=int
+  The size of the batch.
+
+skip_unauthorized
+  Don't raise an exception if an unauthorized item is encountered.
+
+orphan=int
+  The desired minimum batch size. This controls how sequences are split into
+  batches. If a batch smaller than the orphan size would occur, then no split
+  is performed, and a batch larger than the batch size results.
+
+  For example, if the sequence size is 12, the batch size is 10 the orphan size
+  is 3, then the result is one batch with all 12 items since splitting the
+  items into two batches would result in a batch smaller than the orphan size.
+
+  The default value is 0.
+
+overlap=int
+  The number of items to overlap between batches. The default is no overlap.
+
+previous
+  Iterates once if there is a previous batch. Sets batch variables for previous
+  sequence.
+
+next
+  Iterates once if there is a next batch. Sets batch variables for the next
+  sequence.
+
+prefix=string
+  Provide versions of the tag variables that start with this prefix instead of
+  "sequence", and that use underscores (_) instead of hyphens (-). The prefix
+  must start with a letter and contain only alphanumeric characters and
+  underscores (_).
+
+sort_expr=expression
+  Sorts the sequence by an attribute named by the value of the expression. This
+  allows you to sort on different attributes.
+
+reverse_expr=expression
+  Reverses the sequence if the expression evaluates to true. This allows you to
+  selectively reverse the sequence.
+
+Tag Variables
+-------------
+
+Current Item Variables
+++++++++++++++++++++++
+
+These variables describe the current item.
+
+sequence-item
+  The current item.
+
+sequence-key
+  The current key. When looping over tuples of the form '(key,value)', the 'in'
+  tag interprets them as '(sequence-key, sequence-item)'.
+
+sequence-index
+  The index starting with 0 of the current item.
+
+sequence-number
+  The index starting with 1 of the current item.
+
+sequence-roman
+  The index in lowercase Roman numerals of the current item.
+
+sequence-Roman
+  The index in uppercase Roman numerals of the current item.
+
+sequence-letter
+  The index in lowercase letters of the current item.
+
+sequence-Letter
+  The index in uppercase letters of the current item.
+
+sequence-start
+  True if the current item is the first item.
+
+sequence-end
+  True if the current item is the last item.
+
+sequence-even
+  True if the index of the current item is even.
+
+sequence-odd
+  True if the index of the current item is odd.
+
+sequence-length
+  The length of the sequence.
+
+sequence-var-*variable*
+  A variable in the current item. For example, 'sequence-var-title' is the
+  'title' variable of the current item. Normally you can access these variables
+  directly since the current item is pushed on the DTML namespace. However
+  these variables can be useful when displaying previous and next batch
+  information.
+
+sequence-index-*variable*
+  The index of a variable of the current item.
+
+Summary Variables
++++++++++++++++++
+
+These variable summarize information about numeric item variables. To use these
+variable you must loop over objects (like database query results) that have
+numeric variables.
+
+total-*variable*
+  The total of all occurrences of an item variable. 
+
+count-*variable*
+  The number of occurrences of an item variable.
+
+min-*variable*
+  The minimum value of an item variable.
+
+max-*variable*
+  The maximum value of an item variable.
+
+mean-*variable*
+  The mean value of an item variable.
+
+variance-*variable*
+  The variance of an item variable with count-1 degrees of freedom.
+
+variance-n-*variable*
+  The variance of an item variable with n degrees of freedom.
+
+standard-deviation-*variable*
+  The standard-deviation of an item variable with count-1 degrees of freedom.
+
+standard-deviation-n-*variable*
+  The standard-deviation of an item variable with n degrees of freedom.
+
+Grouping Variables
+++++++++++++++++++
+
+These variables allow you to track changes in current item variables.
+
+first-*variable*
+  True if the current item is the first with a particular value for a variable.
+
+last-*variable*
+  True if the current item is the last with a particular value for a variable.
+
+Batch Variables
++++++++++++++++
+
+sequence-query
+  The query string with the 'start' variable removed. You can use this variable
+  to construct links to next and previous batches.
+
+sequence-step-size
+  The batch size.
+
+previous-sequence
+  True if the current batch is not the first one. Note, this variable is only
+  true for the first loop iteration.
+
+previous-sequence-start-index
+  The starting index of the previous batch.
+
+previous-sequence-start-number
+  The starting number of the previous batch. Note, this is the same as
+  'previous-sequence-start-index' + 1.
+
+previous-sequence-end-index
+  The ending index of the previous batch.
+
+previous-sequence-end-number
+  The ending number of the previous batch. Note, this is the same as
+  'previous-sequence-end-index' + 1.
+
+previous-sequence-size
+  The size of the previous batch.
+
+previous-batches
+  A sequence of mapping objects with information about all previous batches.
+  Each mapping object has these keys 'batch-start-index', 'batch-end-index',
+  and 'batch-size'.
+
+next-sequence
+  True if the current batch is not the last batch. Note, this variable is only
+  true for the last loop iteration.
+
+next-sequence-start-index
+  The starting index of the next sequence.
+
+next-sequence-start-number
+  The starting number of the next sequence. Note, this is the same as
+  'next-sequence-start-index' + 1.
+
+next-sequence-end-index
+  The ending index of the next sequence.
+
+next-sequence-end-number
+  The ending number of the next sequence. Note, this is the same as
+  'next-sequence-end-index' + 1.
+
+next-sequence-size
+  The size of the next index.
+
+next-batches
+  A sequence of mapping objects with information about all following batches.
+  Each mapping object has these keys 'batch-start-index', 'batch-end-index',
+  and 'batch-size'.
+
+Examples
+--------
+
+Looping over sub-objects::
+
+  <dtml-in objectValues>
+    title: <dtml-var title><br>
+  </dtml-in>
+
+Looping over two sets of objects, using prefixes::
+
+  <dtml-let rows="(1,2,3)" cols="(4,5,6)">
+    <dtml-in rows prefix="row">
+      <dtml-in cols prefix="col">
+        <dtml-var expr="row_item * col_item"><br>
+        <dtml-if col_end>
+          <dtml-var expr="col_total_item * row_mean_item">
+        </dtml-if>
+      </dtml-in>
+    </dtml-in>
+  </dtml-let>
+
+Looping over a list of '(key, value)' tuples::
+
+  <dtml-in objectItems>
+    id: <dtml-var sequence-key>, title: <dtml-var title><br>
+  </dtml-in> 
+
+Creating alternate colored table rows::
+
+  <table>
+  <dtml-in objectValues>
+  <tr <dtml-if sequence-odd>bgcolor="#EEEEEE"
+      <dtml-else>bgcolor="#FFFFFF"
+      </dtml-if>>
+    <td><dtml-var title></td>
+  </tr>
+  </dtml-in>
+  </table>
+
+Basic batch processing::
+
+  <p>
+  <dtml-in largeSequence size=10 start=start previous>
+    <a href="<dtml-var absolute_url>
+      <dtml-var sequence-query>start=<dtml-var previous-sequence-start-number>">
+      Previous
+    </a>
+  </dtml-in>
+
+  <dtml-in largeSequence size=10 start=start next>
+    <a href="<dtml-var absolute_url>
+      <dtml-var sequence-query>start=<dtml-var next-sequence-start-number>">
+      Next
+    </a>
+  </dtml-in>
+  </p>
+
+  <p>
+  <dtml-in largeSequence size=10 start=start>
+    <dtml-var sequence-item>
+  </dtml-in>
+  </p>
+
+This example creates *Previous* and *Next* links to navigate between batches.
+Note, by using 'sequence-query', you do not lose any GET variables as you
+navigate between batches.
+
+let: Defines DTML variables
+===========================
+
+The 'let' tag defines variables in the DTML namespace.
+
+Syntax
+------
+
+'let' tag syntax::
+
+  <dtml-let [Name=Variable][Name="Expression"]...>
+  </dtml-let>
+
+The 'let' tag is a block tag. Variables are defined by tag arguments. Defined
+variables are pushed onto the DTML namespace while the 'let' block is executed.
+Variables are defined by attributes. The 'let' tag can have one or more
+attributes with arbitrary names. If the attributes are defined with double
+quotes they are considered expressions, otherwise they are looked up by name.
+Attributes are processed in order, so later attributes can reference, and/or
+overwrite earlier ones.
+
+Examples
+--------
+
+Basic usage::
+
+  <dtml-let name="'Bob'" ids=objectIds>
+    name: <dtml-var name>
+    ids: <dtml-var ids>
+  </dtml-let>
+
+Using the 'let' tag with the 'in' tag::
+
+ <dtml-in expr="(1,2,3,4)">
+   <dtml-let num=sequence-item
+             index=sequence-index
+             result="num*index">
+     <dtml-var num> * <dtml-var index> = <dtml-var result>
+   </dtml-let>
+ </dtml-in>
+
+This yields::
+
+  1 * 0 = 0
+  2 * 1 = 2
+  3 * 2 = 6
+  4 * 3 = 12
+
+See Also
+--------
+
+- with tag
+
+
+mime: Formats data with MIME
+============================
+
+The 'mime' tag allows you to create MIME encoded data. It is chiefly used to
+format email inside the 'sendmail' tag.
+
+Syntax
+------
+
+'mime' tag syntax::
+
+  <dtml-mime>
+  [<dtml-boundry>]
+  ...
+  </dtml-mime>
+
+The 'mime' tag is a block tag. The block is can be divided by one or more
+'boundry' tags to create a multi-part MIME message. 'mime' tags may be nested.
+The 'mime' tag is most often used inside the 'sendmail' tag.
+
+Attributes
+----------
+
+Both the 'mime' and 'boundry' tags have the same attributes.
+
+encode=string
+  MIME Content-Transfer-Encoding header, defaults to 'base64'. Valid encoding
+  options include 'base64', 'quoted-printable', 'uuencode', 'x-uuencode',
+  'uue', 'x-uue', and '7bit'. If the 'encode' attribute is set to '7bit' no
+  encoding is done on the block and the data is assumed to be in a valid MIME
+  format.
+
+type=string
+  MIME Content-Type header.
+
+type_expr=string
+  MIME Content-Type header as a variable expression. You cannot use both 'type'
+  and 'type_expr'.
+
+name=string
+  MIME Content-Type header name.
+
+name_expr=string
+  MIME Content-Type header name as a variable expression. You cannot use both
+  'name' and 'name_expr'.
+
+disposition=string
+  MIME Content-Disposition header.
+
+disposition_expr=string
+  MIME Content-Disposition header as a variable expression. You cannot use both
+  'disposition' and 'disposition_expr'.
+
+filename=string
+  MIME Content-Disposition header filename.
+
+filename_expr=string
+  MIME Content-Disposition header filename as a variable expression. You cannot
+  use both 'filename' and 'filename_expr'.
+
+skip_expr=string
+  A variable expression that if true, skips the block. You can use this
+  attribute to selectively include MIME blocks.
+
+Examples
+--------
+
+Sending a file attachment::
+
+  <dtml-sendmail>
+  To: <dtml-var recipient>
+  Subject: Resume
+  <dtml-mime type="text/plain" encode="7bit">
+
+  Hi, please take a look at my resume.
+
+  <dtml-boundary type="application/octet-stream" disposition="attachment" 
+  encode="base64" filename_expr="resume_file.getId()"><dtml-var expr="resume_file.read()"></dtml-mime>
+  </dtml-sendmail>
+
+See Also
+--------
+
+- `Python Library mimetools <http://docs.python.org/library/mimetools.html>`_
+
+raise: Raises an exception
+==========================
+
+The 'raise' tag raises an exception, mirroring the Python 'raise'
+statement.
+
+Syntax
+------
+
+'raise' tag syntax::
+
+  <dtml-raise ExceptionName|ExceptionExpression>
+  </dtml-raise>
+
+The 'raise' tag is a block tag. It raises an exception. Exceptions
+can be an exception class or a string. The contents of the tag are
+passed as the error value.
+
+Examples
+--------
+
+Raising a KeyError::
+
+  <dtml-raise KeyError></dtml-raise>
+
+Raising an HTTP 404 error::
+
+  <dtml-raise NotFound>Web Page Not Found</dtml-raise>
+
+See Also
+--------
+
+- try tag
+
+- `Python Tutorial Errors and Exceptions <http://docs.python.org/tutorial/errors.html>`_
+
+- `Python Built-in Exceptions <http://docs.python.org/library/exceptions.html>`_
+
+return: Returns data
+====================
+
+The 'return' tag stops executing DTML and returns data. It mirrors
+the Python 'return' statement.
+
+Syntax
+------
+
+'return' tag syntax::
+
+  <dtml-return ReturnVariable|expr="ReturnExpression">
+
+Stops execution of DTML and returns a variable or expression. The
+DTML output is not returned. Usually a return expression is more
+useful than a return variable. Scripts largely obsolete this tag.
+
+Examples
+
+Returning a variable::
+
+  <dtml-return result>
+
+Returning a Python dictionary::
+
+  <dtml-return expr="{'hi':200, 'lo':5}">
+
+sendmail: Sends email with SMTP
+===============================
+
+The 'sendmail' tag sends an email message using SMTP.
+
+Syntax
+------
+
+'sendmail' tag syntax::
+
+  <dtml-sendmail>
+  </dtml-sendmail>
+
+The 'sendmail' tag is a block tag. It either requires a 'mailhost' or a
+'smtphost' argument, but not both. The tag block is sent as an email message.
+The beginning of the block describes the email headers. The headers are
+separated from the body by a blank line. Alternately the 'To', 'From' and
+'Subject' headers can be set with tag arguments.
+
+Attributes
+----------
+
+mailhost
+  The name of a Zope MailHost object to use to send email. You cannot specify
+  both a mailhost and a smtphost.
+
+smtphost
+  The name of a SMTP server used to send email. You cannot specify both a
+  mailhost and a smtphost.
+
+port
+  If the smtphost attribute is used, then the port attribute is used to specify
+  a port number to connect to. If not specified, then port 25 will be used.
+
+mailto
+  The recipient address or a list of recipient addresses separated by commas.
+  This can also be specified with the 'To' header.
+
+mailfrom
+  The sender address. This can also be specified with the 'From' header.
+
+subject
+  The email subject. This can also be specified with the 'Subject' header.
+
+Examples
+--------
+
+Sending an email message using a Mail Host::
+
+  <dtml-sendmail mailhost="mailhost">
+  To: <dtml-var recipient>
+  From: <dtml-var sender>
+  Subject: <dtml-var subject>
+
+  Dear <dtml-var recipient>,
+
+  You order number <dtml-var order_number> is ready.
+  Please pick it up at your soonest convenience.
+  </dtml-sendmail>
+
+See Also
+--------
+
+- `RFC 821 (SMTP Protocol) <http://www.ietf.org/rfc/rfc0821.txt>`_
+
+- mime tag
+
+
+sqlgroup: Formats complex SQL expressions
+=========================================
+
+The 'sqlgroup' tag formats complex boolean SQL expressions. You can use it
+along with the 'sqltest' tag to build dynamic SQL queries that tailor
+themselves to the environment. This tag is used in SQL Methods.
+
+Syntax
+------
+
+'sqlgroup' tag syntax::
+
+  <dtml-sqlgroup>
+  [<dtml-or>]
+  [<dtml-and>]
+  ...
+  </dtml-sqlgroup>
+
+The 'sqlgroup' tag is a block tag. It is divided into blocks with
+one or more optional 'or' and 'and' tags. 'sqlgroup' tags can be
+nested to produce complex logic.
+
+Attributes
+----------
+
+required=boolean
+  Indicates whether the group is required. If it is not required and contains
+  nothing, it is excluded from the DTML output.
+
+where=boolean
+  If true, includes the string "where". This is useful for the outermost
+  'sqlgroup' tag in a SQL 'select' query.
+
+Examples
+--------
+
+Sample usage::
+
+  select * from employees 
+  <dtml-sqlgroup where>
+    <dtml-sqltest salary op="gt" type="float" optional>
+  <dtml-and>
+    <dtml-sqltest first type="nb" multiple optional>
+  <dtml-and>
+    <dtml-sqltest last type="nb" multiple optional>
+  </dtml-sqlgroup>  
+
+If 'first' is 'Bob' and 'last' is 'Smith, McDonald' it renders::
+
+  select * from employees
+  where
+  (first='Bob'
+   and
+   last in ('Smith', 'McDonald')
+  )
+
+If 'salary' is 50000 and 'last' is 'Smith' it renders::
+
+  select * from employees
+  where 
+  (salary > 50000.0
+   and
+   last='Smith'
+  )
+
+Nested 'sqlgroup' tags::
+
+  select * from employees
+  <dtml-sqlgroup where>
+    <dtml-sqlgroup>
+       <dtml-sqltest first op="like" type="nb">
+    <dtml-and>
+       <dtml-sqltest last op="like" type="nb">
+    </dtml-sqlgroup>
+  <dtml-or>
+    <dtml-sqltest salary op="gt" type="float">
+  </dtml-sqlgroup>
+
+Given sample arguments, this template renders to SQL like so::
+
+  select * form employees
+  where
+  (
+    (
+     name like 'A*'
+     and
+     last like 'Smith'
+     )
+   or
+   salary > 20000.0
+  )
+
+See Also
+--------
+
+- sqltest tag
+
+
+sqltest: Formats SQL condition tests
+====================================
+
+The 'sqltest' tag inserts a condition test into SQL code. It tests a column
+against a variable. This tag is used in SQL Methods.
+
+Syntax
+------
+
+'sqltest' tag syntax::
+
+  <dtml-sqltest Variable|expr="VariableExpression">
+
+The 'sqltest' tag is a singleton. It inserts a SQL condition test statement. It
+is used to build SQL queries. The 'sqltest' tag correctly escapes the inserted
+variable. The named variable or variable expression is tested against a SQL
+column using the specified comparison operation.
+
+Attributes
+----------
+
+type=string
+  The type of the variable. Valid types include: 'string', 'int', 'float' and
+  'nb'. 'nb' means non-blank string, and should be used instead of 'string'
+  unless you want to test for blank values. The type attribute is required and
+  is used to properly escape inserted variable.
+
+column=string
+  The name of the SQL column to test against. This attribute defaults to the
+  variable name.
+
+multiple=boolean
+  If true, then the variable may be a sequence of values to test the column
+  against.
+
+optional=boolean
+  If true, then the test is optional and will not be rendered if the variable
+  is empty or non-existent.
+
+op=string
+  The comparison operation. Valid comparisons include: 
+
+  eq
+    equal to
+
+  gt
+    greater than
+
+  lt
+    less than
+
+  ne
+    not equal to
+
+  ge
+    greater than or equal to
+
+  le
+    less than or equal to
+
+  The comparison defaults to equal to. If the comparison is not
+  recognized it is used anyway. Thus you can use comparisons such
+  as 'like'.
+
+Examples
+--------
+
+Basic usage::
+
+  select * from employees
+    where <dtml-sqltest name type="nb">
+
+If the 'name' variable is 'Bob' then this renders::
+
+  select * from employees
+    where name = 'Bob'
+
+Multiple values::
+
+  select * from employees
+    where <dtml-sqltest empid type=int multiple>
+
+If the 'empid' variable is '(12,14,17)' then this renders::
+
+  select * from employees
+    where empid in (12, 14, 17)
+
+See Also
+--------
+
+- sqlgroup tag
+
+- sqlvar tag
+
+
+sqlvar: Inserts SQL variables
+=============================
+
+The 'sqlvar' tag safely inserts variables into SQL code. This tag is used in
+SQL Methods.
+
+Syntax
+------
+
+'sqlvar' tag syntax::
+
+  <dtml-sqlvar Variable|expr="VariableExpression">
+
+The 'sqlvar' tag is a singleton. Like the 'var' tag, the 'sqlvar' tag looks up
+a variable and inserts it. Unlike the var tag, the formatting options are
+tailored for SQL code.
+
+Attributes
+----------
+
+type=string
+  The type of the variable. Valid types include: 'string', 'int', 'float' and
+  'nb'. 'nb' means non-blank string and should be used in place of 'string'
+  unless you want to use blank strings. The type attribute is required and is
+  used to properly escape inserted variable.
+
+optional=boolean
+  If true and the variable is null or non-existent, then nothing is inserted.
+
+Examples
+--------
+
+Basic usage::
+
+  select * from employees 
+    where name=<dtml-sqlvar name type="nb">
+
+This SQL quotes the 'name' string variable.
+
+See Also
+--------
+
+- sqltest tag
+
+
+tree: Inserts a tree widget
+===========================
+
+The 'tree' tag displays a dynamic tree widget by querying Zope objects.
+
+Syntax
+------
+
+'tree' tag syntax::
+
+  <dtml-tree [VariableName|expr="VariableExpression"]>
+  </dtml-tree>
+
+The 'tree' tag is a block tag. It renders a dynamic tree widget in
+HTML. The root of the tree is given by variable name or
+expression, if present, otherwise it defaults to the current
+object. The 'tree' block is rendered for each tree node, with the
+current node pushed onto the DTML namespace.
+
+Tree state is set in HTTP cookies. Thus for trees to work, cookies
+must be enabled. Also you can only have one tree per page.
+
+Attributes
+----------
+
+branches=string
+  Finds tree branches by calling the named method. The default method is
+  'tpValues' which most Zope objects support.
+
+branches_expr=string
+  Finds tree branches by evaluating the expression.
+
+id=string
+  The name of a method or id to determine tree state. It defaults to 'tpId'
+  which most Zope objects support. This attribute is for advanced usage only.
+
+url=string
+  The name of a method or attribute to determine tree item URLs. It defaults to
+  'tpURL' which most Zope objects support. This attribute is for advanced usage
+  only.
+
+leaves=string
+  The name of a DTML Document or Method used to render nodes that don't have
+  any children. Note: this document should begin with '<dtml-var
+  standard_html_header>' and end with '<dtml-var standard_html_footer>' in
+  order to ensure proper display in the tree.
+
+header=string
+  The name of a DTML Document or Method displayed before expanded nodes. If the
+  header is not found, it is skipped.
+
+footer=string
+  The name of a DTML Document or Method displayed after expanded nodes. If the
+  footer is not found, it is skipped.
+
+nowrap=boolean
+  If true then rather than wrap, nodes may be truncated to fit available space.
+
+sort=string
+  Sorts the branches by the named attribute.
+
+reverse
+  Reverses the order of the branches.
+
+assume_children=boolean
+  Assumes that nodes have children. This is useful if fetching and querying
+  child nodes is a costly process. This results in plus boxes being drawn next
+  to all nodes.
+
+single=boolean
+  Allows only one branch to be expanded at a time. When you expand a new
+  branch, any other expanded branches close.
+
+skip_unauthorized
+  Skips nodes that the user is unauthorized to see, rather than raising an
+  error.
+
+urlparam=string
+  A query string which is included in the expanding and contracting widget
+  links. This attribute is for advanced usage only.
+
+prefix=string
+  Provide versions of the tag variables that start with this prefix instead of
+  "tree", and that use underscores (_) instead of hyphens (-). The prefix must
+  start with a letter and contain only alphanumeric characters and underscores
+  (_).
+
+Tag Variables
+-------------
+
+tree-item-expanded
+  True if the current node is expanded.
+
+tree-item-url
+  The URL of the current node.
+
+tree-root-url
+  The URL of the root node.
+
+tree-level
+  The depth of the current node. Top-level nodes have a depth of zero.
+
+tree-colspan
+  The number of levels deep the tree is being rendered. This variable along
+  with the 'tree-level' variable can be used to calculate table rows and
+  colspan settings when inserting table rows into the tree table.
+
+tree-state
+  The tree state expressed as a list of ids and sub-lists of ids. This variable
+  is for advanced usage only.
+
+Tag Control Variables
+---------------------
+
+You can control the tree tag by setting these variables.
+
+expand_all
+  If this variable is true then the entire tree is expanded.
+
+collapse_all
+  If this variable is true then the entire tree is collapsed.
+
+Examples
+--------
+
+Display a tree rooted in the current object::
+
+  <dtml-tree>
+    <dtml-var title_or_id>
+  </dtml-tree>
+
+Display a tree rooted in another object, using a custom branches
+method::
+
+  <dtml-tree expr="folder.object" branches="objectValues">
+    Node id : <dtml-var getId>
+  </dtml-tree>
+
+try: Handles exceptions
+=======================
+
+The 'try' tag allows exception handling in DTML, mirroring the Python
+'try/except' and 'try/finally' constructs.
+
+Syntax
+------
+
+The 'try' tag has two different syntaxes, 'try/except/else' and 'try/finally'.
+
+'try/except/else' Syntax::
+
+  <dtml-try>
+  <dtml-except [ExceptionName] [ExceptionName]...>
+  ... 
+  [<dtml-else>]
+  </dtml-try>
+
+The 'try' tag encloses a block in which exceptions can be caught and handled.
+There can be one or more 'except' tags that handles zero or more exceptions. If
+an 'except' tag does not specify an exception, then it handles all exceptions.
+
+When an exception is raised, control jumps to the first 'except' tag that
+handles the exception. If there is no 'except' tag to handle the exception,
+then the exception is raised normally.
+
+If no exception is raised, and there is an 'else' tag, then the 'else' tag will
+be executed after the body of the 'try' tag.
+
+The 'except' and 'else' tags are optional.
+
+'try/finally' Syntax::
+
+  <dtml-try>
+  <dtml-finally>
+  </dtml-try>
+
+The 'finally' tag cannot be used in the same 'try' block as the 'except' and
+'else' tags. If there is a 'finally' tag, its block will be executed whether or
+not an exception is raised in the 'try' block.
+
+Attributes
+----------
+
+except
+  Zero or more exception names. If no exceptions are listed then the except tag
+  will handle all exceptions.
+
+Tag Variables
+-------------
+
+Inside the 'except' block these variables are defined.
+
+error_type
+  The exception type.
+
+error_value
+  The exception value.
+
+error_tb
+  The traceback.
+
+Examples
+--------
+
+Catching a math error::
+
+  <dtml-try>
+  <dtml-var expr="1/0">
+  <dtml-except ZeroDivisionError>
+  You tried to divide by zero.
+  </dtml-try>
+
+Returning information about the handled exception::
+
+  <dtml-try>
+  <dtml-call dangerousMethod>
+  <dtml-except>
+  An error occurred.
+  Error type: <dtml-var error_type>
+  Error value: <dtml-var error_value>
+  </dtml-try>
+
+Using finally to make sure to perform clean up regardless of whether an error
+is raised or not::
+
+  <dtml-call acquireLock>
+  <dtml-try>
+  <dtml-call someMethod>
+  <dtml-finally>
+  <dtml-call releaseLock>
+  </dtml-try>
+
+See Also
+--------
+
+- raise tag
+
+- `Python Tutorial Errors and Exceptions <http://docs.python.org/tutorial/errors.html>`_
+
+- `Python Built-in Exceptions <http://docs.python.org/library/exceptions.html>`_
+
+
+unless: Tests a condition
+=========================
+
+The 'unless' tag provides a shortcut for testing negative conditions. For more
+complete condition testing use the 'if' tag.
+
+Syntax
+------
+
+'unless' tag syntax::
+
+  <dtml-unless ConditionVariable|expr="ConditionExpression">
+  </dtml-unless>
+
+The 'unless' tag is a block tag. If the condition variable or expression
+evaluates to false, then the contained block is executed. Like the 'if' tag,
+variables that are not present are considered false.
+
+Examples
+--------
+
+Testing a variable::
+
+  <dtml-unless testMode>
+    <dtml-call dangerousOperation>
+  </dtml-unless>
+
+The block will be executed if 'testMode' does not exist, or exists but is
+false.
+
+See Also
+--------
+
+- if tag
+
+
+var: Inserts a variable
+=======================
+
+The 'var' tags allows you insert variables into DTML output.
+
+Syntax
+------
+
+'var' tag syntax::
+
+  <dtml-var Variable|expr="Expression">
+
+The 'var' tag is a singleton tag. The 'var' tag finds a variable by searching
+the DTML namespace which usually consists of current object, the current
+object's containers, and finally the web request. If the variable is found, it
+is inserted into the DTML output. If not found, Zope raises an error.
+
+'var' tag entity syntax::
+
+  &dtml-variableName;
+
+Entity syntax is a short cut which inserts and HTML quotes the variable. It is
+useful when inserting variables into HTML tags.
+
+'var' tag entity syntax with attributes::
+
+  &dtml.attribute1[.attribute2]...-variableName;
+
+To a limited degree you may specify attributes with the entity syntax. You may
+include zero or more attributes delimited by periods. You cannot provide
+arguments for attributes using the entity syntax. If you provide zero or more
+attributes, then the variable is not automatically HTML quoted. Thus you can
+avoid HTML quoting with this syntax, '&dtml.-variableName;'.
+
+Attributes
+----------
+
+html_quote
+  Convert characters that have special meaning in HTML to HTML character
+  entities.
+
+missing=string
+  Specify a default value in case Zope cannot find the variable.
+
+fmt=string
+  Format a variable. Zope provides a few built-in formats including C-style
+  format strings. For more information on C-style format strings see the
+  `Python Library Reference <http://docs.python.org/library/stdtypes.html#typesseq-strings>`_.
+  If the format string is not a built-in format, then it is assumed to be a
+  method of the object, and it called.
+
+  collection-length
+    The length of the variable, assuming it is a sequence.
+
+null=string
+  A default value to use if the variable is None.
+
+lower
+  Converts upper-case letters to lower case. 
+
+upper
+  Converts lower-case letters to upper case. 
+
+capitalize
+  Capitalizes the first character of the inserted word.
+
+spacify
+  Changes underscores in the inserted value to spaces.
+
+thousands_commas
+  Inserts commas every three digits to the left of a decimal point in values
+  containing numbers for example '12000' becomes '12,000'.
+
+url
+  Inserts the URL of the object, by calling its 'absolute_url' method.
+
+url_quote
+  Converts characters that have special meaning in URLs to HTML character
+  entities.
+
+url_quote_plus
+  URL quotes character, like 'url_quote' but also converts spaces to plus
+  signs.
+
+sql_quote
+  Converts single quotes to pairs of single quotes. This is needed to safely
+  include values in SQL strings.
+
+newline_to_br
+  Convert newlines (including carriage returns) to HTML break tags.
+
+size=arg
+  Truncates the variable at the given length (Note: if a space occurs in the
+  second half of the truncated string, then the string is further truncated to
+  the right-most space).
+
+etc=arg
+  Specifies a string to add to the end of a string which has been truncated (by
+  setting the 'size' attribute listed above). By default, this is '...'
+
+
+Examples
+--------
+
+Inserting a simple variable into a document::
+
+  <dtml-var standard_html_header>
+
+Truncation::
+
+  <dtml-var colors size=10 etc=", etc.">
+
+will produce the following output if *colors* is the string 'red yellow
+green'::
+
+  red yellow, etc.
+
+C-style string formatting::
+
+  <dtml-var expr="23432.2323" fmt="%.2f">
+
+renders to::
+
+  23432.23
+
+Inserting a variable, *link*, inside an HTML 'A' tag with the entity syntax::
+
+  <a href="&dtml-link;">Link</a>
+
+Inserting a link to a document 'doc', using entity syntax with attributes::
+
+  <a href="&dtml.url-doc;"><dtml-var doc fmt="title_or_id"></a>
+
+This creates an HTML link to an object using its URL and title. This example
+calls the object's 'absolute_url' method for the URL (using the 'url'
+attribute) and its 'title_or_id' method for the title.
+
+with: Controls DTML variable look up
+====================================
+
+The 'with' tag pushes an object onto the DTML namespace. Variables will be
+looked up in the pushed object first.
+
+Syntax
+------
+
+'with' tag syntax::
+
+  <dtml-with Variable|expr="Expression">
+  </dtml-with>
+
+The 'with' tag is a block tag. It pushes the named variable or variable
+expression onto the DTML namespace for the duration of the 'with' block. Thus
+names are looked up in the pushed object first.
+
+Attributes
+----------
+
+only
+  Limits the DTML namespace to only include the one defined in the 'with' tag.
+
+mapping
+  Indicates that the variable or expression is a mapping object. This ensures
+  that variables are looked up correctly in the mapping object.
+
+Examples
+--------
+
+Looking up a variable in the REQUEST::
+
+  <dtml-with REQUEST only>
+    <dtml-if id>
+      <dtml-var id>
+    <dtml-else>
+      'id' was not in the request.
+    </dtml-if>
+  </dtml-with>
+
+Pushing the first child on the DTML namespace::
+
+  <dtml-with expr="objectValues()[0]">
+    First child's id: <dtml-var id>
+  </dtml-with>
+
+See Also
+--------
+
+- let tag

Copied: zope2docs/branches/baijum-reorganize/zope2book/AppendixB.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/AppendixB.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/AppendixB.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/AppendixB.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,27 @@
+Appendix B: API Reference
+#########################
+
+Introduction
+============
+
+This reference describes the interfaces to the most common set of basic Zope
+objects. This reference is useful while writing Page Templates, DTML, Python
+scripts, and Product code.
+
+The intended audience is able to read simple Python code and has at least
+passing experience with object-oriented programming.
+
+The reference is not a tutorial. Nor is it a substitute for reading the rest of
+the Zope Book. Examples, where they are provided, are intended to be
+illustrative, but not comprehensive.
+
+Sorry
+=====
+
+The manually maintained API reference wasn't such a good idea.
+
+Converting it from the original source of structured text to reStructuredText
+was too much work to be done. We will look into auto-generating the API
+documentation from docstrings at some point.
+
+Reading the code is your best bet for now.

Copied: zope2docs/branches/baijum-reorganize/zope2book/AppendixC.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/AppendixC.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/AppendixC.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/AppendixC.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,1382 @@
+Appendix C: Zope Page Templates Reference
+#########################################
+
+Zope Page Templates are an HTML/XML generation tool. This appendix is a
+reference to Zope Page Templates standards: Template Attribute Language (TAL),
+TAL Expression Syntax (TALES), and Macro Expansion TAL (METAL). It also
+describes some ZPT-specific behaviors that are not part of the standards.
+
+TAL Overview
+============
+
+The *Template Attribute Language* (TAL) standard is an attribute language used
+to create dynamic templates. It allows elements of a document to be replaced,
+repeated, or omitted.
+
+The statements of TAL are XML attributes from the TAL namespace. These
+attributes can be applied to an XML or HTML document in order to make it act as
+a template.
+
+A **TAL statement** has a name (the attribute name) and a body (the attribute
+value). For example, an `content` statement might look like::
+
+  tal:content="string:Hello"
+
+The element on which a statement is defined is its **statement element**. Most
+TAL statements require expressions, but the syntax and semantics of these
+expressions are not part of TAL. TALES is recommended for this purpose.
+
+TAL Namespace
++++++++++++++
+
+The TAL namespace URI and recommended alias are currently defined
+as::
+
+  xmlns:tal="http://xml.zope.org/namespaces/tal"
+
+This is not a URL, but merely a unique identifier. Do not expect a browser to
+resolve it successfully.
+
+Zope does not require an XML namespace declaration when creating templates with
+a content-type of `text/html`. However, it does require an XML namespace
+declaration for all other content-types.
+
+TAL Statements
+++++++++++++++
+
+These are the tal statements:
+
+- tal:attributes - dynamically change element attributes.
+
+- tal:define - define variables.
+
+- tal:condition - test conditions.
+
+- tal:content - replace the content of an element.
+
+- tal:omit-tag - remove an element, leaving the content of the element.
+
+- tal:on-error - handle errors.
+
+- tal:repeat - repeat an element.
+
+- tal:replace - replace the content of an element and remove the element
+  leaving the content.
+
+Expressions used in statements may return values of any type, although most
+statements will only accept strings, or will convert values into a string
+representation. The expression language must define a value named *nothing*
+that is not a string. In particular, this value is useful for deleting elements
+or attributes.
+
+Order of Operations
++++++++++++++++++++
+
+When there is only one TAL statement per element, the order in which they are
+executed is simple. Starting with the root element, each element's statements
+are executed, then each of its child elements is visited, in order, to do the
+same.
+
+Any combination of statements may appear on the same elements, except that the
+`content` and `replace` statements may not appear together.
+
+Due to the fact that TAL sees statements as XML attributes, even in HTML
+documents, it cannot use the order in which statements are written in the tag
+to determine the order in which they are executed. TAL must also forbid
+multiples of the same kind of statement on a single element, so it is
+sufficient to arrange the kinds of statement in a precedence list.
+
+When an element has multiple statements, they are executed in this order:
+
+
+1. define
+
+2. condition
+
+3. repeat
+
+4. content or replace
+
+5. attributes
+
+6. omit-tag
+
+Since the `on-error` statement is only invoked when an error occurs, it does
+not appear in the list.
+
+It may not be apparent that there needs to be an ordering. The reason that
+there must be one is that TAL is XML based. The XML specification specifically
+states that XML processors are free to rewrite the terms. In particular, you
+cannot assume that attributes of an XML statement will be processed in the
+order written, particularly if there is another preprocessor involved. To avoid
+needless proliferation of tags, and still permit unambiguous execution of
+complex TAL, a precedence order was chosen according to the following
+rationale.
+
+The reasoning behind this ordering goes like this: You often want to set up
+variables for use in other statements, so `define` comes first. The very next
+thing to do is decide whether this element will be included at all, so
+`condition` is next; since the condition may depend on variables you just set,
+it comes after `define`. It is valuable be able to replace various parts of an
+element with different values on each iteration of a repeat, so `repeat` is
+next. It makes no sense to replace attributes and then throw them away, so
+`attributes` is last. The remaining statements clash, because they each replace
+or edit the statement element.
+
+attributes: Replace element attributes
+======================================
+
+Syntax
+++++++
+
+tal:attributes syntax::
+
+  argument             ::= attribute_statement [';' attribute_statement]*
+  attribute_statement  ::= attribute_name expression
+  attribute_name       ::= [namespace-prefix ':'] Name
+  namespace-prefix     ::= Name
+
+*Note: If you want to include a semi-colon (;) in an `expression`, it must be
+escaped by doubling it (;;).*
+
+Description
++++++++++++
+
+The `tal:attributes` statement replaces the value of an attribute (or creates
+an attribute) with a dynamic value. You can qualify an attribute name with a
+namespace prefix, for example::
+
+  html:table
+
+if you are generating an XML document with multiple namespaces. The value of
+each expression is converted to a string, if necessary.
+
+If the expression associated with an attribute assignment evaluates to
+*nothing*, then that attribute is deleted from the statement element. If the
+expression evaluates to *default*, then that attribute is left unchanged. Each
+attribute assignment is independent, so attributes may be assigned in the same
+statement in which some attributes are deleted and others are left alone.
+
+If you use `tal:attributes` on an element with an active `tal:replace` command,
+the `tal:attributes` statement is ignored.
+
+
+If you use `tal:attributes` on an element with a `tal:repeat` statement, the
+replacement is made on each repetition of the element, and the replacement
+expression is evaluated fresh for each repetition.
+
+Examples
+++++++++
+
+Replacing a link::
+
+  <a href="/sample/link.html"
+     tal:attributes="href context/sub/absolute_url">
+
+Replacing two attributes::
+
+  <textarea
+    rows="80" cols="20"
+    tal:attributes="rows request/rows;cols request/cols">
+
+condition: Conditionally insert or remove an element
+====================================================
+
+Syntax
+++++++
+
+tal:condition syntax::
+
+  argument ::= expression
+
+Description
++++++++++++
+
+The `tal:condition` statement includes the statement element in the template
+only if the condition is met, and omits it otherwise. If its expression
+evaluates to a *true* value, then normal processing of the element continues,
+otherwise the statement element is immediately removed from the template. For
+these purposes, the value *nothing* is false, and *default* has the same effect
+as returning a true value.
+
+*Note: Zope considers missing variables, None, zero, empty strings, and empty
+sequences false; all other values are true.*
+
+Examples
+++++++++
+
+Test a variable before inserting it (the first example tests for existence and
+truth, while the second only tests for existence)::
+
+  <p tal:condition="request/message | nothing"
+     tal:content="request/message">message goes here</p>
+
+  <p tal:condition="exists:request/message"
+     tal:content="request/message">message goes here</p>
+
+Test for alternate conditions::
+
+  <div tal:repeat="item python:range(10)">
+    <p tal:condition="repeat/item/even">Even</p>
+    <p tal:condition="repeat/item/odd">Odd</p>
+  </div>
+
+content: Replace the content of an element
+==========================================
+
+Syntax
+++++++
+
+tal:content syntax::
+
+  argument ::= (['text'] | 'structure') expression
+
+Description
++++++++++++
+
+Rather than replacing an entire element, you can insert text or structure in
+place of its children with the `tal:content` statement. The statement argument
+is exactly like that of `tal:replace`, and is interpreted in the same fashion.
+If the expression evaluates to *nothing*, the statement element is left
+childless. If the expression evaluates to *default*, then the element's
+contents are unchanged.
+
+The default replacement behavior is `text`, which replaces angle-brackets and
+ampersands with their HTML entity equivalents. The `structure` keyword passes
+the replacement text through unchanged, allowing HTML/XML markup to be
+inserted. This can break your page if the text contains unanticipated markup
+(e.g.. text submitted via a web form), which is the reason that it is not the
+default.
+
+Examples
+++++++++
+
+Inserting the user name::
+
+  <p tal:content="user/getUserName">Fred Farkas</p>
+
+Inserting HTML/XML::
+
+  <p tal:content="structure context/getStory">
+    marked <b>up</b> content goes here.
+  </p>
+
+define: Define variables
+========================
+
+Syntax
+++++++
+
+tal:define syntax::
+
+  argument       ::= define_scope [';' define_scope]*
+  define_scope   ::= (['local'] | 'global') define_var
+  define_var     ::= variable_name expression
+  variable_name  ::= Name
+
+*Note: If you want to include a semi-colon (;) in an `expression`, it must be
+escaped by doubling it (;;).*
+
+Description
++++++++++++
+
+The `tal:define` statement defines variables. You can define two different
+kinds of TAL variables: local and global. When you define a local variable in a
+statement element, you can only use that variable in that element and the
+elements it contains. If you redefine a local variable in a contained element,
+the new definition hides the outer element's definition within the inner
+element. When you define a global variables, you can use it in any element
+processed after the defining element. If you redefine a global variable, you
+replace its definition for the rest of the template.
+
+*Note: local variables are the default*
+
+If the expression associated with a variable evaluates to *nothing*, then that
+variable has the value *nothing*, and may be used as such in further
+expressions. Likewise, if the expression evaluates to *default*, then the
+variable has the value *default*, and may be used as such in further
+expressions.
+
+Examples
+++++++++
+
+Defining a global variable::
+
+  tal:define="global company_name string:Zope Corp, Inc."
+
+Defining two variables, where the second depends on the first::
+
+  tal:define="mytitle template/title; tlen python:len(mytitle)"
+
+
+omit-tag: Remove an element, leaving its contents
+=================================================
+
+Syntax
+++++++
+
+tal:omit-tag syntax::
+
+  argument ::= [ expression ]
+
+Description
++++++++++++
+
+The `tal:omit-tag` statement leaves the contents of an element in place while
+omitting the surrounding start and end tags.
+
+If the expression evaluates to a *false* value, then normal processing of the
+element continues and the tags are not omitted. If the expression evaluates to
+a *true* value, or no expression is provided, the statement element is replaced
+with its contents.
+
+Zope treats empty strings, empty sequences, zero, None, and *nothing* as false.
+All other values are considered true, including *default*.
+
+Examples
+++++++++
+
+Unconditionally omitting a tag::
+
+  <div tal:omit-tag="" comment="This tag will be removed">
+    <i>...but this text will remain.</i>
+  </div>
+
+Conditionally omitting a tag::
+
+  <b tal:omit-tag="not:bold">
+    I may be bold.
+  </b>
+
+The above example will omit the `b` tag if the variable `bold` is false.
+
+Creating ten paragraph tags, with no enclosing tag::
+
+  <span tal:repeat="n python:range(10)"
+        tal:omit-tag="">
+    <p tal:content="n">1</p>
+  </span>
+
+
+on-error: Handle errors
+=======================
+
+Syntax
+++++++
+
+tal:on-error syntax::
+
+  argument ::= (['text'] | 'structure') expression
+
+Description
++++++++++++
+
+The `tal:on-error` statement provides error handling for your template. When a
+TAL statement produces an error, the TAL interpreter searches for a
+`tal:on-error` statement on the same element, then on the enclosing element,
+and so forth. The first `tal:on-error` found is invoked. It is treated as a
+`tal:content` statement.
+
+A local variable `error` is set. This variable has these attributes:
+
+type
+  the exception type
+
+value
+  the exception instance
+
+traceback
+  the traceback object
+
+The simplest sort of `tal:on-error` statement has a literal error string or
+*nothing* for an expression. A more complex handler may call a script that
+examines the error and either emits error text or raises an exception to
+propagate the error outwards.
+
+Examples
+++++++++
+
+Simple error message::
+
+  <b tal:on-error="string: Username is not defined!" 
+     tal:content="context/getUsername">Ishmael</b>
+
+Removing elements with errors::
+
+  <b tal:on-error="nothing"
+     tal:content="context/getUsername">Ishmael</b>
+
+Calling an error-handling script::
+
+  <div tal:on-error="structure context/errorScript">
+  ...
+  </div>
+
+Here's what the error-handling script might look like::
+
+  ## Script (Python) "errHandler"
+  ##bind namespace=_
+  ##
+  error=_['error']
+  if error.type==ZeroDivisionError:
+      return "<p>Can't divide by zero.</p>"
+  else
+      return """<p>An error ocurred.</p>
+      <p>Error type: %s</p>
+      <p>Error value: %s</p>""" % (error.type, error.value)
+
+
+repeat: Repeat an element
+=========================
+
+Syntax
+++++++
+
+tal:repeat syntax::
+
+  argument      ::= variable_name expression
+  variable_name ::= Name
+
+Description
++++++++++++
+
+The `tal:repeat` statement replicates a sub-tree of your document once for each
+item in a sequence. The expression should evaluate to a sequence. If the
+sequence is empty, then the statement element is deleted, otherwise it is
+repeated for each value in the sequence. If the expression is *default*, then
+the element is left unchanged, and no new variables are defined.
+
+The `variable_name` is used to define a local variable and a repeat variable.
+For each repetition, the local variable is set to the current sequence element,
+and the repeat variable is set to an iteration object.
+
+Repeat Variables
+++++++++++++++++
+
+You use repeat variables to access information about the current repetition
+(such as the repeat index). The repeat variable has the same name as the local
+variable, but is only accessible through the built-in variable named `repeat`.
+
+
+The following information is available from the repeat variable:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- *index*- - repetition number, starting from zero.
+
+- *number*- - repetition number, starting from one.
+
+- *even*- - true for even-indexed repetitions (0, 2, 4, ...).
+
+- *odd*- - true for odd-indexed repetitions (1, 3, 5, ...).
+
+- *start*- - true for the starting repetition (index 0).
+
+- *end*- - true for the ending, or final, repetition.
+
+- *first*- - true for the first item in a group - see note below
+
+- *last*- - true for the last item in a group - see note below
+
+- *length*- - length of the sequence, which will be the total number of
+  repetitions.
+
+- *letter*- - repetition number as a lower-case letter: "a" - "z", "aa" - "az",
+  "ba" - "bz", ..., "za" - "zz", "aaa" - "aaz", and so forth.
+
+- *Letter*- - upper-case version of - *letter*- .
+
+- *roman*- - repetition number as a lower-case roman numeral: "i", "ii", "iii",
+  "iv", "v", etc.
+
+- *Roman*- - upper-case version of - *roman*- .
+
+You can access the contents of the repeat variable using path expressions or
+Python expressions. In path expressions, you write a three-part path consisting
+of the name `repeat`, the statement variable's name, and the name of the
+information you want, for example, `repeat/item/start`. In Python expressions,
+you use normal dictionary notation to get the repeat variable, then attribute
+access to get the information, for example, "python:repeat['item'].start".
+
+With the exception of `start`, `end`, and `index`, all of the attributes of a
+repeat variable are methods. Thus, when you use a Python expression to access
+them, you must call them, as in "python:repeat['item'].length()".
+
+Note that `first` and `last` are intended for use with sorted sequences. They
+try to divide the sequence into group of items with the same value. If you
+provide a path, then the value obtained by following that path from a sequence
+item is used for grouping, otherwise the value of the item is used. You can
+provide the path by passing it as a parameter, as in::
+
+  python:repeat['item'].first(color)
+  
+or by appending it to the path from the repeat variable, as in
+"repeat/item/first/color".
+
+Examples
+++++++++
+
+Iterating over a sequence of strings::
+
+  <p tal:repeat="txt python: ('one', 'two', 'three')">
+    <span tal:replace="txt" />
+  </p>
+
+Inserting a sequence of table rows, and using the repeat variable to number the
+rows::
+
+  <table>
+    <tr tal:repeat="item context/cart">
+      <td tal:content="repeat/item/number">1</td>
+      <td tal:content="item/description">Widget</td>
+      <td tal:content="item/price">$1.50</td>
+    </tr>
+  </table>
+
+Nested repeats::
+
+  <table border="1">
+    <tr tal:repeat="row python:range(10)">
+      <td tal:repeat="column python:range(10)">
+        <span tal:define="x repeat/row/number; 
+                          y repeat/column/number; 
+                          z python:x*y"
+              tal:replace="string:$x * $y = $z">
+            1 * 1 = 1
+        </span>
+      </td>
+    </tr>
+  </table>
+
+
+Insert objects. Separate groups of objects by meta-type by drawing a rule
+between them::
+
+  <div tal:repeat="object objects">
+    <h2 tal:condition="repeat/object/first/meta_type"
+        tal:content="object/meta_type">Meta Type</h2>
+    <p tal:content="object/getId">Object ID</p>
+    <hr tal:condition="repeat/object/last/meta_type" />
+  </div>
+
+Note, the objects in the above example should already be sorted by meta-type.
+
+replace: Replace an element
+===========================
+
+Syntax
+++++++
+
+tal:replace syntax::
+
+  argument ::= (['text'] | 'structure') expression
+
+Description
++++++++++++
+
+The `tal:replace` statement replaces an element with dynamic content. It
+replaces the statement element with either text or a structure (unescaped
+markup). The body of the statement is an expression with an optional type
+prefix. The value of the expression is converted into an escaped string if you
+prefix the expression with `text` or omit the prefix, and is inserted unchanged
+if you prefix it with `structure`. Escaping consists of converting "&amp;" to
+"&amp;amp;", "&lt;" to "&amp;lt;", and "&gt;" to "&amp;gt;".
+
+If the value is *nothing*, then the element is simply removed. If the value is
+*default*, then the element is left unchanged.
+
+Examples
+++++++++
+
+The two ways to insert the title of a template::
+
+  <span tal:replace="template/title">Title</span>
+  <span tal:replace="text template/title">Title</span>
+
+Inserting HTML/XML::
+
+  <div tal:replace="structure table" />
+
+Inserting nothing::
+
+  <div tal:replace="nothing">
+    This element is a comment.
+  </div>
+
+TALES Overview
+==============
+
+The *Template Attribute Language Expression Syntax* (TALES) standard describes
+expressions that supply TAL and METAL with data. TALES is *one* possible
+expression syntax for these languages, but they are not bound to this
+definition. Similarly, TALES could be used in a context having nothing to do
+with TAL or METAL.
+
+TALES expressions are described below with any delimiter or quote markup from
+higher language layers removed. Here is the basic definition of TALES syntax::
+
+  Expression  ::= [type_prefix ':'] String
+  type_prefix ::= Name
+
+Here are some simple examples::
+
+  a/b/c
+  path:a/b/c
+  nothing
+  path:nothing
+  python: 1 + 2
+  string:Hello, ${user/getUserName}
+
+The optional *type prefix* determines the semantics and syntax of the
+*expression string* that follows it. A given implementation of TALES can define
+any number of expression types, with whatever syntax you like. It also
+determines which expression type is indicated by omitting the prefix.
+
+If you do not specify a prefix, Zope assumes that the expression is a *path*
+expression.
+
+TALES Expression Types
+++++++++++++++++++++++
+
+These are the TALES expression types supported by Zope:
+
+- path expressions - locate a value by its path.
+
+- exists expressions - test whether a path is valid.
+
+- nocall expressions - locate an object by its path.
+
+- not expressions - negate an expression
+
+- string expressions - format a string
+
+- python expressions - execute a Python expression
+
+Built-in Names
+++++++++++++++
+
+These are the names always available to TALES expressions in Zope:
+
+- *nothing*- - special value used by to represent a - *non-value*- (e.g. void,
+  None, Nil, NULL).
+
+- *default*- - special value used to specify that existing text should not be
+  replaced. See the documentation for individual TAL statements for details on
+  how they interpret - *default*- .
+
+- *options*- - the - *keyword*- arguments passed to the template. These are
+  generally available when a template is called from Methods and Scripts,
+  rather than from the web.
+
+- *repeat*- - the repeat variables; see the tal:repeat documentation.
+
+- *attrs*- - a dictionary containing the initial values of the attributes of
+  the current statement tag.
+
+- *CONTEXTS*- - the list of standard names (this list). This can be used to
+  access a built-in variable that has been hidden by a local or global variable
+  with the same name.
+
+- *root*- - the system's top-most object: the Zope root folder.
+
+- *context*- - the object to which the template is being applied.
+
+- *container*- - The folder in which the template is located.
+
+- *template*- - the template itself.
+
+- *request*- - the publishing request object.
+
+- *user*- - the authenticated user object.
+
+- *modules*- - a collection through which Python modules and packages can be
+  accessed. Only modules which are approved by the Zope security policy can be
+  accessed.
+
+Note the names `root`, `context`, `container`, `template`, `request`, `user`, and
+`modules` are optional names supported by Zope, but are not required by the
+TALES standard.
+
+TALES Exists expressions
+========================
+
+Syntax
+++++++
+
+Exists expression syntax::
+
+  exists_expressions ::= 'exists:' path_expression
+
+Description
++++++++++++
+
+Exists expressions test for the existence of paths. An exists expression
+returns true when the path expressions following it expression returns a value.
+It is false when the path expression cannot locate an object.
+
+Examples
+++++++++
+
+Testing for the existence of a form variable::
+
+  <p tal:condition="not:exists:request/form/number">
+    Please enter a number between 0 and 5
+  </p>
+
+Note that in this case you can't use the expression, `not:request/form/number`,
+since that expression will be true if the `number` variable exists and is zero.
+
+TALES Nocall expressions
+========================
+
+Syntax
+++++++
+
+Nocall expression syntax::
+
+  nocall_expression ::= 'nocall:' path_expression
+
+Description
++++++++++++
+
+Nocall expressions avoid rendering the results of a path expression.
+
+An ordinary path expression tries to render the object that it fetches. This
+means that if the object is a function, Script, Method, or some other kind of
+executable thing, then expression will evaluate to the result of calling the
+object. This is usually what you want, but not always. For example, if you want
+to put a DTML Document into a variable so that you can refer to its properties,
+you can't use a normal path expression because it will render the Document into
+a string.
+
+Examples
+++++++++
+
+Using nocall to get the properties of a document::
+
+  <span tal:define="doc nocall:context/aDoc"
+        tal:content="string:${doc/getId}: ${doc/title}">
+    Id: Title
+  </span>
+
+Using nocall expressions on a functions::
+
+  <p tal:define="join nocall:modules/string/join">
+
+This example defines a variable:: `join` which is bound to the `string.join`
+function.
+
+TALES Not expressions
+=====================
+
+Syntax
+++++++
+
+Not expression syntax::
+
+  not_expression ::= 'not:' expression
+
+Description
++++++++++++
+
+Not expression evaluates the expression string (recursively) as a full
+expression, and returns the boolean negation of its value. If the expression
+supplied does not evaluate to a boolean value, *not* will issue a warning and
+*coerce* the expression's value into a boolean type based on the following
+rules:
+
+1. the number 0 is *false*
+
+2. positive and negative numbers are *true*
+
+3. an empty string or other sequence is *false*
+
+4. a non-empty string or other sequence is *true*
+
+5. a #. *non-value*#. (e.g. void, None, Nil, NULL, etc) is *false*
+
+6. all other values are implementation-dependent.
+
+If no expression string is supplied, an error should be generated.
+
+Zope considers all objects not specifically listed above as *false* to be
+*true*.
+
+Examples
+++++++++
+
+Testing a sequence::
+
+  <p tal:condition="not:context/objectIds">
+    There are no contained objects.
+  </p>
+
+TALES Path expressions
+======================
+
+Syntax
+++++++
+
+Path expression syntax::
+
+  PathExpr    ::= Path [ '|' Expression ]
+  Path        ::= variable [ '/' PathSegment ]*
+  variable    ::= Name
+  PathSegment ::= ( '?' variable ) | PathChar+
+  PathChar    ::= AlphaNumeric | ' ' | '_' | '-' | '.' | ',' | '~'
+
+Description
++++++++++++
+
+A path expression consists of a *path* optionally followed by a vertical bar
+(|) and alternate expression. A path consists of one or more non-empty strings
+separated by slashes. The first string must be a variable name (a built-in
+variable or a user defined variable), and the remaining strings, the *path
+segments*, may contain letters, digits, spaces, and the punctuation characters
+underscore, dash, period, comma, and tilde.
+
+A limited amount of indirection is possible by using a variable name prefixed
+with `?` as a path segment. The variable must contain a string, which replaces
+that segment before the path is traversed.
+
+For example::
+
+  request/cookies/oatmeal
+  nothing
+  context/some-file 2009_02.html.tar.gz/foo
+  root/to/branch | default
+  request/name | string:Anonymous Coward
+  context/?tname/macros/?mname
+
+When a path expression is evaluated, Zope attempts to traverse the path, from
+left to right, until it succeeds or runs out of paths segments. To traverse a
+path, it first fetches the object stored in the variable. For each path
+segment, it traverses from the current object to the sub-object named by the
+path segment. Sub-objects are located according to standard Zope traversal rules
+(via getattr, getitem, or traversal hooks).
+
+Once a path has been successfully traversed, the resulting object is the value
+of the expression. If it is a callable object, such as a method or template, it
+is called.
+
+If a traversal step fails, and no alternate expression has been specified, an
+error results. Otherwise, the alternate expression is evaluated.
+
+The alternate expression can be any TALES expression. For example::
+
+  request/name | string:Anonymous Coward
+
+is a valid path expression. This is useful chiefly for providing default
+values, such as strings and numbers, which are not expressible as path
+expressions. Since the alternate expression can be a path expression, it is
+possible to "chain" path expressions, as in::
+
+  first | second | third | nothing
+
+If no path is given the result is *nothing*.
+
+Since every path must start with a variable name, you need a set of starting
+variables that you can use to find other objects and values. See the TALES
+overview for a list of built-in variables. Variable names are looked up first
+in locals, then in globals, then in the built-in list, so the built-in
+variables act just like built-ins in Python; They are always available, but
+they can be shadowed by a global or local variable declaration. You can always
+access the built-in names explicitly by prefixing them with *CONTEXTS*. (e.g.
+CONTEXTS/root, CONTEXTS/nothing, etc).
+
+Examples
+++++++++
+
+Inserting a cookie variable or a property::
+
+  <span tal:replace="request/cookies/pref | context/pref">
+    preference
+  </span>
+
+Inserting the user name::
+
+  <p tal:content="user/getUserName">
+    User name
+  </p>
+
+TALES Python expressions
+========================
+
+Syntax
+++++++
+
+Python expression syntax::
+
+  Any valid Python language expression
+
+Description
++++++++++++
+
+Python expressions evaluate Python code in a security-restricted environment.
+Python expressions offer the same facilities as those available in Python-based
+Scripts and DTML variable expressions.
+
+Security Restrictions
+~~~~~~~~~~~~~~~~~~~~~
+
+Python expressions are subject to the same security restrictions as
+Python-based scripts. These restrictions include:
+
+
+access limits
+  Python expressions are subject to Zope permission and role security
+  restrictions. In addition, expressions cannot access objects whose names
+  begin with underscore.
+
+write limits
+  Python expressions cannot change attributes of Zope objects.
+
+Despite these limits malicious Python expressions can cause problems.
+
+Built-in Functions
+~~~~~~~~~~~~~~~~~~
+
+Python expressions have the same built-ins as Python-based Scripts with a few
+additions.
+
+These standard Python built-ins are available:
+
+- None
+
+- abs
+
+- apply
+
+- callable
+
+- chr
+
+- cmp
+
+- complex
+
+- delattr
+
+- divmod
+
+- filter
+
+- float
+
+- getattr
+
+- hash
+
+- hex
+
+- int
+
+- isinstance
+
+- issubclass
+
+- list
+
+- len
+
+- long
+
+- map
+
+- max
+
+- min
+
+- oct
+
+- ord
+
+- repr
+
+- round
+
+- setattr
+
+- str
+
+- tuple
+
+The `range` and `pow` functions are available and work the same way they do in
+standard Python; however, they are limited to keep them from generating very
+large numbers and sequences. This limitation helps protect against denial of
+service attacks.
+
+These functions are available in Python expressions, but not in Python-based
+scripts:
+
+path(string)
+  Evaluate a TALES path expression.
+
+string(string)
+  Evaluate a TALES string expression.
+
+exists(string)
+  Evaluates a TALES exists expression.
+
+nocall(string)
+  Evaluates a TALES nocall expression.
+
+Python Modules
+~~~~~~~~~~~~~~
+
+A number of Python modules are available by default. You can make more modules
+available. You can access modules either via path expressions (for example
+`modules/string/join`) or in Python with the `modules` mapping object (for
+example `modules["string"].join`). Here are the default modules:
+
+string
+  The standard `Python string module
+  <http://www.python.org/doc/current/lib/module-string.html>`_ Note: most of
+  the functions in the module are also available as methods on string objects.
+
+random
+
+The standard 
+  `Python random module
+  <http://www.python.org/doc/current/lib/module-random.html>`_
+
+math
+  The standard `Python math module
+  <http://www.python.org/doc/current/lib/module-math.html>`_ .
+
+sequence
+  A module with a powerful sorting function. See sequence for more information.
+
+Products.PythonScripts.standard
+  Various HTML formatting functions available in DTML. See
+  Products.PythonScripts.standard for more information.
+
+ZTUtils
+  Batch processing facilities similar to those offered by `dtml-in`. See
+  ZTUtils for more information.
+
+AccessControl
+  Security and access checking facilities. See AccessControl for more
+  information.
+
+Examples
+++++++++
+
+Using a module usage (pick a random choice from a list)::
+
+  <span tal:replace="python:modules['random'].choice(
+                         ['one', 'two', 'three', 'four', 'five'])">
+    a random number between one and five
+  </span>
+
+String processing (capitalize the user name)::
+
+  <p tal:content="python:user.getUserName().capitalize()">
+    User Name
+  </p>
+
+Basic math (convert an image size to megabytes)::
+
+  <p tal:content="python:image.getSize() / 1048576.0">
+    12.2323
+  </p>
+
+String formatting (format a float to two decimal places)::
+
+  <p tal:content="python:'%0.2f' % size">
+    13.56
+  </p>
+
+TALES String expressions
+========================
+
+Syntax
+++++++
+
+String expression syntax::
+
+  string_expression ::= ( plain_string | [ varsub ] )*
+  varsub            ::= ( '$' Path ) | ( '${' Path '}' )
+  plain_string      ::= ( '$$' | non_dollar )*
+  non_dollar        ::= any character except '$'
+
+Description
++++++++++++
+
+String expressions interpret the expression string as text. If no expression
+string is supplied the resulting string is *empty*. The string can contain
+variable substitutions of the form `$name` or `${path}`, where `name` is a
+variable name, and `path` is a path expression. The escaped string value of the
+path expression is inserted into the string. To prevent a `$` from being
+interpreted this way, it must be escaped as `$$`.
+
+Examples
+++++++++
+
+Basic string formatting::
+
+  <span tal:replace="string:$this and $that">
+    Spam and Eggs
+  </span>
+
+Using paths::
+
+  <p tal:content="string:total: ${request/form/total}">
+    total: 12
+  </p>
+
+Including a dollar sign::
+
+  <p tal:content="string:cost: $$$cost">
+    cost: $42.00
+  </p>
+
+METAL Overview
+==============
+
+The *Macro Expansion Template Attribute Language* (METAL) standard is a
+facility for HTML/XML macro preprocessing. It can be used in conjunction with
+or independently of TAL and TALES.
+
+Macros provide a way to define a chunk of presentation in one template, and
+share it in others, so that changes to the macro are immediately reflected in
+all of the places that share it. Additionally, macros are always fully
+expanded, even in a template's source text, so that the template appears very
+similar to its final rendering
+
+METAL Namespace
++++++++++++++++
+
+The METAL namespace URI and recommended alias are currently defined as::
+
+  xmlns:metal="http://xml.zope.org/namespaces/metal"
+
+Just like the TAL namespace URI, this URI is not attached to a web page; it's
+just a unique identifier.
+
+Zope does not require an XML namespace declaration when creating templates with
+a content-type of `text/html`. However, it does require an XML namespace
+declaration for all other content-types.
+
+METAL Statements
+++++++++++++++++
+
+METAL defines a number of statements:
+
+- metal:define-macro - Define a macro.
+
+- metal:use-macro - Use a macro.
+
+- metal:define-slot - Define a macro customization point.
+
+- metal:fill-slot - Customize a macro.
+
+Although METAL does not define the syntax of expression non-terminals, leaving
+that up to the implementation, a canonical expression syntax for use in METAL
+arguments is described in TALES Specification.
+
+define-macro: Define a macro
+============================
+
+Syntax
+++++++
+
+metal:define-macro syntax::
+
+  argument ::= Name
+
+Description
++++++++++++
+
+The `metal:define-macro` statement defines a macro. The macro is named by the
+statement expression, and is defined as the element and its sub-tree.
+
+In Zope, a macro definition is available as a sub-object of a template's
+`macros` object. For example, to access a macro named `header` in a template
+named `master.html`, you could use the path expression::
+
+  master.html/macros/header
+
+Examples
+++++++++
+
+Simple macro definition::
+
+  <p metal:define-macro="copyright">
+    Copyright 2009, <em>Foobar</em> Inc.
+  </p>
+
+
+define-slot: Define a macro customization point
+===============================================
+
+Syntax
+++++++
+
+metal:define-slot syntax::
+
+  argument ::= Name
+
+Description
++++++++++++
+
+The `metal:define-slot` statement defines a macro customization point or
+*slot*. When a macro is used, its slots can be replaced, in order to customize
+the macro. Slot definitions provide default content for the slot. You will get
+the default slot contents if you decide not to customize the macro when using
+it.
+
+The `metal:define-slot` statement must be used inside a `metal:define-macro`
+statement.
+
+Slot names must be unique within a macro.
+
+Examples
+++++++++
+
+Simple macro with slot::
+
+  <p metal:define-macro="hello">
+    Hello <b metal:define-slot="name">World</b>
+  </p>
+
+This example defines a macro with one slot named `name`. When you use this
+macro you can customize the `b` element by filling the `name` slot.
+
+fill-slot: Customize a macro
+============================
+
+Syntax
+++++++
+
+metal:fill-slot syntax::
+
+  argument ::= Name
+
+Description
++++++++++++
+
+The `metal:fill-slot` statement customizes a macro by replacing a *slot* in the
+macro with the statement element (and its content).
+
+The `metal:fill-slot` statement must be used inside a `metal:use-macro`
+statement. Slot names must be unique within a macro.
+
+If the named slot does not exist within the macro, the slot contents will be
+silently dropped.
+
+Examples
+++++++++
+
+Given this macro::
+
+  <p metal:define-macro="hello">
+    Hello <b metal:define-slot="name">World</b>
+  </p>
+
+You can fill the `name` slot like so::
+
+  <p metal:use-macro="container/master.html/macros/hello">
+    Hello <b metal:fill-slot="name">Kevin Bacon</b>
+  </p>
+
+use-macro: Use a macro
+======================
+
+Syntax
+++++++
+
+metal:use-macro syntax::
+
+  argument ::= expression
+
+Description
++++++++++++
+
+The `metal:use-macro` statement replaces the statement element with a macro.
+The statement expression describes a macro definition.
+
+In Zope the expression will generally be a path expression referring to a macro
+defined in another template. See "metal:define-macro" for more information.
+
+The effect of expanding a macro is to graft a subtree from another document (or
+from elsewhere in the current document) in place of the statement element,
+replacing the existing sub-tree. Parts of the original subtree may remain,
+grafted onto the new subtree, if the macro has *slots*. See metal:define-slot
+for more information. If the macro body uses any macros, they are expanded
+first.
+
+When a macro is expanded, its `metal:define-macro` attribute is replaced with
+the `metal:use-macro` attribute from the statement element. This makes the root
+of the expanded macro a valid `use-macro` statement element.
+
+Examples
+++++++++
+
+Basic macro usage::
+
+  <p metal:use-macro="container/other.html/macros/header">
+    header macro from defined in other.html template
+  </p>
+
+This example refers to the `header` macro defined in the `other.html` template
+which is in the same folder as the current template. When the macro is
+expanded, the `p` element and its contents will be replaced by the macro. Note:
+there will still be a `metal:use-macro` attribute on the replacement element.
+
+ZPT-specific Behaviors
+======================
+
+The behavior of Zope Page Templates is almost completely described by the TAL,
+TALES, and METAL specifications. ZPTs do, however, have a few additional
+features that are not described in the standards.
+
+HTML Support Features
++++++++++++++++++++++
+
+When the content-type of a Page Template is set to `text/html`, Zope processes
+the template somewhat differently than with any other content-type. As
+mentioned under TAL Namespace, HTML documents are not required to declare
+namespaces, and are provided with `tal` and `metal` namespaces by default.
+
+HTML documents are parsed using a non-XML parser that is somewhat more
+forgiving of malformed markup. In particular, elements that are often written
+without closing tags, such as paragraphs and list items, are not treated as
+errors when written that way, unless they are statement elements. This laxity
+can cause a confusing error in at least one case; a `<div>` element is
+block-level, and therefore technically not allowed to be nested in a `<p>`
+element, so it will cause the paragraph to be implicitly closed. The closing
+`</p>` tag will then cause a NestingError, since it is not matched up with the
+opening tag. The solution is to use `<span>` instead.
+
+Unclosed statement elements are always treated as errors, so as not to cause
+subtle errors by trying to infer where the element ends. Elements which
+normally do not have closing tags in HTML, such as image and input elements,
+are not required to have a closing tag, or to use the XHTML `<tag />` form.
+
+Certain boolean attributes, such as `checked` and `selected`, are treated
+differently by `tal:attributes`. The value is treated as true or false (as
+defined by `tal:condition`). The attribute is set to `attr="attr"` in the true
+case and omitted otherwise. If the value is `default`, then it is treated as
+true if the attribute already exists, and false if it does not. For example,
+each of the following lines::
+
+  <input type="checkbox" checked tal:attributes="checked default">
+  <input type="checkbox" tal:attributes="checked string:yes">
+  <input type="checkbox" tal:attributes="checked python:42">
+
+will render as::
+
+  <input type="checkbox" checked="checked">
+
+while each of these::
+
+  <input type="checkbox" tal:attributes="checked default">
+  <input type="checkbox" tal:attributes="checked string:">
+  <input type="checkbox" tal:attributes="checked nothing">
+
+will render as::
+
+  <input type="checkbox">
+
+This works correctly in all browsers in which it has been tested.
+

Copied: zope2docs/branches/baijum-reorganize/zope2book/AppendixD.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/AppendixD.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/AppendixD.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/AppendixD.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,72 @@
+Appendix D: Zope Resources
+##########################
+
+At the time of this writing there is a multitude of sources for Zope
+information on the Internet and in print. We've collected a number of the most
+important links which you can use to find out more about Zope.
+
+Zope Web Sites
+==============
+
+`Zope.org <http://www.zope.org>`_ is the official Zope website. It has
+downloads, documentation, news, and lots of community resources.
+
+`DZUG <http://dzug.org/>`_ was started as the main community site for the
+German Zope community and combines documentation translated to German,
+downloads, a portal for the various regional German Zope User Groups as well as
+information about Zope-related events in Europe.
+
+`Zope Italia <http://www.zope.it/>`_ forms the focal point for the Italian Zope
+community with news, events information and local Zope group contacts.
+
+Zope Documentation
+==================
+
+`ZopeWiki - A wiki for the Zope community <http://zopewiki.org/>`_ is a
+community-run Zope documentation website set up by Simon Michael, author of the
+famus ZWiki wiki product for Zope.
+
+`Zope Developer's Guide <http://www.zope.org/DocProjects/DevGuide>`_ teaches
+you how to write Zope products. It is somewhat outdated but cotains some
+nuggets you don't find elsewhere.
+
+(Other) Zope Books
+==================
+
+`The Zope Bible
+<http://www.amazon.com/exec/obidos/ASIN/0764548573/qid=1030511472/sr=2-1/ref=sr_2_1/002-3988880-4512056>`_
+by Scott Robertson and Michael Bernstein.
+
+`The Book of Zope
+<http://www.amazon.com/exec/obidos/ASIN/1886411573/qid=1030511472/sr=2-2/ref=sr_2_2/002-3988880-4512056>`_
+by Beehive.
+
+`The Zope Web Application Construction Kit
+<http://www.amazon.com/exec/obidos/tg/detail/-/0672321335/qid=1030511472/sr=1-5/ref=sr_1_5/002-3988880-4512056?v=glance&amp;s=books>`_
+edited by Martina Brockman, et. al.
+
+`Zope: Web Application Development and Content Management
+<http://www.amazon.com/exec/obidos/tg/detail/-/0735711100/qid=1030511472/sr=1-2/ref=sr_1_2/002-3988880-4512056?v=glance&amp;s=books>`_
+edited by Steve Spicklemire et al.
+
+`Zope: Timely, Practical, Reliable
+<http://www.amazon.com/exec/obidos/tg/detail/-/0470844515/ref=ase_zopezone-20/102-5632760-7919306?v=glance&s=books>`_
+written by Pierre Julien Grizel.
+
+`The Zope Book
+<http://www.amazon.com/exec/obidos/ASIN/0735711372/zopezone-20/102-5632760-7919306>`_
+is the hardcover version of the original edition Zope Book on which this text
+is based.
+
+Mailing Lists
+=============
+
+`mail.zope.org <http://www.zope.org/Resources/MailingLists>`_ maintains a collection
+of the many Zope mailing lists.
+
+Python Information
+==================
+
+`Python.org <http://www.python.org>`_ has lots of information about Python
+including a tutorial and reference documentation.
+

Copied: zope2docs/branches/baijum-reorganize/zope2book/AppendixE.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/AppendixE.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/AppendixE.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/AppendixE.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,49 @@
+Appendix E: DTML Name Lookup Rules
+##################################
+
+These are the rules which DTML uses to resolve names mentioned in `name=` and
+`expr=` tags. The rules are in order from first to last in the search path.
+
+The DTML call signature is as follows::
+
+  def __call__(client=None, mapping={}, **kw)
+
+The `client` argument is typically unreferenced in the body of DTML text, but
+typically resolves to the "context" in which the method was called (for
+example, in the simplest case, its client is the folder in which it lives).
+
+The `mapping` argument is typically referred to as `_` in the body of DTML
+text.
+
+The keyword arguments (i.e. `**kw` ) are referred to by their respective names
+in the body of DTML text.
+
+1. The keyword arguments are searched.
+
+2. The mapping object is searched.
+
+3. Attributes of the client, including inherited and acquired attributes, are
+   searched.
+
+4. If DTML is used in a Zope DTML Method or Document object and the variable
+   name is `document_id` or `document_title`, then the id or title of the
+   document or method is used.
+
+5. Attributes of the folder containing the DTML object (its container) are
+   searched. Attributes include objects in the contents of the folder,
+   properties of the folder, and other attributes defined by Zope, such as
+   `ZopeTime`. Folder attributes include the attributes of folders containing
+   the folder, with contained folders taking precedence over containing
+   folders.
+
+6. User-defined Web-request variables (ie. in the REQUEST.other namespace) are
+   searched.
+
+7. Form-defined Web-request variables (ie. in the REQUEST.form namespace) are
+   searched.
+
+8. Cookie-defined Web-request variables (ie. in the REQUEST.cookies namespace)
+   are searched.
+
+9. CGI-defined Web-request variables (ie. in the REQUEST.environ namespace) are
+   searched.

Copied: zope2docs/branches/baijum-reorganize/zope2book/BasicObject.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/BasicObject.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/BasicObject.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/BasicObject.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,688 @@
+Using Basic Zope Objects
+########################
+
+When building a web application with Zope, you construct the application
+with *objects*.  The most fundamental Zope objects are explained in this
+chapter.
+
+Basic Zope Objects
+==================
+
+Zope ships with objects that help you perform different tasks. By design,
+different objects handle different parts of your application.  Some objects
+hold your content data, such as word processor documents, spreadsheets, and
+images.  Some objects handle your application's logic by accepting input
+from a web form, or by executing a script.  Some objects control the way
+your content is displayed, or *presented* to your viewer, for example, as a
+web page or via email.
+
+In general, basic Zope objects take on one of three types of roles:
+
+Content
+  Zope objects like documents, images, and files hold different kinds of
+  textual and binary data.  In addition to objects in Zope containing
+  content, Zope can work with content stored externally, such as
+  information in a relational database.
+
+Presentation
+  You can control the look and feel of your site with Zope objects that act
+  as web page "templates". Zope comes with two facilities to help you
+  manage presentation: Zope Page Templates (ZPT) and Document Templates
+  (DTML). In the first part of the book we will only cover page templates
+  and later on expand on document templates. If you already know HTML, page
+  templates are easier to work with and more limited in their options. For
+  some of the more advanced tasks DTML can be a better option as explained
+  later on.
+
+Logic
+  Scripting business logic in Zope is done using Python. "Logic" is any kind of
+  programming that does not involve presentation, but rather involves the
+  carrying out of tasks such as changing objects, sending messages, testing
+  conditions, and responding to events.
+
+Zope also has other kinds of objects that fit into none of these categories,
+which are explored further in the chapter entitled `Zope Services
+<ZopeServices.html>`_. You may also install "third party" Zope objects ,
+defined in Python packages, to expand Zope's capabilities. You can browse a
+list of packages specifically aimed at Zope at the
+`Python Package Index <http://pypi.python.org/pypi?:action=browse&c=514>`_.
+
+
+Content Objects: Folders, Files, and Images
+===========================================
+
+Folders
+-------
+
+You've already met one of the fundamental Zope objects: the *Folder*.
+Folders are the basic building blocks of Zope. The purpose of a folder is
+simple: a Folder's only job in life is to *contain* other objects.
+
+Folders can contain any other kind of Zope object, including other folders.
+You can nest folders inside each other to form a tree of folders.  This
+kind of "folder within a folder" arrangement provides your Zope site with
+*structure*.  Good structure is very important, as Zope security and
+presentation is influenced by your site's folder structure.  Folder
+structure should be very familiar to anyone who has worked with files and
+folders on their computer using a file manager like Microsoft *Windows
+Explorer*.
+
+Files
+-----
+
+Zope Files contain raw data, just as the files on your computer do.
+Software, audio, video and documents are typically transported around the
+Internet and the world as files. A Zope File object is an analogue to these
+kinds of files.  You can use Files to hold any kind of information that
+Zope doesn't specifically support, such as Flash files, audio files,
+"tarballs", etc. 
+
+Files do not consider their contents to be of any special format, textual
+or otherwise.  Files are good for holding any kind of *binary content*,
+which is just raw computer information of some kind. Files are also good
+for holding textual content if the content doesn't necessarily need to be
+edited through the web.
+
+Every File object has a particular *content type*, which is a standard
+Internet MIME designation for different categories of content. Examples of
+content types are "text/plain" (plain text content), "text/html" (html text
+content), and "application/pdf" (an Adobe Portable Document Format file).
+When you upload a file into Zope, Zope tries to guess the content type from
+the name of the file.
+
+Creating and Editing Files
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To create a File object in your Zope instance, visit the root folder in the
+ZMI and choose *File* from Zope's Add list.  Before filling out the "id" or
+"title" of the File object, click the *Browse* button from the resulting
+"Add File" screen.  This should trigger your browser to display a dialog
+box that allows you to choose a "real" file from your local computer, which
+will be uploaded to Zope when the "Add" button on the "Add File" form is
+selected.  Try choosing a file on your local computer, such as a Word file
+(.doc) or a Portable Document Format (.pdf) file.
+
+.. figure:: Figures/addfile.jpg
+
+   Adding a PDF File Object
+
+Zope attempts to use the filename of the file you choose to upload as the
+File object's 'id' and 'title', thus you don't need to supply an 'id' or
+'title' in the "Add File" form unless you want the File object to be named
+differently than the filename of the file on your local computer.  After
+you select a file to upload, click *Add*.  Depending on the size of the
+file you want to upload, it may take a few minutes to add the file to Zope.
+
+After you add the File, a File object with the name of the file on your
+local computer will appear in the Workspace pane.  Look at its *Edit* view.
+Here you will see that Zope has guessed the content type, as shown in the
+figure below.
+
+.. figure:: Figures/fileobject.jpg
+
+   Editing an Uploaded PDF File Object
+
+If you add a Word document, the content type is *application/msword*.  If
+you add a PDF file, the content type is *application/pdf*.  If Zope does
+not recognize the file type, it chooses the default, generic content type
+of *application/octet-stream*.  Zope doesn't always guess correctly, so the
+ability to change the content type of a File object is provided in the
+object editing interface.  To change the content type of a File object,
+type the new content type into the *Content Type* field and click the *Save
+Changes* button.
+
+You can change the contents of an existing File object by selecting a new
+file from your local filesystem in the *File Data* form element and
+clicking *Upload*.
+
+Editing Text File Contents
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If your File holds only text and is smaller than 64 kilobytes, Zope will
+allow you to edit its contents in a textarea within the Edit view of the
+ZMI. A text file is one that has a content-type that starts with *text/*,
+such as *text/html*, or *text/plain*.
+
+Viewing Files
+~~~~~~~~~~~~~
+
+You can view a file in the Workspace frame by clicking the *View* tab in a
+File object's management screen. 
+
+.. figure:: Figures/viewingfile.jpg
+
+   Viewing an Uploaded PDF File Object
+
+You can also view a File by visiting its Zope URL.  For example, if you
+have a file in your Zope root folder called *Reader.pdf*, you can view that
+file in your web browser via the URL *http://localhost:8080/Reader.pdf*.
+Depending on the type of file and your web browser's configuration, your
+web browser may choose to display or download the file.
+
+Images 
+------
+
+Image objects contain the data from image files, such as GIF, JPEG, and PNG
+files. In Zope, Images are very similar to File objects, except that they
+include extra behavior for managing graphic content, such as an image's
+width and height attributes.
+
+Image objects use the same management interface as File objects.
+Everything in the previous section about using file objects also applies to
+images. In addition, Image objects display a preview of their images once
+they have been uploaded to Zope.
+
+Presentation Objects:  Zope Page Templates
+==========================================
+
+Zope encourages you to keep your presentation and logic separate by
+providing different objects that are intended to be used expressly for
+"presentation".  "Presentation" is defined as the task of dynamically
+defining layout of web pages and other user-visible data.  Presentation
+objects typically render HTML (and sometimes XML).
+
+Zope has one "presentation" facility: *Zope Page Templates* (ZPT). Zope Page
+Templates are objects that allow you to define dynamic presentation for a web
+page. The HTML in your template is made dynamic by inserting special XML
+namespace elements into your HTML that define the dynamic behavior for that
+page.
+
+ZPT has characteristics of a "server-side" scripting language, like SSI, PHP or
+JSP. This means that ZPT commands are executed by Zope on the server, and the
+result of that execution is sent to your web browser. By contrast, client-side
+scripting languages, like Javascript, are not processed by the server, but are
+rather sent to and executed by your web browser.
+
+Zope also has an older version of a presentation facility included, which is
+called *Document Template Markup Language* or short DTML.
+
+ZPT vs. DTML: Same Purpose, Different Approach
+----------------------------------------------
+
+There is a major problem with many languages designed for the purpose of
+creating dynamic HTML content: they don't allow for "separation of
+presentation and logic" very well.  For example, "tag-based" scripting
+languages, like DTML, SSI, PHP, and JSP, encourage programmers to embed
+special tags into HTML that are, at best, mysterious to graphics designers
+who "just want to make the page look good" and don't know (or want to
+know!) a lot about creating an application around the HTML that they
+generate.  Worse, these tags can sometimes cause the HTML on which the
+designer has been working to become "invalid" HTML, unrecognizable by any
+of his or her tools.
+
+Typically, when using these kinds of technologies, an HTML designer will
+"mock up" a page in a tool like Macromedia Dreamweaver or Adobe GoLive, and
+then hand it off to a web programmer, who will decorate the page with
+special tags to insert dynamic content.  However, using tag-based scripting
+languages, this is a "one way" workflow: if the presentation ever needs to
+change, the programmer cannot just hand back the page that has been
+"decorated" with the special tags, because these tags will often be ignored
+or stripped out by the designer's tools.  One of several things needs to
+happen at this point to enact the presentation changes:
+
+- the designer mocks up a new page and the programmer re-embeds the dynamic
+  tags "from scratch", or
+
+- the designer hand-edits the HTML, working around the dynamic tags, or
+
+- the programmer does the presentation himself.
+
+Clearly, none of these options are desirable, because neither the
+programmer nor the designer are doing the things that they are best at in
+the most efficient way.
+
+Zope's original dynamic presentation language was DTML.  It soon became
+apparent that DTML was great at allowing programmers to quickly generate
+dynamic web pages, but it failed to allow programmers to work
+effectively together with non-technical graphics designers.  Thus, ZPT was
+born.  ZPT is an "attribute-based" presentation language that tries to
+allow for the "round-tripping" of templates between programmers and
+non-technical designers.
+
+DTML is still fully supported in Zope. If you are familiar with PHP it might
+fit your mind better then ZPT. For some of the advanced topics covered later
+in the book, like relation database integration or more uncommon tasks like
+dynamic generation of non-xml files, DTML can be easier to work with.
+
+Zope Page Templates
+-------------------
+
+Zope Page Templates (ZPTs) are typically used to create dynamic HTML pages.
+
+Creating a Page Template
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Create a Folder with the 'id' *Sales* in the root folder, and give it any
+title you like.  Enter the Sales folder by clicking on it, then select
+*Page Template* from the Add list.  The Add form for a page template will
+be displayed.  Specify the 'id' "SalesPage" and click *Add*.  You have
+successfully created a page template whose content is standard
+"boilerplate" text at this point.
+
+Editing a Page Template
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The easiest way to edit a page template is by clicking on its name or icon
+in the ZMI.  When you click on either one of those items, you are taken to
+the *Edit* view of the page template, which displays a textarea in which
+you can edit the template.  Click on the "SalesPage" template.  You will
+see something like the following screen:
+
+.. figure:: Figures/salespage.jpg
+
+   Default Page Template Content
+
+Replace the original, boilerplate content included in the page template
+with the following HTML::
+
+  <html>
+    <body>
+      <h1>This is my first page template!</h1>
+    </body>
+  </html>
+
+Then click *Save Changes* at the bottom of the edit form.
+
+Uploading a Page Template
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you'd prefer not to edit your HTML templates in a web browser, or you
+have some existing HTML pages that you'd like to bring into Zope, Zope
+allows you to upload your existing html files and convert them to page
+templates.
+
+Create a text file on your local computer named 'upload_pt.html'.  Populate
+it with the following content::
+
+  <html>
+    <body>
+      <h1>This is my second page template!</h1>
+    </body>
+  </html>
+
+While in the Sales folder, choose *Page Template* from the add menu, which
+will cause the page template Add form to be displayed.  The last form
+element on the add form is the *Browse* button.  Click this button, and
+your browser will display a file selection dialog.  CHoose the
+'upload_pt.html' file, type in an 'id' of "upload_pt" for the new Page
+Template, and click *Add and Edit*.  After uploading your file, you will be
+taken back to the Edit form of your new page template.
+
+Viewing a Page Template
+~~~~~~~~~~~~~~~~~~~~~~~
+
+You can view a Page Template in the Workspace frame by clicking the *Test*
+tab from the template's management screen.  Click the *Test* tab of the
+SalesPage template, and you will see something like the following figure:
+
+.. figure:: Figures/viewingpt.png
+
+   Viewing a Page Template
+
+You can also view a Page Template by visiting its Zope URL directly.
+
+
+Logic Objects:  Script (Python) Objects
+=======================================
+
+"Logic" objects in Zope are objects that typically perform some sort of
+"heavy lifting" or "number crunching" in support of presentation objects.
+When they are executed, they need not return HTML or any other sort of
+structured presentation text.  Instead, they might return values that are
+easy for a presentation object to format for display.  For example, a logic
+object may return a "list" of "strings".  Then, a presentation object may
+"call in" to the logic object and format the results of the call into a
+one-column HTML table, where the rows of the table are populated by the
+strings.  Instead of embedding logic in a presentation object, you can (and
+should) elect to move the logic into a logic object, using a presentation
+object only to format the result for display.  In this manner, you can
+change or replace the presentation object without needing to "re-code" or
+replace the logic.
+
+Note that logic objects, like presentation and content objects, are also
+addressable directly via a URL, and *may* elect to return HTML, which can
+be displayed meaningfully in a browser.  However, the return value of a
+logic object can almost always be displayed in a browser, even if the logic
+object does not return HTML.
+
+There is one kind of logic objects supported by stock Zope: *Script (Python)*
+objects.
+
+The stock logic objects are written in the syntax of the *Python* scripting
+language. Python is a general-purpose programming language. You are encouraged
+to read the `Python Tutorial <http://docs.python.org/tutorial/>`_
+in order to understand the syntax and semantics of the example Script (Python)
+objects shown throughout this chapter and throughout this book. And don't
+panic: Python is very easy to learn and understand.
+
+One important Python feature that must be mentioned here, however: Python uses
+whitespace in the form of indentation to denote block structure. Where other
+languages, such as C, Perl, and PHP might use "curly braces" -- "{" and "}" --
+to express a block of code, Python determines code blocks by examining the
+indentation of code text. If you're used to other programming languages, this
+may take some "getting-used-to" (typically consisting of a few hours of
+unsavory spoken language ;-) ). If you have problems saving or executing Script
+objects, make sure to check your Script's indentation.
+
+Script (Python) Objects
+-----------------------
+
+Script (Python) objects are one type of logic object.  Note that the
+tortuous form of their name (as opposed to "Python Script") is unfortunate:
+a legal issue prevents Zope Corporation from naming them "Python Scripts",
+but most folks at Zope Corporation and in the Zope community refer to them
+in conversation as just that.
+
+Script (Python) objects are "security-constrained", web-editable pieces of
+code that are written in a subset of the Python scripting language.  Not
+all Python code is executable via a Script (Python) object.  Script
+(Python) objects are constrained by Zope's *security policy*, which means,
+for the most part, that they are unable to import all but a defined set of
+restricted Python modules, and that they cannot directly access files on
+your file system.  This is a security feature, as it allows site
+administrators to safely delegate the ability to create logic in Python to
+untrusted or "semi-trusted" users.  For more information about Zope's
+security features, see `Users and Security <Security.html>`_.
+
+Creating a Script (Python)
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Enter the Sales folder you created earlier by clicking on it, then select
+*Script (Python)* from the Add list.  The Add form for the object will be
+displayed.  Specify the 'id' "SalesScript" and click *Add*.  You will see
+an entry in the Sales folder Content view representing the "SalesScript"
+Script (Python) object, whose content is standard, boilerplate text at this
+point.
+
+Editing a Script (Python)
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The easiest way to edit a Script (Python) is by clicking on its name or
+icon in the ZMI: when you click on either of these items, you are taken to
+the *Edit* view of the Script (Python), which gives you a textarea in which
+you can edit the template.  Click on the 'SalesScript' icon.  You will see
+something like the following:
+
+.. figure:: Figures/scriptdefault.png
+
+   Default Script Content
+
+In the *Parameter List* form element, type 'name="Chris"'.
+
+Replace the original content that comes in the "body" (the big TEXTAREA
+below the 'Last Modified' line) of the Script (Python) object with the
+following text::
+
+   return 'Hello, %s from the SalesScript script' % name
+
+Then click *Save Changes* at the bottom of the edit form. You can now
+execute, or test, your Script (Python) object.
+
+Testing a Script (Python)
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can test a Script (Python) in the Workspace frame by clicking the
+*Test* tab from the Script's management screen.  When you test a script,
+the output of the script will be displayed in your browser.  Script testing
+may require that you provide values for the script's *parameters* before
+you can view the results.  Click the *Test* tab of the SalesScript object,
+and you will see something like the following figure:
+
+.. figure:: Figures/testscript.png
+
+   Testing a Script
+
+In the Value box next to the 'name' parameter, enter your name, and then
+click "Run Script".  You will be presented with output in the Workspace
+frame not unlike::
+
+   Hello, [yourname] from the SalesScript script
+
+If a Script does not require parameters or has defaults for its parameters
+(as does the example above), you may visit its URL directly to see its
+output.  In our case, visiting the URL of SalesScript directly in your
+browser will produce::
+
+   Hello, Chris from the SalesScript script
+
+If a Script *does* require or accept parameters, you may also influence its
+execution by visiting its URL directly and including a "query string".  In
+our case, visiting the URL
+'http://localhost:8080/Sales/SalesScript?name=Fred' will produce the
+following output::
+
+   Hello, Fred from the SalesScript script
+
+Zope maps query string argument values to their corresponding parameters
+automatically, as you can see by this output.
+
+Uploading a Script (Python)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Uploading the body of a Script (Python) object is much like uploading the
+body of a Page Template.  One significant difference is that
+Script (Python) objects interpret text that is offset by "double-pound"
+('##') at the beginning of the text as data about their parameters, title,
+and "bindings".  For example, if you entered the following in a text editor
+and uploaded it, the lines that start with "double-pound" signs would be
+interpreted as parameter data, and the only text in the "body" would be the
+'return' line.  It would appear exactly as our SalesScript did::
+
+  ## Script (Python) "SalesScript"
+  ##bind container=container
+  ##bind context=context
+  ##bind namespace=
+  ##bind script=script
+  ##bind subpath=traverse_subpath
+  ##parameters=name="Chris"
+  ##title=
+  ##
+  return 'Hello, %s from the SalesScript script' % name
+
+You may see this view of a Script (Python) object by clicking on the 'view
+or download' link in the description beneath the "body" textarea.
+
+You may also type the "double-pound" quoted text into the "body" textarea,
+along with the actual script lines, and the "double-pound" quoted text will
+be "auto-magically" turned into bindings and parameters for the Script
+(Python) object.
+
+SQL Methods:  Another Kind of Logic Object
+------------------------------------------
+
+*SQL Methods* are logic objects used to store and execute database queries
+that you can reuse in your web applications.  We don't explain them in this
+chapter, because we haven't yet explained how to interface Zope with a
+relational database.  SQL Methods are explained in the chapter entitled
+`Relational Database Connectivity <RelationalDatabases.html>`_, where an
+example of creating a web application using a relational database is given.
+
+Creating a Basic Zope Application Using Page Templates and Scripts
+==================================================================
+
+Here is a simple example of using Zope's logic and content objects to build
+an online web form to help your users calculate the amount of compound
+interest on their debts.  This kind of calculation involves the following
+procedure:
+
+1. You need the following information: your current account balance (or
+   debt), called the "principal"; the annual interest rate expressed as a
+   decimal (like 0.095), called the "interest_rate"; the number of times
+   during the year that interest is compounded (usually monthly), called
+   the "periods"; and the number of years from now you want to calculate,
+   called the "years".
+
+2. Divide your "interest_rate" by "periods" (usually 12). We'll call this
+   result "i".
+
+3. Take "periods" and multiply it by "years".  We'll call this result "n".
+
+4. Raise (1 + "i") to the power "n".
+
+5. Multiply the result by your "principal". This is the new balance (or
+   debt).
+
+We will use Page Template and Script (Python) objects to construct an
+application to perform this task.
+
+For this example, you will need two Page Templates with the 'ids'
+*interestRateForm* and *interestRateDisplay*, respectively, to collect and
+display information from the user.  You will also need a Script (Python)
+object with an 'id' of *calculateCompoundingInterest* that will do the
+actual calculation.
+
+The first step is to create a folder in which to hold the application.  In
+your Zope's root folder, create a folder with the 'id' "Interest".  You
+will create all of the objects that follow within this folder.
+
+Creating a Data Collection Form
+-------------------------------
+
+Visit the 'Interest' folder by clicking on it within the Zope Management
+Interface.  Within the 'Interest' folder, create a Page Template with the
+'id' *interestRateForm* that collects "principal", "interest_rate",
+"periods", and "years" from your users.  Use this text as the body of your
+*interestRateForm* page template::
+
+  <html>
+    <body>
+
+    <form action="interestRateDisplay" method="POST">
+    <p>Please enter the following information:</p>
+
+    Your current balance (or debt): <input name="principal:float"><br>
+    Your annual interest rate: <input name="interest_rate:float"><br>
+    Number of periods in a year: <input name="periods:int"><br>
+    Number of years: <input name="years:int"><br>
+    <input type="submit" value=" Calculate "><br>
+    </form>
+
+    </body>
+  </html>
+
+This form collects information and, when it is submitted, calls the
+*interestRateDisplay* template (which we have not yet created).
+
+Creating a Script To Calculate Interest Rates
+---------------------------------------------
+
+Now, revisit the Contents view of the *Interest* folder and create a Script
+(Python) object with the id *calculateCompoundingInterest* that accepts
+four parameters: 'principal', 'interest_rate', 'periods', and 'years'.
+Provide it with the following "body"::
+
+  """ 
+  Calculate compounding interest.
+  """
+  i = interest_rate / periods
+  n = periods * years
+  return ((1 + i) ** n) * principal 
+
+Remember: you enter the parameter names, separated by commas, into the
+*Parameters List* field, and the body into the body text area.  Remember
+also that when you're creating a Script (Python) object, you're actually
+programming in the Python programming language, which is
+indentation-sensitive.  Make sure each of the lines above line up along the
+left side of the text area, or you may get an error when you attempt to
+save it.
+
+Creating a Page Template To Display Results
+-------------------------------------------
+
+Next, go back to the Contents view of the *Interest* folder and create a
+Page Template with the id *interestRateDisplay*.  This Page Template is
+**called by** *interestRateForm* and **calls**
+*calculateCompoundingInterest*.  It also renders and returns the results::
+
+  <html>
+    <body>
+    Your total balance (or debt) including compounded interest over
+    <span tal:define="years request/years;
+                      principal request/principal;
+                      interest_rate request/interest_rate;
+                      periods request/periods">
+      <span tal:content="years">2</span> years is:<br><br>
+      <b>$
+      <span tal:content="python: context.calculateCompoundingInterest(principal, 
+                                                       interest_rate,
+                                                       periods,
+                                                       years)" >1.00</span>
+      </b>
+    </span>
+    </body>
+  </html>
+
+Dealing With Errors
+-------------------
+
+As in any programming venue, you will need to deal with errors.  Nobody's
+perfect!  You may have already encountered some errors as you entered these
+scripts.  Let's explore errors a bit by way of an example.  In our case, we
+cannot use the Page Template *Test* tab to test the *interestRateDisplay*
+without receiving an error, because it depends on the *interestRateForm* to
+supply it with the variables "years, "principal", "interest_rate", and
+"periods".  Thus, it is not directly "testable".  For the sake of "seeing
+the problem before it happens for real", click the *Test* tab.  Zope will
+present an error page with text not unlike the following text::
+
+    Site Error
+
+    An error was encountered while publishing this resource.
+
+    Error Type: KeyError
+    Error Value: years
+
+This error message is telling you that your Page Template makes a reference
+to a variable "years" that it can't find.  You can view the full error by
+visiting the *error_log* object and clicking the top-most error log entry,
+which will be named *KeyError: years* in the *Log* tab.  The error log
+entry contains information about the error, including the time, the user
+who received the error, the URL that caused the error to happen, the
+exception type, the exception value, and a "Traceback", which typically
+gives you enough technical information to understand what happened.  In our
+case, the part of the traceback that is interesting to us is::
+
+   * Module Products.PageTemplates.TALES, line 217, in evaluate
+     URL: /Interest/interestRateDisplay
+     Line 4, Column 8
+     Expression: standard:'request/years'
+
+This tells us that the failure occurred when the Page Template attempted to
+access the variable 'request/years'.  We know why: there is no variable
+'request/years', because that variable is only "filled in" as a result of
+posting via our *interestRateForm*, which calls in to our
+*interestRateDisplay* Page Template, which has the effect of inserting the
+variables 'principal', 'interest_rate', 'periods', and 'years' into the
+'request' "namespace".  We'll cover Page Template namespaces in a
+succeeding chapter.
+
+Using The Application
+---------------------
+
+Let's use the application you've just created.  Visit the
+*interestRateForm* Page Template and click the *Test* tab.
+
+Type in '20000' for balance or debt, '.06' for interest rate, '4' for
+periods in a year, and '20' for number of years, and then click
+*Calculate*.  This will cause *interestRateForm* to submit the collect
+information to *interestRateDisplay*, which calls the Script (Python)
+object named *calculateCompoundingInterest*.  The display method uses the
+value returned by the script in the resulting display.  You will see the
+following result:
+
+.. figure:: Figures/interestdisplay.png
+
+   Result of the Interest Application
+
+If you see something close to this, it calls for congratulations, because
+you've just built your first Zope application successfully!  If you are
+having trouble, try to troubleshoot the application by using the tips in
+the section "Dealing With Errors."  If you're stuck entirely, it's
+advisable that you send a message to the `Zope mailing list
+<mailto:zope at zope.org>`_ detailing the problem that you're having as
+concisely and clearly as possible.  It is likely that someone there will be
+able to help you, and it is polite to subscribe to the Zope mailing list
+itself if you want to receive replies.  See the `Mailing list
+section <http://www.zope.org/Resources/MailingLists>`_ of Zope.org for
+information about how to subscribe to the Zope (zope at zope.org) mailing
+list.

Copied: zope2docs/branches/baijum-reorganize/zope2book/BasicScripting.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/BasicScripting.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/BasicScripting.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/BasicScripting.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,725 @@
+Basic Zope Scripting
+####################
+
+So far, you've learned about some basic Zope objects and how to manage them
+through the *Zope Management Interface*. This chapter shows you how to manage
+Zope objects programmatically.
+
+
+Calling Methods From the Web
+============================
+
+Since Zope is a web application server, the easiest way to communicate with
+Zope is through a web browser. Any URL your browser requests from the server is
+mapped to both an object and a method. The method is executed *on* the object,
+and a response is sent to your browser.
+
+As you might already know, visiting the URL :: 
+
+  http://localhost:8080/
+
+returns the *Zope Quick Start* page. In this case, we only specify an object --
+the *root* object -- but no method. This just works because there is a default
+method defined for *Folders*: *index_html*. Visiting the URL::
+
+  http://localhost:8080/index_html
+
+returns (almost) exactly the same page.
+
+You can also specify the root object as:: 
+
+  http://localhost:8080/manage_main
+
+but in this case the *manage_main* method is called, and the workspace frame
+displays the root content of your Zope site, without the navigator frame.
+
+The same method can be called *on* other objects: when you visit the URL::
+
+  http://localhost:8080/Control_Panel/manage_main
+
+the *manage_main* method is called *on* the *Control Panel* object.
+
+Sometimes a query string is added to the URL, e.g.:: 
+
+  http://localhost:8080/manage_main?skey=meta_type
+
+The query string is used for passing arguments to the method. In this case, the
+argument::
+
+  skey
+
+specifies the sort key with the value *meta_type*. Based on this argument, the
+*manage_main* method returns a modified version of the basic page: the
+sub-objects are sorted by *Type*, not by *Name* as they are without that query
+string.
+
+While the *manage_main* method is defined in the class of the object,
+*index_html* is (by default) a DTML Method object in the root folder that can
+be modified through the web. *index_html* itself is a presentation object, but
+when called *on* a folder, it behaves as a method that returns the default view
+of the folder.
+
+Method Objects and Context Objects
+++++++++++++++++++++++++++++++++++
+
+When you call a method, you usually want to single out some object that is
+central to the method's task, either because that object provides information
+that the method needs, or because the method will modify that object. In
+`object-oriented <ObjectOrientation.stx>`_ terms, we want to call the method
+*on* this particular object. But in conventional object-oriented programming,
+each object can perform the methods that are defined in (or inherited by) its
+class. How is it that one Zope object can be used as a method for (potentially)
+many other objects, without its being defined by the classes that define these
+objects?
+
+Recall that in the chapter entitled `Acquisition <Acquisition.stx>`_, we
+learned that Zope can find objects in different places by *acquiring* them from
+parent containers. Acquisition allows us to treat an object as a method that
+can be called *in the context of* any suitable object, just by constructing an
+appropriate URL. The object *on* which we call a method gives it a context in
+which to execute. Or, to put it another way: the context is the environment in
+which the method executes, from which the method may get information that it
+needs in order to do its job.
+
+Another way to understand the context of a method is to think of the method as
+a function in a procedural programming language, and its context as an implicit
+argument to that function.
+
+While the Zope way to call methods *in the context of* objects **works**
+differently than the normal object-oriented way to call class-defined methods
+*on* objects, they are **used** the same way, and it is simpler to say that you
+are calling the method *on* the object.
+
+There are two general ways to call methods *on* objects: by visiting an URL,
+and by calling the method from another method.
+
+URL Traversal and Acquisition
++++++++++++++++++++++++++++++
+
+The concept of calling methods *in the context of* objects is a powerful
+feature that enables you to apply logic to objects, like documents or folders,
+without having to embed any actual code within the object.
+
+For example, suppose you have a collection of objects and methods, as shown in
+the figure below.
+
+`A collection of objects and methods <img:9-1:Figures/zoo.png>`_
+
+To call the *feed* method on the *hippo* object, you would visit the URL:: 
+
+  Zoo/LargeAnimals/hippo/feed
+
+To call the *feed* method on the *kangarooMouse* object you would visit the
+URL:: 
+
+  Zoo/SmallAnimals/kangarooMouse/feed
+
+These URLs place the *feed* method in the context of the *hippo* and
+*kangarooMouse* objects, respectively.
+
+Zope breaks apart the URL and compares it to the object hierarchy,
+working backwards until it finds a match for each part.  This process is
+called *URL traversal*.  For example, when you give Zope the URL:: 
+
+  Zoo/LargeAnimals/hippo/feed
+
+it starts at the root folder and looks for an object named *Zoo*. It then moves
+to the *Zoo* folder and looks for an object named *LargeAnimals*. It moves to
+the *LargeAnimals* folder and looks for an object named *hippo*. It moves to
+the *hippo* object and looks for an object named *feed*. The *feed* method
+cannot be found in the *hippo* object and is located in the *Zoo* folder by
+using acquisition. Zope always starts looking for an object in the last object
+it traversed, in this case: *hippo*. Since *hippo* does not contain anything,
+Zope backs up to *hippo's* immediate container *LargeAnimals*. The *feed*
+method is not there, so Zope backs up to *LargeAnimals* container, *Zoo*, where
+*feed* is finally found.
+
+Now Zope has reached the end of the URL and has matched objects to every name
+in the URL. Zope recognizes that the last object found, *feed*, is callable,
+and calls it *in the context of* the second-to-last object found: the *hippo*
+object. This is how the *feed* method is called *on* the *hippo* object.
+
+Likewise, you can call the *wash* method on the *hippo* by visiting the URL::
+
+  Zoo/LargeAnimals/hippo/wash
+
+In this case, Zope acquires the *wash* method from the *LargeAnimals* folder.
+
+Note that *Script (Python)* and *Page Template* objects are always method
+objects. You can't call another method *in the context* of one of them. Given
+*wash* is such a method object, visiting the URL ::
+
+  Zoo/LargeAnimals/hippo/wash/feed
+
+would also call the *wash* method on the *hippo* object. Instead of traversing
+to *feed*, everything after the method ::
+
+  wash
+
+is cut off of the URL and stored in the variable::
+
+  traverse_subpath
+
+
+The Special Folder Object *index_html*
++++++++++++++++++++++++++++++++++++++++
+
+As already mentioned at the beginning of this chapter, Zope uses the default
+method if no other method is specified. The default method for Folders is
+*index_html*, which does not necessarily need to be a method itself. If it
+isn't a callable, the default method of the object *index_html* is called on
+*index_html*. This is analogous to how an *index.html* file provides a default
+view for a directory in Apache and other web servers. Instead of explicitly
+including the name *index_html* in your URL to show default content for a
+Folder, you can omit it and still gain the same effect.
+
+For example, if you create an *index_html* object in your *Zoo* Folder, and
+view the folder by clicking the View tab or by visiting the URL::
+
+  http://localhost:8080/Zoo/
+
+Zope will call the *index_html* object in the *Zoo* folder and display its
+results. You could instead use the more explicit URL::
+
+  http://localhost:8080/Zoo/index_html
+
+and it will display the same content.
+
+A Folder can also *acquire* an *index_html* object from its parent Folders. You
+can use this behavior to create a default view for a set of Folders. To do so,
+create an *index_html* object in a Folder that contains another set of Folders.
+This default view will be used for all the Folders in the set. This behavior is
+already evident in Zope: if you create a set of empty Folders in the Zope root
+Folder, you may notice that when you view any of the Folders via a URL, the
+content of the "root" Folder's *index_html* method is displayed. The
+*index_html* in the root Folder is acquired. Furthermore, if you create more
+empty Folders inside the Folders you've just created in the root Folder, a
+visit to these Folders' URLs will also display the root Folder's *index_html*.
+This is acquisition at work.
+
+If you want a different default view of a given Folder, just create a custom
+*index_html* object in that particular Folder. This allows you to override the
+default view of a particular Folder on a case-by-case basis, while allowing
+other Folders defined at the same level to acquire a common default view.
+
+The *index_html* object may be a *Page Template*, a *Script (Python)* object, a
+*DTML Method* or any other Zope object that is URL-accessible and that returns
+browser-renderable content. The content is typically HTML, but Zope doesn't
+care. You can return XML, or text, or anything you like.
+
+Using Python-based Scripts
+==========================
+
+Now let us take a look at a basic method object: *Script (Python)*.
+
+The Python Language
++++++++++++++++++++
+
+`Python <http://www.python.org/>`_ is a high-level, object oriented scripting
+language. Most of Zope is written in Python. Many folks like Python because of
+its clarity, simplicity, and ability to scale to large projects.
+
+There are many resources available for learning Python. The python.org website
+has lots of Python documentation including a `tutorial
+<http://www.python.org/doc/current/tut/tut.html>`_ by Python's creator, Guido
+van Rossum.
+
+For people who have already some programming experience, `Dive Into Python
+<http://diveintopython.org/>`_ is a great online resource to learn python.
+
+Python comes with a rich set of modules and packages. You can find out more
+about the `Python standard library
+<http://www.python.org/doc/current/lib/lib.html>`_ at the python.org website.
+
+Creating Python-based Scripts
++++++++++++++++++++++++++++++
+
+To create a Python-based Script, select *Script (Python)* from the Add
+drop-down list. Name the script *hello*, and click the *Add and Edit* button.
+You should now see the *Edit* view of your script.
+
+This screen allows you to control the parameters and body of your script. You
+can enter your script's parameters in the *parameter list* field. Type the body
+of your script in the text area at the bottom of the screen.
+
+Enter:: 
+
+  name="World"
+
+into the *parameter list* field, and in the body of the script, type::
+
+  return "Hello %s." % name
+
+Our script is now equivalent to the following function definition in standard
+Python syntax::
+
+  def hello(name="World"):
+      return "Hello %s." % name
+
+The script should return a result similar to the following image:
+
+`Script editing view <img:9-2:Figures/8-5.png>`_
+
+You can now test the script by going to the *Test* tab, as shown in the
+following figure.
+
+`Testing a Script <img:9-3:Figures/8-6.png>`_
+
+Leave the *name* field blank, and click the *Run Script* button. Zope should
+return "Hello World." Now go back and try entering your name in the *Value*
+field, and clicking the *Run Script* button. Zope should now say "hello" to
+you.
+
+Since scripts are called on Zope objects, you can get access to Zope objects
+via the *context* variable. For example, this script returns the number of
+objects contained by a given Zope object::
+
+  ## Script (Python) "numberOfObjects"
+  ##
+  return len( context.objectIds() )
+
+Note that the lines at the top starting with a double hash (##) are generated
+by Zope when you view the script outside the *Edit* tab of the ZMI, e.g., by
+clicking the *view or download* link at the bottom of the *Edit* tab. We'll use
+this format for our examples.
+
+The script calls::
+
+  context.objectIds()
+
+a method in the Zope API, to get a list of the contained objects. *objectIds*
+is a method of *Folders*, so the context object should be a Folder-like object.
+The script then calls::
+
+  len()
+
+to find the number of items in that list. When you call this script on a given
+Zope object, the *context* variable is bound to the context object. So, if you
+called this script by visiting the URL::
+
+  FolderA/FolderB/numberOfObjects
+
+the *context* parameter would refer to the `FolderB` object.
+
+When writing your logic in Python, you'll typically want to query Zope objects,
+call other scripts, and return reports. Suppose you want to implement a simple
+workflow system, in which various Zope objects are tagged with properties that
+indicate their status. You might want to produce reports that summarize which
+objects are in which state. You can use Python to query objects and test their
+properties. For example, here is a script named::
+
+  objectsForStatus
+
+with one parameter, 'status'::
+
+  ## Script (Python) "objectsForStatus"
+  ##parameters=status
+  ##
+  """ Returns all sub-objects that have a given status property.
+  """
+  results=[]
+  for object in context.objectValues():
+      if object.getProperty('status') == status:
+          results.append(object)
+  return results
+
+This script loops through an object's sub-objects, and returns all the
+sub-objects that have a::
+
+  status
+
+property with a given value.
+
+Accessing the HTTP Request
+++++++++++++++++++++++++++
+
+What if we need to get user input, e.g., values from a form? We can find the
+REQUEST object, which represents a Zope web request, in the context. For
+example, if we visited our *feed* script via the URL::
+
+  Zoo/LargeAnimals/hippo/feed?food_type=spam
+
+we could access the:: 
+
+  food_type
+
+variable as::
+
+  context.REQUEST.food_type
+
+This same technique works with variables passed from forms.
+
+Another way to get the REQUEST is to pass it as a parameter to the script. If
+REQUEST is one of the script's parameters, Zope will automatically pass the
+HTTP request and assign it to this parameter. We could then access the::
+
+  food_type
+
+variable as::
+
+  REQUEST.food_type
+
+String Processing in Python
++++++++++++++++++++++++++++
+
+One common use for scripts is to do string processing. Python has a number of
+standard modules for string processing. Due to security restrictions, you
+cannot do regular expression processing within Python-based Scripts. If you
+really need regular expressions, you can easily use them in External Methods,
+described in a subsequent chapter. However, in a Script (Python) object, you do
+have access to string methods.
+
+Suppose you want to change all the occurrences of a given word in a text file.
+Here is a script, *replaceWord*, that accepts two arguments: *word* and
+*replacement*. This will change all the occurrences of a given word in a
+File::
+
+  ## Script (Python) "replaceWord"
+  ##parameters=word, replacement
+  ##
+  """ Replaces all the occurrences of a word with a replacement word in
+  the source text of a text file. Call this script on a text file to use
+  it.
+
+  Note: you will need permission to edit the file in order to call this
+  script on the *File* object.  This script assumes that the context is
+  a *File* object, which provides 'data', 'title', 'content_type' and
+  the manage_edit() method.
+  """
+  text = context.data
+  text = text.replace(word, replacement)
+  context.manage_edit(context.title, context.content_type, filedata=text)
+
+You can call this script from the web on a text *File* in order to change the
+text. For example, the URL::
+
+  Swamp/replaceWord?word=Alligator&replacement=Crocodile
+
+would call the *replaceWord* script on the text *File* named::
+
+  Swamp
+
+and would replace all occurrences of the word::
+
+  Alligator
+
+with::
+
+  Crocodile
+
+See the Python documentation for more information about manipulating strings
+from Python.
+
+One thing that you might be tempted to do with scripts is to use Python to
+search for objects that contain a given word within their text or as a
+property. You can do this, but Zope has a much better facility for this kind of
+work: the *Catalog*. See the chapter entitled `Searching and Categorizing
+Content <SearchingZCatalog.stx>`_ for more information on searching with
+Catalogs.
+
+Print Statement Support
++++++++++++++++++++++++
+
+Python-based Scripts have a special facility to help you print information.
+Normally, printed data is sent to standard output and is displayed on the
+console. This is not practical for a server application like Zope, since the
+service does not always have access to the server's console. Scripts allow you
+to use print anyway, and to retrieve what you printed with the special variable
+*printed*. For example::
+
+  ## Script (Python) "printExample"
+  ##
+  for word in ('Zope', 'on', 'a', 'rope'):
+      print word
+  return printed
+
+This script will return::
+
+  Zope
+  on
+  a
+  rope
+
+The reason that there is a line break in between each word is that Python adds
+a new line after every string that is printed.
+
+You might want to use the::
+
+  print
+
+statement to perform simple debugging in your scripts. For more complex output
+control, you probably should manage things yourself by accumulating data,
+modifying it, and returning it manually, rather than relying on the::
+
+  print
+
+statement. And for controlling presentation, you should return the script
+output to a Page Template or DTML page, which then displays the return value
+appropriately.
+
+Built-in Functions
+++++++++++++++++++
+
+Python-based Scripts give you a slightly different menu of built-ins than you'd
+find in normal Python. Most of the changes are designed to keep you from
+performing unsafe actions. For example, the *open* function is not available,
+which keeps you from being able to access the file system. To partially make up
+for some missing built-ins, a few extra functions are available.
+
+The following restricted built-ins work the same as standard Python built-ins:
+*None*, *abs*, *apply*, *callable*, *chr*, *cmp*, *complex*, *delattr*,
+*divmod*, *filter*, *float*, *getattr*, *hash*, *hex*, *int*, *isinstance*,
+*issubclass*, *list*, *len*, *long*, *map*, *max*, *min*, *oct*, *ord*, *repr*,
+*round*, *setattr*, *str*, and *tuple*. For more information on what these
+built-ins do, see the online `Python Documentation
+<http://www.python.org/doc/>`_.
+
+The *range* and *pow* functions are available and work the same way they do in
+standard Python; however, they are limited to keep them from generating very
+large numbers and sequences. This limitation helps protect against
+denial-of-service attacks.
+
+In addition, these DTML utility functions are available: *DateTime* and *test*.
+See Appendix A, `DTML Reference <AppendixA.stx>`_ for more information on these
+functions.
+
+Finally, to make up for the lack of a *type* function, there is a *same_type*
+function that compares the type of two or more objects, returning *true* if
+they are of the same type. So, instead of saying::
+
+  if type(foo) == type([]):
+      return "foo is a list"
+
+... to check if::
+
+  foo
+
+is a list, you would instead use the *same_type* function::
+
+  if same_type(foo, []):
+      return "foo is a list"
+
+Calling ZPT from Scripts
+========================
+
+Often, you would want to call a *Page Template* from a Script. For instance, a
+common pattern is to call a Script from an HTML form. The Script would process
+user input, and return an output page with feedback messages - telling the user
+her request executed correctly, or signalling an error as appropriate.
+
+Scripts are good at logic and general computational tasks but ill-suited for
+generating HTML. Therefore, it makes sense to delegate the user feedback output
+to a *Page Template* and call it from the Script. Assume we have this Page
+Template with the *id* 'hello_world_pt'::
+
+  <p>Hello <span tal:replace="options/name | default">World</span>!</p>
+
+You will learn more about *Page Templates* in the next chapter. For now, just
+understand that this *Page Template* generates an HTML page based on the value
+*name*. Calling this template from a Script and returning the result could be
+done with the following line::
+
+  return context.hello_world_pt(name="John Doe")
+
+The *name* parameter to the Page Template ends up in the::
+
+  options/name
+
+path expression. So the returned HTML will be::
+
+  <p>Hello John Doe!</p>
+
+Note that::
+
+  context.hello_world_pt
+
+works because there is no dot in the id of the template. In Python, dots are
+used to separate ids. This is the reason why Zope often uses ids like::
+
+  index_html
+
+instead of the more common::
+
+  index.html
+
+and why this example uses::
+
+  hello_world_pt
+
+instead of::
+
+  hello_world.pt
+
+However, if desired, you can use dots within object ids. Using *getattr* to
+access the dotted id, the modified line would look like this::
+
+  return getattr(context, 'hello_world.pt')(name="John Doe")
+
+Returning Values from Scripts
+=============================
+
+Scripts have their own variable scope. In this respect, scripts in Zope behave
+just like functions, procedures, or methods in most programming languages. If
+you name a script *updateInfo*, for example, and *updateInfo* assigns a value
+to a variable *status*, then *status* is local to your script: it gets cleared
+once the script returns. To get at the value of a script variable, we must pass
+it back to the caller with a *return* statement.
+
+Scripts can only return a single object. If you need to return more than one
+value, put them in a dictionary and pass that back.
+
+Suppose you have a Python script *compute_diets*, out of which you want to get
+values::
+
+  ## Script (Python) "compute_diets"
+  d = {'fat': 10,
+       'protein': 20,
+       'carbohydrate': 40,
+  }
+  return d
+
+The values would, of course, be calculated in a real application; in this
+simple example, we've simply hard-coded some numbers.
+
+You could call this script from ZPT like this::
+
+  <p tal:repeat="diet context/compute_diets">
+      This animal needs
+      <span tal:replace="diet/fat" />kg fat,
+      <span tal:replace="diet/protein" />kg protein, and
+      <span tal:replace="diet/carbohydrate" />kg carbohydrates.
+  </p>
+
+More on ZPT in the next chapter.
+
+The Zope API
+============
+
+One of the main reasons to script in Zope is to get convenient access to the
+Zope Application Programmer Interface (API). The Zope API describes built-in
+actions that can be called on Zope objects. You can examine the Zope API in the
+help system, as shown in the figure below.
+
+`Zope API Documentation <img:9-4:Figures/8-4.png>`_
+
+Suppose you would like a script that takes a file you upload from a form, and
+creates a Zope File object in a Folder. To do this, you'd need to know a number
+of Zope API actions. It's easy enough to read files in Python, but once you
+have the file, you must know which actions to call in order to create a new
+File object in a Folder.
+
+There are many other things that you might like to script using the Zope API:
+any management task that you can perform through the web can be scripted using
+the Zope API, including creating, modifying, and deleting Zope objects. You can
+even perform maintenance tasks, like restarting Zope and packing the Zope
+database.
+
+The Zope API is documented in Appendix B, `API Reference <AppendixB.stx>`_, as
+well as in the Zope online help. The API documentation shows you which classes
+inherit from which other classes. For example, *Folder* inherits from
+*ObjectManager*, which means that Folder objects have all the methods listed in
+the *ObjectManager* section of the API reference.
+
+To get you started and whet your appetite, we will go through some example
+Python scripts that demonstrate how you can use the Zope API:
+
+Get all objects in a Folder
++++++++++++++++++++++++++++
+
+The::
+
+  objectValues()
+
+method returns a list of objects contained in a Folder. If the context happens
+not to be a Folder, nothing is returned::
+
+  objs = context.objectValues()
+
+Get the id of an object
++++++++++++++++++++++++
+
+The id is the "handle" to access an object, and is set at object creation::
+
+  id = context.getId()
+
+Note that there is no *setId()* method: you have to either use the ZMI to
+rename them, set their::
+
+  id
+
+attribute via security-unrestricted code, or use the::
+
+  manage_renameObject
+
+or::
+
+  manage_renameObjects
+
+API methods exposed upon the container of the object you want to rename.
+
+Get the Zope root Folder
+++++++++++++++++++++++++
+
+The root Folder is the top level element in the Zope object database::
+
+  root = context.getPhysicalRoot()
+
+Get the physical path to an object
+++++++++++++++++++++++++++++++++++
+
+The::
+
+  getPhysicalPath()
+
+method returns a list containing the ids of the object's containment
+hierarchy::
+
+  path_list = context.getPhysicalPath()
+  path_string = "/".join(path_list)
+
+Get an object by path
++++++++++++++++++++++
+
+restrictedTraverse() is the complement to::
+
+  getPhysicalPath()
+
+The path can be absolute -- starting at the Zope root -- or relative to the
+context::
+
+  path = "/Zoo/LargeAnimals/hippo"
+  hippo_obj = context.restrictedTraverse(path)
+
+Get a property
+++++++++++++++
+
+getProperty()
+
+returns a property of an object. Many objects support properties (those that
+are derived from the PropertyManager class), the most notable exception being
+DTML Methods, which do not::
+
+  pattern = context.getProperty('pattern')
+  return pattern
+
+Change properties of an object
+++++++++++++++++++++++++++++++
+
+The object has to support properties, and the property must exist::
+
+  values = {'pattern' : 'spotted'}
+  context.manage_changeProperties(values)
+
+Traverse to an object and add a new property
+++++++++++++++++++++++++++++++++++++++++++++
+
+We get an object by its absolute path, add a property::
+
+  weight
+
+and set it to some value. Again, the object must support properties in order
+for this to work::
+
+  path = "/Zoo/LargeAnimals/hippo"
+  hippo_obj = context.restrictedTraverse(path)
+  hippo_obj.manage_addProperty('weight', 500, 'int')

Copied: zope2docs/branches/baijum-reorganize/zope2book/Contributions.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/Contributions.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/Contributions.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/Contributions.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,67 @@
+Contributions
+=============
+
+Contributors to this book include Amos Latteier, Michel Pelletier,
+Chris McDonough, Evan Simpson, Tom Deprez, Paul Everitt, Bakhtiar
+A. Hamid, Geir Baekholt, Thomas Reulbach, Paul Winkler, Peter Sabaini,
+Andrew Veitch, Kevin Carlson, Joel Burton, John DeStefano, Tres Seaver,
+Hanno Schlicting, and the Zope Community.
+
+Amos and Michel wrote the entirety of the first edition of this
+book, and kept the online version of the book current up until Zope
+2.5.1.
+
+Tom Deprez provided much-needed editing assistance on the first
+book edition.
+
+Evan Simpson edited the chapters related to ZPT for the 2.6
+edition.
+
+Paul Everitt contributed to the first few chapters of the first
+edition, edited the first few chapters of the second edition for
+sanity and contributed some "Maintaining Zope" content for the
+2.6 edition.
+
+Bakhtiar Hamid edited the ZEO chapter for the 2.6 edition.
+
+Geir edited and extended the Users and Security chapter for the 2.6
+edition.
+
+Paul Winkler with help from Peter Sabaini expertly massaged the
+Advanced Scripting chapter into coherency for the 2.6 edition.
+
+Peter Sabaini greatly fleshed out and extended the "Maintaining Zope"
+and the "Searching and Categorizing Content" chapter for the 2.6 Edition. 
+
+Andrew Veitch cheerfully performed the thankless task of
+editing and extending the Relational Database Connectivity chapter
+for the 2.6 edition.
+
+Kevin Carlson masterfully edited and expanded the Advanced DTML
+chapter. 
+
+Joel Burton rewrote the ZCatalog chapter late in the 2.6 book's
+lifetime.
+
+Dario Lopez-Kästen updated the "Introducing Zope" chapter for the
+2.7 edition.
+
+Chris McDonough edited the entirety of the book for the 2.6
+edition, entirely rewrote a few chapters and added new material
+related to object orientation, using the Zope management interface,
+acquisition, installation, services, virtual hosting, sessions, and
+DTML name lookup rules.
+
+Jo <jo at winfix dot it> has contributed a number of spelling corrections.
+
+John DeStefano edited chapters of the book in a post-2.7-edition mode.
+
+Tres Seaver moved the text into the Zope Subversion repository, and
+helped with the conversion of the text from ``Structured Text``
+to ``ReStructured Text``.
+
+Hanno Schlichting did the remainder of the ``ReStructured Text`` conversion,
+completed the integration with Sphinx and rewrote many chapters for Zope 2.12.
+
+Anyone who added a comment to the online BackTalk edition of the
+first online edition of this book contributed greatly.  Thank you!

Copied: zope2docs/branches/baijum-reorganize/zope2book/DTML.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/DTML.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/DTML.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/DTML.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,1427 @@
+Basic DTML
+==========
+
+
+.. note::
+    DTML has been the primary markup language within Zope for a long time.  However
+    the *recommended* primary markup language within Zope is nowadays ZPT (Zope
+    Page Templates). ZPT is your choice for generating markupish output like HTML
+    or XML. The usage of DTML should be limited where you have to generate
+    non-markupish output like text files or other formats. Since DTML is pretty old
+    it really does not support features like internationalization or unicode very
+    well.  In addition the syntax of DTML is not always very easy to understand.
+    You have to learn DTML to some point if you intend to use ZSQL methods (for
+    RDBMS integration with Zope) - but even for the RDBMS integration we have
+    better solutions like Object-Relational-Mappers (check with the chapter about
+    relational database connectivity).
+
+
+DTML (Document Template Markup Language) is a templating facility which
+supports the creation of dynamic HTML and text. In Zope it is most often used
+when you want to generate non-HTML or non-XML content, like parts of SQL
+queries, dynamic CSS and JavaScript files or email templates. Generating HTML
+and XML is usually done with page templates inside Zope.
+
+DTML is a *tag-based* presentation and scripting language.  This
+means that *tags* (e.g. '<dtml-var name>') embedded in your text
+cause parts of your text to be replaced with "computed" content.
+
+DTML is a "server-side" scripting language.  This means that DTML
+commands are executed by Zope at the server, and the result of that
+execution is sent to your web browser. By contrast, "client-side"
+scripting languages like JavaScript are not processed by the server,
+but are rather sent to and executed by your web browser.
+
+How DTML Relates to Similar Languages and Templating Facilities
+---------------------------------------------------------------
+
+DTML is similar in function to "HTML-embedded" scripting languages
+such as JSP, PHP, or mod_perl.  It differs from these facilities
+inasmuch as it will not allow you to create "inline" Python
+*statements* (if... then.. else..)  in the way that JSP, mod_perl
+or PHP will allow you to embed a block of their respective
+language's code into a page. DTML does allow you to embed
+Python *expressions* (a == 1) into tags.  It provides
+flow control and conditional logic by way of "special" tags.
+It is more similar to Perl's 'HTML::Template' package than it is
+to mod_perl in this way.  It can also be compared to the web
+server facility of Server Side Includes (SSI), but with far more
+features and flexibility.
+
+When To Use DTML
+----------------
+
+If you don't want to use page templates for whatever reason DTML might work
+well. Likewise, if you want to dynamically create non-HTML text (like CSS
+stylesheets or email messages), DTML can help.
+
+When Not To Use DTML
+--------------------
+
+If you want code which expresses a set of complex algorithms to be
+maintainable (as "logic" programming should be), you shouldn't
+write it in DTML.  DTML is not a general purpose programming
+language, it instead is a special language designed for formatting
+and displaying content.  While it may be possible to implement
+complex algorithms in DTML, it is often painful.
+
+For example, let's suppose you want to output some text which
+displays a representation of the famous `Fibonacci sequence
+<http://www.mathacademy.com/pr/prime/articles/fibonac/index.asp>`_.
+You would not want to write the program that actually makes the
+calculation of the Fibonacci numbers by writing DTML.  It could be
+done in DTML, but the result would be difficult to understand and
+maintain.  However, DTML is perfect for describing the output that
+the results of the Fibonnacci calculations are inserted into.  You
+can "call out" from DTML to Script (Python) objects as necessary
+and process the results of the call in DTML.  For example, it is
+`trivial in Python <http://docs.python.org/tutorial/introduction.html>`_
+(search for the word Fibonacci on this page) to implement a Fibonacci
+sequence generator, and trivial in DTML to create some dynamic 
+output which shows these numbers in a readable format.  If you find
+yourself creating complex and hard-to-understand logic in DTML,
+it's likely time to explore the the Zope features which allow you
+to script "logic" in Python, while letting DTML do the
+presentation "dirty work".
+
+String processing is another area where DTML is likely not the
+best choice.  If you want to manipulate input from a user in a
+complex way, by using functions that manipulate strings, you are
+better off doing it in Python, which has more powerful string
+processing capabilities than DTML.
+
+The Difference Between DTML Documents and DTML Methods
+------------------------------------------------------
+
+You can use DTML scripting commands in two types of Zope objects,
+*DTML Documents* and *DTML Methods*.  These two types of DTML
+objects are subtly different from one another, and their
+differences cause many would-be DTML programmers to become
+confused when deciding to use one versus the other.  So what is
+the difference?
+
+DTML Methods are used to carry out actions. They are
+*presentation* objects (as used in the vernacular of the `Using
+Basic Zope Objects`_ chapter).  If you want to
+render the properties or attributes of another object like a DTML
+Document or a Folder, you will use a DTML Method.  DTML Methods do
+not have their own properties.
+
+DTML Documents are *content* objects (in the vernacular used in
+the chapter entitled `Using Basic Zope Objects`_).
+If you want to create a "stand-alone" text document, you
+might create a DTML Document object to hold the text.
+DTML Document objects have their own *properties* (attributes),
+unlike DTML Methods.
+
+In almost all cases, you will want to use a DTML Method object to
+perform DTML scripting.  DTML Document objects are an artifact of
+Zope's history that is somewhat unfortunate.  In Zope's earlier
+days, a consensus came about that it was important to have objects
+in Zope that could perform DTML commands but have properties of
+their own.  At the time, the other content objects in Zope, such
+as Files and Images were either nonexistent or had limitations in
+functionality that made the concept of a DTML Document attractive.
+That attraction has waned as Zope's other built-in content objects
+have become more functional.  DTML Documents remain in Zope almost
+solely as a backwards-compatibility measure.  If you never use a
+DTML Document in your work with Zope, you won't miss out on
+much!
+
+Details
+-------
+
+DTML Methods are method objects.  The chapter named `Object
+Orientation <ObjectOrientation.html>`_ discusses the concept of a
+"method".  DTML Methods are *methods* of the folder that
+contains them, and thus they do not have regard for their own
+identity as a Zope object when they are used. For example, if
+you had a folder called Folder and a DTML method in that folder
+called Method::
+
+  AFolder/
+          AMethod
+
+AMethod is a *method* of AFolder. This means that AMethod does not
+have any of it's own attributes or properties.  Instead it uses
+those of AFolder. Suppose you put the following DTML string in
+AMethod::
+
+  <dtml-var id>
+
+When you view the AMethod DTML Method, you will see the string
+'AFolder', which is the 'id' of AMethod's containing Folder
+(AFolder). When this DTML method is viewed, it resolves the name
+'id' to the string which is the value of AFolder's 'id' property.
+
+DTML Documents, on the other hand, are not methods.  They are
+"aware" of their own identity as Zope objects. For example, if
+you created a DTML Document in the folder AFolder called
+ADocument, and you put the above DTML string into ADocument and
+viewed it, it would render to the string 'ADocument'.  It
+resolves the name 'id' to the string which is the value of
+its *own* id, not the id of its containing folder.
+
+.. important::
+   
+   For this chapter, unless stated otherwise, use DTML Methods to
+   hold the example DTML text, as opposed to DTML Documents!**
+
+DTML Tag Syntax
+---------------
+
+DTML contains two kinds of tags, *singleton* and *block* tags.
+Singleton tags consist of one tag enclosed by less-than (&lt;) and
+greater-than (&gt;) symbols.  The *var* tag is an example of a
+singleton tag::
+
+  <dtml-var parrot>
+
+There's no need to close the *var* tag with a '</dtml-var>' tag
+because it is a singleton tag.
+
+Block tags consist of two tags, one that opens the block and one that
+closes the block, and content that goes between them::
+
+  <dtml-in mySequence>
+
+    this is a text inside the dtml-in tag block
+
+  </dtml-in>
+
+The opening tag starts the block and the closing tag ends it. The
+closing tag has the same name as the opening tag with a slash
+preceding it. This is the same convention that HTML and XML use.
+
+DTML Tag Names, Targets, and Attributes
+---------------------------------------
+
+All DTML tags have *names*.  The name is simply the word which
+follows 'dtml-'.  For instance, the name of the DTML tag
+'dtml-var' is 'var', and the name of the DTML tag 'dtml-in' is
+'in'.
+
+Most DTML tags have *targets*.  The target of a DTML tag is just
+the word or expression that, after a space, follows the tag
+name.  For example, the target of the DTML tag '<dtml-var
+standard_html_header>' is 'standard_html_header'.  The target of
+the DTML tag '<dtml-in foo>' is 'foo'.  The target of the DTML
+tag '<dtml-var "objectIds()"> is the expression "objectIds()".
+The target typically refers to the name of an object (or a
+Python expression that resolves to an object) that you wish the
+tag to operate upon.
+
+All DTML tags have *attributes*. An attribute provides
+information about how the tag is supposed to work. Some
+attributes are optional. For example, the *var* tag inserts the
+value of its target. It has an optional *missing* attribute that
+specifies a default value in case the variable can't be found::
+
+  <dtml-var wingspan missing="unknown wingspan">
+
+If the *wingspan* variable is not found then 'unknown wingspan'
+is inserted instead.
+
+Some attributes don't have values. For example, you can convert
+an inserted variable to upper case with the *upper* attribute::
+
+  <dtml-var exclamation upper>
+
+Here we are referencing the *exclamation* target, modifying it
+with the attribute *upper*.  Notice that the *upper* attribute,
+unlike the *missing* attribute doesn't need a value.
+
+See the `DTML Reference <AppendixA.html>`_ appendix for more
+information on the syntax of different DTML tags.
+
+Creating a "Sandbox" for the Examples in This Chapter
+-----------------------------------------------------
+
+You should create a Folder in your Zope's root folder named
+"DTML_Examples" if you intend on creating objects from examples in
+this chapter.  Create the example objects within this "sandbox".
+This prevents you from littering your Zope root folder with DTML
+examples.
+
+Examples of Using DTML for Common Tasks
+---------------------------------------
+
+Below, we show how to use DTML to complete three common tasks:
+inserting text into a web page, displaying results by iterating
+over a sequence, and processing form results.
+
+Inserting Text into HTML with DTML
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+DTML commands are written as tags that begin with *dtml-*.  You
+create dynamic content in DTML by mixing content and DTML tags
+together.  Inserting the value of a variable (a variable is also
+known as a "target") into HTML is the most basic task that you can
+perform with DTML.  Many DTML tags insert variable values, and
+they all do it in a similar way.  Let's look more closely at how
+Zope inserts variable values.
+
+Create a folder in your sandbox with the id "Feedbags" and the
+title "Bob's Fancy Feedbags". While inside the 'Feedbags' folder,
+create a DTML Method with an id of "pricelist". Note: an
+'id' is how you refer to an object such as a DTML Method
+or a Folder later on; titles are for informational
+purposes only. 
+
+Change the contents of the DTML Method to the following::
+
+  <dtml-var standard_html_header>
+
+  <h1>Price list for <dtml-var title></h1>
+
+  <p>Hemp Bag $2.50</p>
+  <p>Silk Bag $5.00</p>
+
+  <dtml-var standard_html_footer>
+
+Now view the DTML Method by clicking the *View* tab. When you view
+the DTML method this way, it will be *rendered*, which means that
+you will not necessarily see a straight representation of the HTML
+that you typed in to the form.  Instead you will see the
+*rendered* version of the page, which will include the extra text
+provided by DTML by way of the tags you've inserted.  You should
+see something like the figure below:
+
+.. figure:: Figures/9-1_bobsfeedbags.png
+
+   Viewing the pricelist method
+
+If you tell your browser to view the HTML source of the Workspace
+frame, you will see something not unlike the below::
+
+  <html>
+    <head><title>Bob's Fancy Feedbags</title>
+    </head>
+    <body bgcolor="#FFFFFF">
+      <h1>Price list for Bob's Fancy Feedbags</h1>
+      <p>Hemp Bag $2.50</p>
+      <p>Silk Bag $5.00</p>
+    </body>
+
+  </html>
+
+That's certainly not what you typed in, is it?
+
+DTML makes the reuse of content and layout possible.  In the
+example above, we've made use of the 'standard_html_header' DTML
+Method and the 'standard_html_footer' DTML Method, both of which
+live in the root folder, to insert HTML text into our page.  These
+DTML methods (and any other DTML method) can be used by other DTML
+methods to insert text into our rendered output.
+
+We've seen that DTML inserts an HTML header, an HTML footer, and a
+title into the web page.  But how does the "var" tag *find* the
+values that it inserts in place of "standard_html_header", "title"
+and "standard_html_footer"?
+
+DTML name lookup is somewhat "magical", because you don't need to
+explicitly tell DTML *where* to find a variable.  Instead, it
+tries to guess what you mean by following a preordained set of
+search rules.  DTML gets the values for variable names by
+searching an environment which includes the current object, the
+containment path, and request variables like values submitted by a
+form and cookies.  The `DTML Name Lookup Rules <AppendixE.html>`_
+represent the namespaces searched and their relative precedence.
+As an example, let's follow the 'pricelist' DTML code
+step-by-step.  In our 'pricelist' method, we've asked DTML to look
+up three names: "standard_html_header", "title", and
+"standard_html_footer".  It searches for these variables in the
+order that they are mentioned in the page.
+
+DTML looks first for "standard_html_header".  It looks in the
+"current object" first, which is its container, the 'Feedbags'
+folder. The 'Feedbags' folder doesn't have any methods or
+properties or sub-objects by that name. Next Zope tries to
+`acquire <Acquisition.html>`_ the object from its containers.  It
+examines the 'Feedbags' folder's container (your sandbox folder,
+likely named "DTML_Examples"), which also doesn't turn up
+anything.  It continues searching through any intermediate
+containters, which also don't have a method or property named
+"standard_html_header" unless you've put one there.  It keeps
+going until it gets to the root folder.  The root folder *does*
+have a sub-object named "standard_html_header", which comes as a
+default object in every Zope. The 'standard_html_header' object is
+a DTML Method. So Zope *calls* the 'standard_html_header' method
+in the root folder and inserts the results into the page.  Note
+that once DTML *finds* a property or variable, if it is callable
+(as in the case of a DTML Method, an External Method, a SQL
+Method, or a Script (Python) object), it is called and the results
+of the call are inserted into the page.
+
+Next DTML looks for the name "title". Here, the search is 
+shorter.  On its first try, DTML finds the 'Feedbags' folder's
+'title' property and inserts it.  The 'title' property is not a
+method or a script, so DTML doesn't need to *call* it.  It just
+renders it into the output.
+
+Finally DTML looks for the name *standard_html_footer*. It has to
+search all the way up to the root folder to find it, just like it
+looked for *standard_html_header*.  It calls the
+*standard_html_footer* in the root and inserts the text result.
+
+The resulting page is fully assembled (rendered) at this point,
+and is sent to your browser.
+
+Understanding how DTML looks up variables is important.  We will
+explore the DTML name lookup mechanism further in the chapter
+entitled `Variables and Advanced DTML <AdvDTML.html>`_.
+It is also documented in `Appendix E <AppendixE.html>`_.
+
+Formatting and Displaying Sequences
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is common that people want to use DTML to format and display
+*sequences*.  A sequence is just a list of items, like "Fred, Joe,
+Jim".  Often, you want to create an HTML table or a bulleted list
+that contains elements in a sequence.  Let's use DTML to call out
+to an object which returns a sequence and render its result.
+
+Create a Script (Python) object named "actors" in your
+sandbox folder. Give the script the following body and
+save it::
+
+  ## Script (Python) "actors"
+  ##bind container=container
+  ##bind context=context
+  ##bind namespace=
+  ##bind script=script
+  ##bind subpath=traverse_subpath
+  ##parameters=
+  ##title=
+  ##
+  return ['Jack Lemmon', 'Ed Harris','Al Pacino', 'Kevin Spacey', 'Alan Arkin']
+
+Make sure that all of the lines of this script line up along the
+left-hand side of the textarea to avoid receiving an error when
+you attempt to save the script, since Python is sensitive to
+indentation.  Don't worry about the '##'s for now, we will
+explain these later.  
+
+This Script (Python) object returns a Python data
+structure which is a *list* of *strings*.  A list is a kind of
+*sequence*, which means that DTML can *iterate* over it using the
+*dtml-in* tag.  Now create a DTML Method named "showActors" in
+your sandbox, give it this body, and save it::
+
+  <html>
+  <body>
+  <h1>Actors in the movie Glengarry Glen Ross</h1>
+  <table border="1">
+    <th>Name</th>
+  <dtml-in actors>
+    <tr>
+    <td><dtml-var sequence-item></td>
+    </tr>
+  </dtml-in>
+  </table>
+  </body>
+  </html>
+
+The DTML *in* tag iterates over the results of the *actors* script
+and inserts a table row into a table for each of the actors
+mentioned in the script.  Note that inside the table cell, we use
+a special name *sequence-item*.  *sequence-item* is a special name
+that is meaningful within a *dtml-in* tag.  It refers to the
+"current item" (in this case, the actor name string) during
+processing.  The HTML source of the Workspace frame when you click
+the *View* tab on the 'showActors' method will look something
+like::
+
+  <html>
+  <body>
+  <h1>Actors in the movie Glengarry Glen Ross</h1>
+  <table border="1">
+    <th>Name</th>
+          <tr>
+    <td>Jack Lemmon</td>
+
+    </tr>
+          <tr>
+    <td>Ed Harris</td>
+    </tr>
+          <tr>
+    <td>Al Pacino</td>
+    </tr>
+          <tr>
+
+    <td>Kevin Spacey</td>
+    </tr>
+          <tr>
+    <td>Alan Arkin</td>
+    </tr>
+        </table>
+  </body>
+  </html>
+
+Note that you didn't have to specifically tell DTML that you are
+querying a Script (Python) object.  You just tell it the name of
+the object to call (in this case 'actors'), and it does the work
+of figuring out how to call the object and pass it appropriate
+arguments. If you replace the 'actors' Script with some other kind
+of object that does exactly the same thing, like another DTML
+Method, you won't have to change your 'showActors' DTML Method.
+It will "just work".
+
+Processing Input from Forms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can use DTML to perform actions based on the information
+contained in the submission of an HTML form.
+
+Create a DTML Method named "infoForm" with the following body::
+
+  <dtml-var standard_html_header>
+
+  <p>Please send me information on your aardvark adoption
+  program.</p>
+
+  <form action="infoAction">
+  name: <input type="text" name="user_name"><br>
+  email: <input type="text" name="email_addr"><br>
+  <input type="submit" name="submit" value=" Submit ">
+  </form>
+
+  <dtml-var standard_html_footer>
+
+This is a web form that asks the user for information,
+specifically his user name and email address.  Note that you refer
+to the name "infoAction" as the *action* of the HTML form.  This
+really has nothing to do with DTML, it's an attribute of the HTML
+*form* tag.  But the name specified in the form action tag can
+name another Zope object which will receive and process the
+results of the form when it is submitted.
+
+Create a DTML Method named *infoAction* in the same folder as the
+'infoForm' method.  This is the *target* of the 'infoForm' form
+action.  This method will display a bland "thanks" message which
+includes the name and email information that was gathered from the
+web form.  Provide the *infoAction* method with the following body
+and save it::
+
+  <dtml-var standard_html_header>
+
+  <h1>Thanks <dtml-var user_name></h1>
+
+  <p>We received your request for information and will send you
+  email at <dtml-var email_addr> describing our aardvark adoption
+  program as soon as it receives final governmental approval.
+  </p>
+
+  <dtml-var standard_html_footer>
+
+Navigate back to the 'infoForm' method and use the *View* tab to
+execute it.  Fill out the form and click the *Submit* button. If
+all goes well you should see a thank you message that includes
+your name and email address, much like the figure below:
+
+.. figure:: Figures/aardvarkview.png
+
+   Result of submitting the infoForm method
+
+The Zope object named *REQUEST* contains information about the
+current web request.  This object is in the DTML name lookup path.
+The 'infoAction' method found the form information from the web
+request that happened when you clicked the submit button on the
+rendering of 'infoForm'.  DTML looks for variables in the current
+web request, so you can just refer to the form variable names in
+the target method by name.  In our case, we were able to display
+the values of the form elements *user_name* and *email_addr* in
+the 'infoAction' method just by referring to them by name in their
+respective *dtml-var* tags.  DTML used its `lookup
+rules <AppendixE.html>`_ to search for the variable names.  It found
+the names in the "REQUEST.form" namespace and displayed them.  If
+it had found an object with either name *email_addr* or
+*user_name* earlier in the lookup (if perhaps there was a Zope
+object in your acquisition path named 'user_name') it would have
+found this object first and rendered its results.  But, mostly by
+chance, it didn't, and found the name in REQUEST instead.
+
+Let's examine the contents of the Zope REQUEST object in order to
+shed more light on the situation.  Create a new DTML Method object
+named 'show_request' in your sandbox folder.  Give it the the
+following body::
+
+  <dtml-var REQUEST>
+
+The 'show_request' method will render a human-readable
+representation of Zope's REQUEST object when you click submit on
+the 'infoForm' rendering.  Visit the 'infoForm' method, and change
+it to the following::
+
+  <dtml-var standard_html_header>
+
+  <p>Please send me information on your aardvark adoption
+  program.</p>
+
+  <form action="show_request">
+  name: <input type="text" name="user_name"><br>
+  email: <input type="text" name="email_addr"><br>
+  <input type="submit" name="submit" value=" Submit ">
+  </form>
+
+  <dtml-var standard_html_footer>
+
+We changed the form action of the 'infoForm' method to
+*show_request*.  Now click the *View* tab of the new 'infoForm'
+method.  Fill in some information in the form elements, and click
+*Submit*.  You will see something like the following::
+
+  form
+   submit ' Submit '
+   email_addr 'chrism at zope.com'
+   user_name 'Chris'
+
+  cookies
+   tree-s 'eJzTiFZ3hANPW/VYHU0ALlYElA'
+
+  lazy items
+   SESSION <bound method SessionDataManager.getSessionData of <SessionDataManager instance at 897d020>
+
+  other
+   AUTHENTICATION_PATH ''
+   user_name 'Chris'
+   PUBLISHED <DTMLMethod instance at 8a62670>
+   submit ' Submit '
+   SERVER_URL 'http://localsaints:8084'
+   email_addr 'chrism at zope.com'
+   tree-s 'eJzTiFZ3hANPW/VYHU0ALlYElA'
+   URL 'http://localsaints:8084/DTML_Example/show_request'
+   AUTHENTICATED_USER admin
+   TraversalRequestNameStack []
+   URL0 http://localsaints:8084/DTML_Example/show_request
+   URL1 http://localsaints:8084/DTML_Example
+   URL2 http://localsaints:8084
+   BASE0 http://localsaints:8084
+   BASE1 http://localsaints:8084
+   BASE2 http://localsaints:8084/DTML_Example
+   BASE3 http://localsaints:8084/DTML_Example/show_request
+
+  environ
+   SCRIPT_NAME ''
+   HTTP_ACCEPT_ENCODING 'gzip, deflate, compress;q=0.9'
+   SERVER_PORT '8084'
+   PATH_TRANSLATED '/DTML_Example/show_request'
+   HTTP_ACCEPT 'text/xml...'
+   GATEWAY_INTERFACE 'CGI/1.1'
+   HTTP_COOKIE 'tree-s="eJzTiFZ3hANPW/VYHU0ALlYElA"'
+   HTTP_ACCEPT_LANGUAGE 'en-us, en;q=0.50'
+   REMOTE_ADDR '192.168.1.3'
+   SERVER_NAME 'saints'
+   HTTP_USER_AGENT 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1a+)'
+   HTTP_ACCEPT_CHARSET 'ISO-8859-1, utf-8;q=0.66, *;q=0.66'
+   CONNECTION_TYPE 'keep-alive'
+   channel.creation_time 1027876407
+   QUERY_STRING 'user_name=Chris&email_addr=chrism%40zope.com&submit=+Submit+'
+   SERVER_PROTOCOL 'HTTP/1.1'
+   HTTP_KEEP_ALIVE '300'
+   HTTP_HOST 'localsaints:8084'
+   REQUEST_METHOD 'GET'
+   PATH_INFO '/DTML_Example/show_request'
+   HTTP_REFERER 'http://localsaints:8084/DTML_Example/infoForm'
+
+You have instructed the 'show_request' method to render the
+contents of the web request initiated by the 'infoForm' method.
+Note that each section (form, cookies, lazy items, other, and
+environ) represents a *namespace* inside the REQUEST.  DTML
+searches all of these namespaces for the names you refer to in
+your 'infoForm' form.  Note that *email_addr* and *user_name* are
+in the "form" namespace of the REQUEST.  There is lots of
+information in the rendering of the REQUEST, but for us, this is
+the most pertinent.  For more information on the REQUEST object,
+visit the Zope Help system, and choose Zope Help -> API Reference
+-> Request.
+
+Dealing With Errors
+~~~~~~~~~~~~~~~~~~~
+
+Let's perform an experiment. What happens if you try to view the
+'infoAction' method you created in the last section directly, as
+opposed to getting to it by submitting the 'infoForm' method?
+Click on the 'infoAction' method and then click the *View* tab.
+You will see results not unlike those in the figure below.
+
+.. figure:: Figures/infokeyerror.png
+
+   DTML error resulting from a failed variable lookup
+
+Zope couldn't find the *user_name* variable since it was not in
+the current object, its containers or the web request. This is an
+error that you're likely to see frequently as you learn
+Zope. Don't fear, it just means that you've tried to insert a
+variable that Zope can't find.  You can examine the error by
+visiting the *error_log* object in your root folder.  In this
+case, we know why the error occurred, so visiting the error in the
+*error_log* isn't really necessary.  In this example, you need to
+either insert a variable that Zope can find, or use the 'missing'
+attribute on the var tag as described above::
+
+  <h1>Thanks <dtml-var user_name missing="Anonymous User"></h1>
+
+Understanding where DTML looks for variables will help you figure
+out how to fix this kind of problem.  In this case, you have
+viewed a method that needs to be called from an HTML form like
+*infoForm* in order to provide variables to be inserted in the
+output.
+
+Dynamically Acquiring Content
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Zope looks for DTML variables in the current object's containers
+(its parent folders) if it can't find the variable first in the
+current object. This behavior allows your objects to find and use
+content and behavior defined in their parents.  Zope uses the term
+*acquisition* to refer to this dynamic use of content and
+behavior.
+
+An example of acquisition that you've already seen is how web
+pages use standard headers and footers. To acquire the standard
+header just ask Zope to insert it with the *var* tag::
+
+  <dtml-var standard_html_header>
+
+It doesn't matter where the 'standard_html_method' object or
+property is located. Zope will search upwards in the object
+database until it finds the 'standard_html_header' that is defined
+in the root folder.
+
+You can take advantage of how Zope looks up variables to customize
+your header in different parts of your site. Just create a new
+'standard_html_header' in a folder and it will override global
+header for all web pages in your folder and below it.
+
+Create a new folder in your "sandbox" folder with an id of
+"Green". Enter the 'Green' folder and create a DTML Method with an
+id of "welcome". Edit the 'welcome' DTML Method to have these
+contents::
+
+  <dtml-var standard_html_header>
+
+  <p>Welcome</p>
+
+  <dtml-var standard_html_footer>
+
+Now view the 'welcome' method. It should look like a simple web
+page with the word *welcome*, as shown in the figure below.
+
+.. figure:: Figures/welcomedtml.png
+
+   Welcome method
+
+Now let's customize the header for the *Green* folder. Create a
+DTML Method in the *Green* folder with an id of
+"standard_html_header". Give it the following body::
+
+  <html>
+  <head>
+    <style type="text/css">
+    body {color: #00FF00;}
+    p {font-family: sans-serif;}
+    </style>
+  </head>
+  <body>
+
+Notice that this is not a complete web page. For example, it does
+not have an ending '</html>' tag.  This is just a fragment of HTML
+that will be used as a header, meant to be included into other
+pages. This header uses `CSS <http://www.w3.org/Style/CSS>`_
+(Cascading Style Sheets) to make some changes to the look and feel
+of web pages.
+
+Now revisit the 'welcome' method and click its *View* tab again.
+You will see something like the figure below:
+
+.. figure:: Figures/welcomegreen.png
+
+   Welcome method with custom header
+
+The rendering now looks quite different. This is because it is now
+using the new header we introduced in the 'Green' folder. This
+header will be used by all web pages in the 'Green' folder and its
+sub-folders.
+
+You can continue this process of overriding default content by
+creating another folder inside the 'Green' folder and creating a
+'standard_html_header' DTML Method there. Now web pages in the
+sub-folder will use their local header rather than the 'Green'
+folder's header.  You can of course also create a
+'standard_html_footer', providing it with local content as well.
+
+Using this pattern you can quickly change the look and feel of
+different parts of your website. If you later decide that an area
+of the site needs a different header, just create one. You don't
+have to change the DTML in any of the web pages; they'll
+automatically find the closest header and use it.
+
+Using Python Expressions from DTML
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+So far we've looked at simple DTML tags. Here's an example::
+
+  <dtml-var getHippo>
+
+This will insert the value of the variable named *getHippo*,
+whatever that may be.  DTML will automatically take care of the
+details, like finding the object which represents the variable and
+calling it if necessary. We call this basic tag syntax *name*
+syntax to differentiate it from *expression* syntax.
+
+When you use DTML name syntax, DTML tries to do the right thing to
+insert the results of the object looked up by the variable name,
+no matter what that object may be. In general this means that if
+the variable is another DTML Method or DTML Document, it will be
+called with appropriate arguments.  However, if the variable is
+*not* another DTML Method or DTML Document, and it requires
+parameters, you need to explicitly pass the arguments along using
+an expression.
+
+*Expressions* used in DTML allow you to be more explicit about how
+to find and call variables. Expressions are tag attributes that
+contain small snippets of code in the Python programming language.
+These are typically referred to as *Python expressions*.
+
+A Python expression is essentially any bit of code that *is not* a
+Python *statement*.  For example, the Python statement 'a = 1'
+assigns "1" to the "a" variable. You cannot use this statement in
+DTML expressions.  Likewise, you cannot use the statement 'print
+"x"' in DTML.  It is not an expression.  Essentially, an
+expression must be a combination of values, variables, and Python
+*operators*.  To find out more about Python's expression syntax,
+see the `Python Tutorial <http://docs.python.org/tutorial/>`_
+at the Python.org website.
+
+An expression always results in a return value.  For example, the
+Python expression "a == 5" returns the integer 1 if "a" is equal
+to the integer 5 or the integer 0 if "a" is not equal to the
+integer 5.  The return value of an expression is used by DTML as
+the *target* of the DTML command.
+
+The primary difference in DTML between using *expressions* as
+targets and *names* as targets is that DTML does some magic after
+it locates a *named* targets that it does not do after it finds an
+expression targets.  For example, after finding object with the
+name 'standard_html_header' in the root folder via the name-syntax
+DTML command '<dtml-var standard_html_header>', DTML *calls* the
+'standard_html_header' object, inserting the results into the
+page.  However, when you use an expression-syntax DTML command,
+like '<dtml-var expr="standard_html_header">', DTML *will not*
+call the 'standard_html_header' object.  Instead it will return a
+representation of the object as a string.  In order to *call* the
+'standard_html_header' object in an expression-syntax DTML tag,
+you need to do it explicitly by passing along arguments.  When you
+delve into the realm of DTML expression syntax, DTML "magic" goes
+away, and you need to become aware of the arguments accepted by
+the target (if any) and pass them along.
+
+Let's create a Script (Python) object named 'getHippo' that *must*
+be called in DTML with expression syntax, because it takes a
+non-optional argument that *named* DTML syntax cannot provide.
+
+Create a Script (Python) in your sandbox folder named *getHippo*.
+Provide it with the following body::
+
+  ## Script (Python) "getHippo"
+  ##bind container=container
+  ##bind context=context
+  ##bind namespace=
+  ##bind script=script
+  ##bind subpath=traverse_subpath
+  ##parameters=trap
+  ##title=
+  ##
+  return 'The hippo was captured with a %s.' % trap
+
+Note that this Script (Python) object takes a single parameter
+named "trap".  It is not an optional parameter, so we need to pass
+a value in to this script for it to do anything useful.
+
+Now let's make a DTML method to call 'getHippo'.  Instead of
+letting DTML find and call *getHippo*, we can use an expression to
+explicitly pass arguments.  Create a DTML method named *showHippo*
+and give it the following body::
+
+  <dtml-var expr="getHippo('large net')">
+
+Here we've used a Python expression to explicitly call the
+'getHippo' method with the string argument, 'large net'.  View the
+'showHippo' DTML Method.  It will return a result not unlike the
+following::
+
+    The hippo was captured with a large net.
+
+To see why we need to use expression syntax to call this script,
+let's modify the 'showHippo' method to use DTML name syntax::
+
+  <dtml-var getHippo>
+
+View the method.  You will receive an error not unlike the
+following::
+
+  Error Type: TypeError
+  Error Value: getHippo() takes exactly 1 argument (0 given)
+
+The 'getHippo' method requires that you pass in an argument,
+'trap', that cannot be provided using DTML name syntax.  Thus, you
+receive an error when you try to view the 'showHippo' method.
+
+Expressions make DTML pretty powerful. For example, using Python
+expressions, you can easily test conditions::
+
+    <dtml-if expr="foo < bar">
+      Foo is less than bar.
+    </dtml-if>
+
+Without expressions, this very simple task would have to be broken
+out into a separate method and would add a lot of overhead for
+something this trivial.
+
+Before you get carried away with expressions, take
+care. Expressions can make your DTML hard to understand. Code that
+is hard to understand is more likely to contain errors and is
+harder to maintain. Expressions can also lead to mixing logic in
+your presentation. If you find yourself staring blankly at an
+expression for more than five seconds, stop. Rewrite the DTML
+without the expression and use a Script to do your logic. Just
+because you can do complex things with DTML doesn't mean you
+should.
+
+DTML Expression Gotchas
+%%%%%%%%%%%%%%%%%%%%%%%
+
+Using Python expressions can be tricky. One common mistake is
+to confuse expressions with basic tag syntax. For example::
+
+  <dtml-var objectValues>
+
+and::
+
+  <dtml-var expr="objectValues">
+
+These two examples if you are to put them in a DTML Method will
+end up giving you two completely different results. The first
+example of the DTML *var* tag will automatically *call* the
+object which is represented by *objectValues*. 
+
+In an expression, you have complete control over the variable
+rendering.  In the case of our example, *objectValues* is a
+method implemented in Python which returns the values of the
+objects in the current folder.  It has no required arguments.
+So::
+
+  <dtml-var objectValues>
+
+will call the method. However::
+
+  <dtml-var expr="objectValues">
+
+will *not* call the method, it will just try to insert
+it. The result will be not a list of objects but a string such
+as '<Python Method object at 8681298>'. If you ever see results
+like this, there is a good chance that you're returning a
+method, rather than calling it.
+
+To call a Python method which requires no arguments from an
+expression, you must use standard Python calling syntax by using
+parenthesis::
+
+  <dtml-var expr="objectValues()">
+
+The lesson is that if you use Python expressions you must know
+what kind of variable you are inserting and must use the proper
+Python syntax to appropriately render the variable.
+
+Before we leave the subject of variable expressions we should
+mention that there is a deprecated form of the expression
+syntax. You can leave out the "expr=" part on a variable
+expression tag.  But *please* don't do this.  It is far too easy
+to confuse::
+
+  <dtml-var aName>
+
+with::
+
+  <dtml-var "aName">
+
+and get two completely different results.  These "shortcuts" were
+built into DTML long ago, but we do not encourage you to use them now
+unless you are prepared to accept the confusion and debugging
+problems that come from this subtle difference in syntax.
+
+Common DTML Tags
+----------------
+
+Below, we discuss the most common DTML tags: the *var* tag, the
+*if* tag, the *else* tag, the *elif* tag, and the *in* tag,
+providing examples for the usage of each.
+
+The *Var* Tag
+~~~~~~~~~~~~~
+
+The *var* tag inserts variables into DTML Methods and Documents.  We've
+already seen many examples of how the *var* tag can be used to insert
+strings into web pages.
+
+As you've seen, the *var* tag looks up variables first in the
+current object, then in its containers and finally in the web
+request.
+
+The *var* tag can also use Python expressions to provide more
+control in locating and calling variables.
+
+*Var* Tag Attributes
+%%%%%%%%%%%%%%%%%%%%
+
+You can control the behavior of the *var* tag using its
+attributes. The *var* tag has many attributes that help you in
+common formatting situations. The attributes are summarized in
+Appendix A. Here's a sampling of *var* tag attributes.
+
+html_quote
+  This attribute causes the inserted values to be HTML quoted. This means that
+  '<', '>' and '&' are escaped. Note that all string values which are retrieved
+  from the REQUEST namespace are HTML-quoted by default. This helps to prevent
+  "cross-site scripting" security holes, where a user could insert some clever
+  JavaScript into a page in order to possibly make you divulge information to
+  him which could be private. For more information, see the `CERT advisory
+  <http://www.cert.org/advisories/CA-2000-02.html>`_ on the topic.
+
+missing
+  The missing attribute allows you to specify a default value to use in
+  case Zope can't find the variable. For example::
+
+    <dtml-var bananas missing="We have no bananas">
+
+fmt
+  The fmt attribute allows you to control the format of the *var* tags
+  output. There are many possible formats which are detailed in `Appendix
+  A <AppendixA.html>`_.
+
+  One use of the *fmt* attribute is to format monetary
+  values. For example, create a *float* property in your root
+  folder called *adult_rate*.  This property will represent
+  the cost for one adult to visit the Zoo.  Give this property
+  the value '2.2'.
+
+  You can display this cost in a DTML Document or Method like so::
+
+    One Adult pass: <dtml-var adult_rate fmt=dollars-and-cents>
+
+  This will correctly print "$2.20". It will round more
+  precise decimal numbers to the nearest penny.
+
+
+*Var* Tag Entity Syntax
+%%%%%%%%%%%%%%%%%%%%%%%
+
+Zope provides a shortcut DTML syntax just for the simple *var*
+tag.  Because the *var* tag is a singleton, it can be represented
+with an *HTML entity* like syntax::
+
+  &dtml-cockatiel;
+
+This is equivalent to::
+
+  <dtml-var name="cockatiel" html_quote>
+
+Entity-syntax-based DTML tags always "html quote" their
+renderings.  The main reason to use the entity syntax is to
+avoid putting DTML tags inside HTML tags. For example, instead
+of writing::
+
+  <input type="text" value="<dtml-var name="defaultValue" html_quote>">
+
+You can use the entity syntax to make things more readable for
+you and your text editor::
+
+  <input type="text" value="&dtml-defaultValue;">
+
+The *var* tag entity syntax is very limited. You can't use
+Python expressions within entity-based DTML syntax and many DTML
+attributes won't work with it. See `Appendix A`_
+for more information on *var* tag entity syntax.
+
+The *If* Tag
+~~~~~~~~~~~~
+
+One of DTML's important benefits is to let you customize your web
+pages. Often customization means testing conditions and responding
+appropriately.  This *if* tag lets you evaluate a condition and
+carry out different actions based on the result.
+
+What is a condition?  A condition is either a true or false
+value. In general all objects are considered true unless they are
+0, None, an empty sequence or an empty string.
+
+Here's an example condition:
+
+objectValues
+  True if the variable *objectValues* exists and
+  is true. That is to say, when found and rendered *objectValues*
+  is not 0, None, an empty sequence, or an empty string.
+
+As with the *var* tag, you can use both name syntax and expression
+syntax. Here are some conditions expressed as DTML expressions.
+
+expr="1"
+  Always true.
+
+expr="rhino"
+  True if the rhino variable is true.
+
+expr="x < 5"
+  True if x is less than 5.
+
+expr="objectValues('File')"
+  True if calling the *objectValues* method with an argument of *File*
+  returns a true value.  This method is explained in more detail in this
+  chapter.
+
+The *if* tag is a block tag. The block inside the *if* tag is executed
+if the condition is true.
+
+Here's how you might use a variable expression with the *if* tag to
+test a condition::
+
+  <p>How many monkeys are there?</p>
+
+  <dtml-if expr="monkeys > monkey_limit">
+    <p>There are too many monkeys!</p>
+  </dtml-if>
+
+In the above example, if the Python expression 'monkeys > monkey_limit'
+is true then you will see the first and the second paragraphs of
+HTML. If the condition is false, you will only see the first.
+
+*If* tags can be nested to any depth, for example, you
+could have::
+
+  <p>Are there too many blue monkeys?</p>
+
+  <dtml-if "monkeys.color == 'blue'">
+    <dtml-if expr="monkeys > monkey_limit">
+      <p>There are too many blue monkeys!</p>
+    </dtml-if>
+  </dtml-if>
+
+Nested *if* tags work by evaluating the first condition, and if that
+condition is true, then they evaluate the second
+condition.  In general, DTML *if* tags work very much like
+Python *if* statements...
+
+Name and Expression Syntax Differences
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+The name syntax checks for the *existence* of a name, as well as
+its value. For example::
+
+  <dtml-if monkey_house>
+    <p>There <em>is</em> a monkey house, Mom!</p>
+  </dtml-if>  
+
+If the *monkey_house* variable does not exist, then this condition
+is false. If there is a *monkey_house* variable but it is false,
+then this condition is also false. The condition is only true is
+there is a *monkey_house* variable and it is not 0, None, an empty
+sequence or an empty string.
+
+The Python expression syntax does not check for variable
+existence. This is because the expression must be valid
+Python. For example::
+
+  <dtml-if expr="monkey_house">
+    <p>There <em>is</em> a monkey house, Mom!</p>
+  </dtml-if>
+
+This will work as expected as long as *monkey_house* exists.  If
+the *monkey_house* variable does not exist, Zope will raise a
+*KeyError* exception when it tries to find the variable.
+
+*Else* and *Elif* Tags
+%%%%%%%%%%%%%%%%%%%%%%
+
+The *if* tag only lets you take an action if a condition is
+true. You may also want to take a different action if the
+condition is false.  This can be done with the DTML *else* tag.
+The *if* block can also contain an *else* singleton tag. For
+example::
+
+  <dtml-if expr="monkeys > monkey_limit">
+    <p>There are too many monkeys!</p>
+  <dtml-else>
+    <p>The monkeys are happy!</p>
+  </dtml-if>
+
+The *else* tag splits the *if* tag block into two blocks, the first
+is executed if the condition is true, the second is executed if
+the condition is not true.
+
+A *if* tag block can also contain a *elif* singleton tag. The *elif*
+tag specifies another condition just like an addition *if* tag.
+This lets you specify multiple conditions in one block::
+
+  <dtml-if expr="monkeys > monkey_limit">
+    <p>There are too many monkeys!</p>
+  <dtml-elif expr="monkeys < minimum_monkeys">
+    <p>There aren't enough monkeys!</p>
+  <dtml-else>
+    <p>There are just enough monkeys.</p>
+  </dtml-if>
+
+An *if* tag block can contain any number of *elif* tags but only
+one *else* tag. The *else* tag must always come after the *elif*
+tags.  *Elif* tags can test for condition using either the name
+or expression syntax.
+
+Using Cookies with the *If* Tag
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Let's look at a more meaty *if* tag example.  Often when you have
+visitors to your site you want to give them a cookie to identify
+them with some kind of special value.  Cookies are used frequently
+all over the Internet, and when they are used properly they are
+quite useful.
+
+Suppose we want to differentiate new visitors from folks who have
+already been to our site. When a user visits the site we can set a
+cookie. Then we can test for the cookie when displaying pages. If
+the user has already been to the site they will have the
+cookie. If they don't have the cookie yet, it means that they're
+new.
+
+Suppose we're running a special. First time zoo visitors get in
+for half price. Here's a DTML fragment that tests for a cookie
+using the *hasVisitedZoo* variable and displays the price
+according to whether a user is new or a repeat visitor::
+
+  <dtml-if hasVisitedZoo>
+    <p>Zoo admission <dtml-var adult_rate fmt="dollars-and-cents">.</p>
+  <dtml-else>
+    <p>Zoo admission for first time visitors
+         <dtml-var expr="adult_rate/2" fmt="dollars-and-cents"></p>
+  </dtml-if>  
+
+This fragment tests for the *hasVisitedZoo* variable. If the user
+has visited the zoo before it displays the normal price for
+admission. If the visitor is here for the first time they get in
+for half-price.
+
+Just for completeness sake, here's an implementation of the
+*hasVisitedZoo* method as a Python-based Script that has no
+parameters.::
+
+  ## Script(Python) "hasVisitedZoo"
+  ##
+  """
+  Returns true if the user has previously visited
+  the Zoo. Uses cookies to keep track of zoo visits.
+  """
+  request = context.REQUEST
+  response = request.RESPONSE
+  if request.has_key('zooVisitCookie'):
+      return 1
+  else:
+      response.setCookie('zooVisitCookie', '1')
+      return 0
+
+In the chapter entitled `Advanced Zope Scripting <ScriptingZope.html>`_,
+we'll look more closely at how to script business logic with Python.  For
+now it is sufficient to see that the method looks for a cookie and returns
+a true or false value depending on whether the cookie is found or not.
+Notice how Python uses if and else statements just like DTML uses if and
+*else* tags. DTML's *if* and *else* tags are based on Python's. In fact
+Python also has an elif statement, just like DTML.
+
+The *In* Tag
+~~~~~~~~~~~~
+
+The DTML *in* tag iterates over a sequence of objects, carrying out
+one block of execution for each item in the sequence.  In
+programming, this is often called *iteration*, or *looping*.
+
+The *in* tag is a block tag like the *if* tag.  The content of the *in*
+tag block is executed once for every iteration in the *in* tag
+loop. For example::
+
+  <dtml-in todo_list>
+    <p><dtml-var description></p>
+  </dtml-in>
+
+This example loops over a list of objects named *todo_list*. For
+each item, it inserts an HTML paragraph with a description of
+the to do item.
+
+Iteration is very useful in many web tasks.  Consider a site that
+display houses for sale.  Users will search your site for houses
+that match certain criteria.  You will want to format all of those
+results in a consistent way on the page, therefore, you will need
+to iterate over each result one at a time and render a similar
+block of HTML for each result.
+
+In a way, the contents of an *in* tag block is a kind of *template*
+that is applied once for each item in a sequence.
+
+Iterating over Folder Contents
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Here's an example of how to iterate over the contents of a
+folder. This DTML will loop over all the files in a folder and
+display a link to each one.  This example shows you how to
+display all the "File" objects in a folder, so in order to run
+this example you will need to upload some files into Zope as
+explained in the chapter entitled `Basic Zope Objects <BasicObject.rst>`_.
+Create a DTML Method with the following body::
+
+  <dtml-var standard_html_header>
+  <ul>
+  <dtml-in expr="objectValues('File')">
+    <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></li>
+  </dtml-in>
+  </ul>
+  <dtml-var standard_html_footer>
+
+This code displayed the following file listing, as shown in the
+figure below.
+
+.. figure:: Figures/4-4.png
+
+   Iterating over a list of files
+
+Let's look at this DTML example step by step.  First, the *var*
+tag is used to insert your common header into the method.  Next,
+to indicate that you want the browser to draw an HTML bulleted
+list, you have the *ul* HTML tag.
+
+Then there is the *in* tag.  The tag has an expression that is
+calling the Zope API method called *objectValues*.  This method
+returns a sequence of objects in the current folder that match a
+given criteria.  In this case, the objects must be files.  This
+method call will return a list of files in the current folder.
+
+The *in* tag will loop over every item in this sequence.  If there are
+four file objects in the current folder, then the *in* tag will execute
+the code in its block four times; once for each object in the
+sequence.
+
+During each iteration, the *in* tag looks for variables in the
+current object, first. In the chapter entitled `Variables and
+Advanced DTML`_ we'll look more closely at how DTML
+looks up variables.
+
+For example, this *in* tag iterates over a collection of File
+objects and uses the *var* tag to look up variables in each
+file::
+
+  <dtml-in expr="objectValues('File')">
+    <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></li>
+  </dtml-in>
+
+The first *var* tag is an entity and the second is a normal DTML
+*var* tag.  When the *in* tag loops over the first object its
+*absolute_url* and *title_or_id* variables will be inserted in
+the first bulleted list item::
+
+  <ul>
+    <li><a href="http://localhost:8080/FirstFile">FirstFile</a></li>
+
+During the second iteration the second object's *absolute_url*
+and *title_or_id* variables are inserted in the output::
+
+  <ul>
+    <li><a href="http://localhost:8080/FirstFile">FirstFile</a></li>
+    <li><a href="http://localhost:8080/SecondFile">SecondFile</a></li>
+
+This process will continue until the *in* tag has iterated over
+every file in the current folder.  After the *in* tag you
+finally close your HTML bulleted list with a closing *ul* HTML
+tag and the *standard_html_footer* is inserted.
+
+*In* Tag Special Variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+The *in* tag provides you with some useful information that
+lets you customize your HTML while you are iterating over a
+sequence.  For example, you can make your file library easier to
+read by putting it in an HTML table and making every other table
+row an alternating color, like this, as shown in the figure below.
+
+.. figure:: Figures/4-5.png
+
+   File listing with alternating row colors
+
+The *in* tag makes this easy.  Change your file library method a
+bit to look like this::
+
+  <dtml-var standard_html_header>
+
+  <table>
+  <dtml-in expr="objectValues('File')">
+    <dtml-if sequence-even>
+      <tr bgcolor="grey">
+    <dtml-else>
+      <tr>
+    </dtml-if>    
+    <td>
+    <a href="&dtml-absolute_url;"><dtml-var title_or_id></a>
+    </td></tr>
+  </dtml-in>
+  </table>
+
+  <dtml-var standard_html_footer>
+
+Here an *if* tag is used to test for a special variable called
+'sequence-even'.  The *in* tag sets this variable to a true or false
+value each time through the loop.  If the current iteration number is
+even, then the value is true, if the iteration number is odd, it is
+false.
+
+The result of this test is that a *tr* tag with either a gray
+background or no background is inserted for every other object in
+the sequence.  As you might expect, there is a 'sequence-odd' that
+always has the opposite value of 'sequence-even'.
+
+There are many special variables that the *in* tag defines for you.  Here
+are the most common and useful:
+
+sequence-item
+  This special variable is the current item in the
+  iteration.
+
+  In the case of the file library example, each time through the loop
+  the current file of the iteration is assigned to sequence-item.  It
+  is often useful to have a reference to the current object in the
+  iteration.
+
+sequence-index
+  the current number, starting from 0, of iterations
+  completed so far.  If this number is even, 'sequence-even' is true and
+  'sequence-odd' is false.
+
+sequence-number
+  The current number, starting from 1, of iterations
+  completed so far.  This can be thought of as the cardinal position
+  (first, second, third, etc.) of the current object in the loop.
+  If this number is even, 'sequence-even' is false and 'sequence-odd'
+  is true.
+
+sequence-start
+  This variable is true for the very first iteration.
+
+sequence-end
+  This variable is true for the very last iteration.
+
+These special variables are detailed more thoroughly in `Appendix A`_.
+
+Summary
+-------
+
+DTML is a powerful tool for creating dynamic content. It allows you to
+perform fairly complex calculations. In the chapter entitled `Variables and
+Advanced DTML`_, you'll find out about many more DTML tags, and more
+powerful ways to use the tags you already have seen. Despite its power, you
+should resist the temptation to use DTML for complex scripting. In the
+chapter entitled `Advanced Zope Scripting`_ you'll find out about how to
+use Python for scripting business logic.

Copied: zope2docs/branches/baijum-reorganize/zope2book/ExternalTools.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/ExternalTools.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/ExternalTools.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/ExternalTools.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,480 @@
+Managing Zope Objects Using External Tools
+##########################################
+
+So far, you've been working with Zope objects in your web browser via the Zope
+Management Interface. This chapter details how to use common non-browser-based
+common to access and modify your Zope content.
+
+Editing Zope content and code in the Zope Management Interface is sometimes
+painful, especially when dealing with Python code, DTML, ZPT, or even just
+HTML. The standard TEXTAREA text manipulation widget provided by most browsers
+has an extremely limited feature set: no syntax highlighting, no auto-indent, no
+key re-bindings, no WYSIWYG HTML editing, and sometimes not even a search and
+replace function!
+
+In short, people want to use their own tools, or at least more feature-rich
+tools, to work with Zope content.
+
+It is possible under most operating systems to use the text "cut and paste"
+facility (Ctrl-C, Ctrl-V under Windows, for example) to move text between
+traditional text/HTML editors and your browser, copying data back and forth
+between the Zope Management interface and your other tools. This is, at best,
+cumbersome.
+
+Luckily, Zope provides features that may allow you to interface Zope directly
+with your existing tools. This chapter describes these features, as well as the
+caveats for working with them.
+
+General Caveats
+===============
+
+Most external tools expect to deal with "file-like" content. Zope objects are
+not really files in the strict sense of the word so there are caveats to using
+external tools with Zope:
+
+- Zope data is not stored in files in the filesystem. Thus, tools which only
+  work on files will not work with Zope without providing a "bridge" between
+  the tool and Zope's file-like representation of its object database. This
+  "bridge" is typically accomplished using Zope's FTP or WebDAV features.
+
+- Zope doesn't enforce any file extension rules when creating objects. Some
+  tools don't deal well with objects that don't have file extensions in their
+  names (notably Macromedia Dreamweaver). To avoid this issue, you may name
+  your objects with file extensions according to their type (e.g. name all of
+  your ZPT objects with an `.html` file extension), or use a tool that
+  understands extension-less "files". However, this approach has numerous
+  drawbacks.
+
+- Creating new objects can sometimes be problematic. Because Zope doesn't have
+  a default object-type-to-file-extension policy, new content will often be
+  created as the wrong "kind" of object. For example, if you upload an HTML
+  file "foo.html" via FTP to a place where "foo.html" did not previously exist,
+  it will be created (by default) as a DTML Document object, whereas you may
+  want it to be created as a Zope Page Template. Zope provides a facility to
+  specify the object type created on a per-folder and per-request basis
+  (PUT_factory) that is detailed in this chapter.
+
+- External tools don't know about Zope object properties. If you modify an
+  object in an external tool, it may forget its property list.
+
+- Some external tools have semantics that can drive Zope crazy. For instance,
+  some like to create backup files with an id that is invalid for Zope. Also,
+  some tools will do a move-then-copy when saving, which creates a new Zope
+  object that is divorced from the history of the original object.
+
+- There is nowhere to send meaningful error messages. These integration
+  features expect a finite set of errors defined by the protocol. Thus, the
+  actual problem reported by Zope, such as a syntax error in a page template,
+  cannot be displayed to the user.
+
+- The interactions between the tools and Zope can vary widely. On the client
+  side, different versions of software have different bugs and features. For
+  instance, using FTP under Emacs will sometimes work by default, but sometimes
+  it needs to be configured. Also, Microsoft has many different implementations
+  of DAV in Windows and Office, each with changes that make life difficult.
+
+- Finally, the semantics of Zope can interfere with the experience. The same
+  file on your hard drive, when copied into www.zope.org and your local copy of
+  Zope, will have different results. In the case of the CMF, Zope will actually
+  alter what you saved (to add metadata).
+
+These caveats aside, you may use traditional file manipulation tools to manage
+most kinds of Zope objects.
+
+FTP and WebDAV
+==============
+
+Most Zope "file-like" objects like DTML Methods, DTML Documents, Zope Page
+Templates, Script (Python) objects and others can be edited with FTP and
+WebDAV. Many HTML and text editors support these protocols for editing
+documents on remote servers. Each of these protocols has advantages and
+disadvantages:
+
+- FTP
+
+  FTP is the File Transfer Protocol. FTP is used to transfer files from one
+  computer to another. Many text editors and HTML editors support FTP.
+
+  Some examples of editors and applications that support FTP are Homesite,
+  KDE suite of applications (Kate, Quanta, Kwrite, Konqueror), Bluefish, and
+  Dreamweaver.
+
+- WebDAV
+
+  `WebDAV <http://www.webdav.org/>`_ is a new Internet protocol based on the
+  Web's underlying protocol, HTTP. DAV stands for Distributed Authoring and
+  Versioning. Because DAV is new, it may not be supported by as many text and
+  HTML editors as FTP.
+
+Using FTP to Manage Zope Content
+================================
+
+There are many popular FTP clients, and many web browsers like Netscape and
+Microsoft Internet Explorer come with FTP clients. Many text and HTML editors
+also directly support FTP. You can make use of these clients to manipulate Zope
+objects via FTP.
+
+Determining Your Zope's FTP Port
+++++++++++++++++++++++++++++++++
+
+In the chapter entitled "Using the Zope Management Interface", you determined
+the HTTP port of your Zope system by looking at Zope's start-up output. You can
+find your Zope's FTP port by following the same process::
+
+  ------
+  2000-08-07T23:00:53 INFO(0) ZServer Medusa (V1.18) started at Mon Aug  7 
+  16:00:53 2000
+  Hostname: peanut
+  Port:8080
+
+  ------
+  2000-08-07T23:00:53 INFO(0) ZServer FTP server started at Mon Aug  7   16:00:53 2000
+  Authorizer:None
+  Hostname: peanut
+  Port: 8021
+  ------
+  2000-08-07T23:00:53 INFO(0) ZServer Monitor Server (V1.9) started on port 8099  
+
+The startup log says that the Zope FTP server is listening to port 8021 on the
+machine named *peanut*>. If Zope doesn't report an "FTP server started", it
+likely means that you need to turn Zope's FTP server on by editing the
+necessary incantation in your INSTANCE_HOME/etc/zope.conf as detailed in the
+chapter entitled `Installing and Starting Zope <InstallingZope.stx>`_.
+
+Transferring Files with WS_FTP
+++++++++++++++++++++++++++++++
+
+*WS_FTP* is a popular FTP client for Windows that you can use to transfer
+documents and files between Zope and your local computer. WS_FTP can be
+downloaded from the `Ipswitch Home Page <http://www.ipswitch.com/>`_.
+
+Too transfer objects between your Zope server and local computer:
+
+- start WS_FTP and enter the Zope IP address or machine name and port
+  information.
+
+- Click the "Connect" button.
+
+- Enter your management username and password for the Zope management
+  interface.
+
+If you type in your username and password correctly, WS_FTP shows you what your
+Zope site looks like through FTP. There are folders and documents that
+correspond exactly to what your root Zope folder looks like through the web, as
+shown in the figure below.
+
+`Viewing the Zope object hierarchy through FTP <img:5-1:Figures/3-3.png>`_
+
+Transferring files to and from Zope is straightforward when using WS_FTP. On
+the left-hand side of the WS_FTP window is a file selection box that represents
+files on your local machine.
+
+The file selection box on the right-hand side of the WS_FTP window represents
+objects in your Zope system. Transferring files from your computer to Zope or
+back again is a matter of selecting the file you want to transfer and clicking
+either the left arrow (download) or the right arrow (upload).
+
+You may transfer Zope objects to your local computer as files using WS_FTP. You
+may then edit them and upload them to Zope again when you're finished.
+
+Transferring files with KDE's Konqueror
++++++++++++++++++++++++++++++++++++++++
+
+KDE is one of the many popular window manager for Unix. KDE comes with many
+applications that is FTP enabled. One such application is Konqueror. Konqueror
+is a file manager, and also works as a browser.
+
+To use Konqueror to transfer files to your zope site:
+
+- enter ftp://username@your.server.com:port
+
+- Enter your username and password when prompted.
+
+Once the correct password is presented, you can now transfer files to and from
+your zope site.
+
+With Konqueror, you can split the Konqueror view, and make it to mimic WS_FTP,
+or Midnight Commander (a popular menu based file manager), as shown in the
+figure below.
+
+`Viewing the Zope object hierarchy with Konqueror <img:5-2:Figures/konq.png>`_
+
+We can also edit, create or delete some known Zope objects like folder or ZPT.
+For instance, to edit a file-like object, right click > Open With > Choose
+Application > Kate. You can start editing away. Kate will do the necessary when
+you save your edits.
+
+Transferring files with MS Internet Explorer 6+
++++++++++++++++++++++++++++++++++++++++++++++++
+
+MS Internet Explorer version 6 and above can also do FTP. To use MS Internet
+Explorer to move files between your desktop and Zope:
+
+- enter ftp://your.server.com:port
+
+- click "File" > "Login as".
+
+- Enter your username and password when prompted.
+
+You can then create new Folders and transfer files between Zope and your
+desktop, as shown in the figure below.
+
+`Viewing the Zope object hierarchy with IE <img:5-3:Figures/ie.png>`_
+
+Remote Editing with FTP/DAV-Aware Editors
++++++++++++++++++++++++++++++++++++++++++
+
+Editing Zope Objects with Emacs FTP Modes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Emacs is a very popular text editor. Emacs comes in two major "flavors", GNU
+Emacs and XEmacs. Both of these flavors of Emacs can work directly over FTP to
+manipulate Zope documents and other textual content.
+
+Emacs will let you treat any remote FTP system like any other local filesystem,
+making remote management of Zope content a fairly straightforward matter. More
+importantly, you need not leave Emacs in order to edit content that lives
+inside your Zope.
+
+To log into Zope, run Emacs. The file you visit to open an FTP connection
+depends on which text editor you are running: XEmacs or Emacs:
+
+Xemacs
+  To visit a remote directory in XEmacs, press Ctrl-X D and enter a directory
+  specification in the form: `/user at server#port:/` This will open a "dired"
+  window to the / folder of the FTP server running on *server* and listening on
+  port *port*.
+
+Emacs
+  To visit a remote directory in Emacs, press Ctrl-X D and enter a directory
+  specification in the form: `/user at server port:/` The literal space is
+  inserted by holding down the Control key and the Q key, and then pressing the
+  space "C-Q".
+
+For the typical Zope installation with XEmacs, the filename to open up an FTP
+session with Zope is */user at localhost#8021:/*.
+
+Emacs will ask you for a password before displaying the directory contents. The
+directory contents of the root folder will look a little like the picture
+below:
+
+`Viewing the Zope Root Folder via ange-ftp <img:5-2:Figures/emacsftp.png>`_
+
+You can visit any of these "files" (which are really Zope objects) by selecting
+them in the usual Emacs way: enter to select, modify the file, Ctrl-X S to
+save, etc. You can even create new "files" by visiting a file via "Ctrl-X
+Ctrl-F". New files will be created as DTML Document objects unless you have a
+PUT_factory (described below) installed to specify a different kind of initial
+object.
+
+The ftp program that ships with Microsoft Windows is incompatible with NTEmacs
+(the Windows NT version of GNU Emacs). To edit Zope objects via "ange-ftp"
+under NTEmacs, it requires that you have a special FTP program. This program
+ships with "Cygwin", a UNIX implementation for Windows. To use NTEmacs download
+and install `Cygwin <http://www.cygwin.org>`_ and add the following to your
+`.emacs` configuration file::
+
+  (setq ange-ftp-ftp-program-name "/cygwin/bin/ftp.exe")
+  (setq ange-ftp-try-passive-mode t)
+  (setq ange-ftp-ftp-program-args '("-i" "-n" "-g" "-v" "--prompt" ""))
+
+Caveats With FTP
+~~~~~~~~~~~~~~~~
+
+In addition to the general caveats listed above, using FTP with Zope has some
+unique caveats:
+
+- You need to be aware of passive mode for connecting to Zope.
+
+- The "move-then-copy" problem is most apparent when using Emacs' ange-ftp.
+
+Editing Zope objects with KDE Desktop
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+KDE comes with many applications that is FTP aware. For example, Kate, Kwrite,
+Quanta, Konqueror, and many more.
+
+To start editing objects with Kate:
+
+- Click "File" > "Open".
+
+- Enter the location "ftp://user@server:port/"
+
+- Browse and select the zope object you want to edit.
+
+Once selected, you can edit to your heart's content, and click "File" > "Save"
+when done. Kate will save your edit to your zope server.
+
+`Viewing the Zope Root Folder via Kate/KDE desktop <img:5-2:Figures/kateftp.png>`_
+
+With KDE, you can also mount zope onto your dialog box. To do that:
+
+- click "File" > "Open".
+
+- Right click on the listed locations in the "Open" dialog box
+
+- Click "Add Entry".
+
+- Fill in "Zope ftp" or any other description in the description field.
+
+- Enter the URL "ftp://user@server:port/" in the location field.
+
+- Select your icon.
+
+Now, you can edit zope objects in a single click.
+
+`Zope root exposed to KDE desktop <img:5-2:Figures/kdeopen.png>`_
+
+
+Editing Zope Objects with WebDAV
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+WebDAV is an extension to the HTTP protocol that provides features that allow
+users to concurrently author and edit content on websites. WebDAV offers
+features like locking, revision control, and the tagging of objects with
+properties. Because WebDAV's goals of through the web editing match some of the
+goals of Zope, Zope has supported the WebDAV protocol for a fairly long time.
+
+WebDAV is a newer Internet protocol compared to HTTP or FTP, so there are fewer
+clients that support it. There is, however, growing momentum behind the WebDAV
+movement and more clients are being developed rapidly.
+
+The WebDAV protocol is evolving quickly, and new features are being added all
+the time. You can use any WebDAV client to edit your Zope objects by simply
+pointing the client at your object's URL and editing it. For most clients,
+however, this will cause them to try to edit the *result* of rendering the
+document, not the *source*>. For DTML or ZPT objects, this can be a problem.
+
+Until clients catch up to the latest WebDAV standard and understand the
+difference between the source of a document and its result, Zope offers a
+special HTTP server you can enable. To enable Zope's WebDAV source server,
+enter the following in zope.conf::
+
+  <webdav-source-server>
+    # valid keys are "address" and "force-connection-close"
+    address 8022
+    force-connection-close off
+  </webdav-source-server>
+
+This server listens on a different port than your normal HTTP server and
+returns different, special source content for WebDAV requests that come in on
+that port.
+
+For more information about starting Zope with a WebDAV source port turned on,
+see the chapter entitled `Installing and Starting Zope <InstallingZope.stx>`_.
+The "standard" WebDAV source port number (according to IANA) is 9800.
+
+Unfortunately, this entire discussion of source vs. rendered requests is too
+esoteric for most users, who will try the regular port. Instead of breaking, it
+will work in very unexpected ways, leading to confusion. Until DAV clients
+support the standard's provision for discovering the source URL, this
+distinction will have to be confronted.
+
+Note
+----
+
+Zope has optional support for returning the source version of a resource on the
+normal HTTP port. It does this by inspecting the user agent header of the HTTP
+request. If the user agent matches a string you have configured into your
+server settings, the source is returned.
+
+This is quite useful, as there are few cases in which authoring tools such as
+cadaver or Dreamweaver will want the rendered version. For more information on
+this optional support, read the section "Environment Variables That Affect Zope
+At Runtime" in `Installing and Starting Zope <InstallingZope.stx>`_.
+
+Editing Zope objects with cadaver
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One program that supports WebDAV is a command-line tool named `cadaver`. It is
+available for most UNIX systems (and Cygwin under Windows) from `WebDAV.org
+<http://www.webdav.org/cadaver/>`_.
+
+It is typically invoked from a command-line using the command `cadaver` against
+Zope's WebDAV "source port"::
+
+  $ cadaver
+  dav:!> open http://saints.homeunix.com:9800/
+  Looking up hostname... Connecting to server... connected.
+  Connecting to server... connected.
+  dav:/> ls
+  Listing collection `/': (reconnecting...done) succeeded.
+  Coll:  Control_Panel                           0  Jun  14:03
+  Coll:  ZopeBook                                0  Jul  22:57
+  Coll:  temp_folder                             0  Jul  19:47
+  Coll:  tutorial                                0  Jun  00:42
+  acl_users                               0  Dec   2009
+  browser_id_manager                      0  Jun  14:01
+  index_html                             93  Jul  01:01
+  session_data_manager                    0  Jun  14:01
+  standard_error_message               1365  Jan   2009
+  dav:/>
+
+Cadaver allows you to invoke an editor against files while inside the
+command-line facility::
+
+  dav:/> edit index_html
+  Connecting to server... connected.
+  Locking `index_html': Authentication required for Zope on server `saints.homeunix.com':
+  Username: admin
+  Password:
+  Retrying: succeeded.
+  Downloading `/index_html' to /tmp/cadaver-edit-001320
+  Progress: [=============================>] 100.0% of 93 bytes succeeded.
+  Running editor: `vi /tmp/cadaver-edit-001320'...
+
+In this case, the `index_html` object was pulled up for editing inside of the
+`vi` text editor. You can specify your editor of choice on most UNIX-like
+systems by changing the EDITOR environment variable.
+
+You can also use cadaver to transfer files between your local directory and
+remote Zope, as described above for WS_FTP. For more advanced synchronization
+of data, the `sitecopy` program can inspect your local and remote data and only
+transfer the changes, using FTP or DAV.
+
+Editing Zope objects with KDE applications
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+KDE applications are WebDAV aware. Therefore, we can actually edit Zope objects
+from any of the KDE applications, such as konqueror, quanta, kate, et cetera.
+
+Using konqueror:
+
+- enter::
+
+    webdav://your.server:port/ in the konqueror location.
+
+- enter the username and password when prompted.
+
+- start editing when konqueror presents the Zope workspace.
+
+`Viewing the Zope object hierarchy with konquerorWebDAV <img:Figures/webdavkonq.png>`_
+
+
+Using Kate:
+
+- Open Kate
+
+- Click File > Open
+
+- Enter::
+
+    webdav://your.server:port/
+
+  in "Open File dialog" "Location"
+
+- Browse for your file or start editing.
+
+`Kate Open File dialog box WebDAV <img:Figures/webdavkate.png>`_
+
+
+Other Integration Facilities
+============================
+
+This chapter focused on FTP and DAV. These are the most popular and mature
+approaches for integration. However, other choices are available.
+
+For instance, Zope has long supported the use of HTTP PUT, originally
+implemented by Netscape as "Netscape Publishing". This allows Netscape
+Composer, Mozilla Composer, and Amaya to edit and create new pages, along with
+associated elements such as images and stylesheets.

Copied: zope2docs/branches/baijum-reorganize/zope2book/InstallingZope.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/InstallingZope.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/InstallingZope.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/InstallingZope.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,619 @@
+Installing and Starting Zope
+============================
+
+By the end of this chapter, you should be able to install and start
+Zope.  It is fairly easy to install Zope on most platforms, and it
+typically takes no longer than ten minutes to complete an installation.
+
+Downloading Zope
+----------------
+
+There are typically two types of Zope releases: a "stable" release
+and a "development" release.  If you are new to Zope, you almost
+certainly want to use the "stable" Zope release.
+
+You may download Zope from the `Zope.org <http://www.zope.org/>`_ web
+site, from which the most recent stable and development versions are always
+available in the `Download <http://www.zope.org/Products/>`_
+area.
+
+Zope comes as a "binary" release for the Windows platform, and in source
+format for UNIX-like operating systems. Zope may be compiled on almost any
+UNIX-like operating system.  Zope has reportedly been successfully compiled
+on Linux, FreeBSD, NetBSD, OpenBSD, Mac OS X, HPUX, IRIX, DEC OFS/1, and
+even Cygwin (the UNIX emulation platform for Windows).
+
+As a general rule of thumb: if `Python <http://www.python.org/>`_ is
+available for your operating system, and if you have a C compiler and
+associated development utilities, then it is highly likely that you will be
+able to compile Zope.  A notable exception is Mac OS between versions 7
+through 9, as Zope does not run at all on these platforms.
+
+Installing Zope
+---------------
+
+Zope's installation steps vary somewhat, depending on your operating system
+platform.  The sections below detail installing the binary version of Zope
+on Windows on Intel platforms, and a source installation on Linux.
+
+Installing Zope for Windows With Binaries from Zope.org
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The "Win32" version of Zope works under Windows 95, Windows 98, Windows ME,
+Windows NT, Windows 2000, Windows XP, and Windows Server 2003.  Zope for
+Windows comes as a self-installing *.exe* file.  To install Zope, first,
+download the Win32 executable installer from the
+`Download`_ area on Zope.org.  It is
+typically named something like "Zope-2.X.X-win32-x86.exe" where the "X"'s
+refer to the current Zope version number.
+
+.. figure:: Figures/download-zope.png
+
+   Current stable Zope release for Windows
+
+Download the current stable release installer for Windows from
+Zope.org using your web browser.  Place the file in a temporary
+directory on your hard disk or on your Desktop.  Once the
+installer file has been downloaded, navigate to the folder into
+which you downloaded the file, and double-click on the file's
+icon.  The installer then begins to walk you through the
+installation process.
+
+.. figure:: Figures/installer-package-icon.png
+
+   Zope installer
+
+.. figure:: Figures/installer-first-screen.png
+
+   Beginning the installer
+
+Click *Next*. The installer asks for an installation path. The default is
+usually acceptable, though you are, of course, free to choose another path.
+Then click *Next*. You then can choose which components to install.
+
+.. figure:: Figures/component-selection.png
+
+   Select components
+
+You should select "Full installation" unless you have previously installed
+Zope and know what you are doing. On the next screen, you may customize the
+entry placed in your *Start Menu* folder. Click *Next* again. The installer
+now asks you whether you would like to run Zope as a *service*, unless you
+are running Windows 98 or ME, on which such services are not available. If
+you are only running Zope for personal use, there is no need to run it as a
+service.
+
+.. figure:: Figures/start-as-service.png
+
+   Server options
+
+Upon clicking *Next*, the installer takes you to the "Instance Setup"
+Screen.
+
+.. figure:: Figures/instance-path.png
+
+   Instance setup
+
+You can have more than one Zope running on your PC, but each has to have
+its own *Instance Home*, which is the path to specify here.  This path is
+where Zope will later place its database files. Make sure that you have
+enough disk space left on the specified drive and that you can make backups
+easily.
+
+The *Next* screen asks you for a password for an initial administrative
+account. You use this account to log in for the first time and create more
+users. Note that the installer does not ask you to verify your password, so
+be careful not to mis-type it.
+
+.. figure:: Figures/instance-passwd.png
+
+   Administrative password
+
+Click *Next* after entering a password. The installer presents an overview,
+form which you can commence installation by clicking *Install*. After a few
+moments, the Zope installer will present you with a "Completion" screen.
+
+.. figure:: Figures/installer-complete.png
+
+   Installation completion
+
+Let the installer start Zope for you, or start Zope manually by navigating
+to the Zope folder in the Start Menu and selecting "Run Zope in Console".
+See the section below entitled `Starting Zope`_.
+
+Compiling and Installing Zope from Source Code
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If binaries aren't available for your platform, chances are good that you
+will be able to compile Zope from its source code.  To do this, however,
+you first must:
+
+- ensure that you have a "C" compiler on your system (*GNU gcc* is
+  preferred);
+
+- ensure that you have a recent "make" on your system (*GNU make* is
+  preferred);
+
+- install the `Python <http://www.python.org/>`_ language on your
+  system from source, or install a binary Python package, including
+  development headers.
+
+Zope is written primarily in the Python language, and Zope requires Python
+in order to be able to run at all.  While binary versions of Zope ship with
+a recent Python version, the source Zope distribution does not.  Zope
+developers try to use the most recent Python for Zope, but often the latest
+Python version is more recent than the officially-supported Zope version.
+Zope 2.12 requires Python 2.5.4 or later, and Zope versions 2.11 and 2.10
+require a Python 2.4.*x* version equal to or greater than 2.4.3.  For the
+most recent information on which version of Python is required for
+compiling Zope, see the release notes on the release Web page.
+
+You can obtain detailed instructions for downloading, compiling, and
+installing Python from source at the `Python.org <http://www.python.org/>`_
+website.  Most Linux distributions ship with a pre-installed Python 2.5,
+but care is required when attempting to use a vendor-installed Python to
+compile Zope: some of these vendor-supplied Python distributions do not
+ship the necessary Python development files needed to compile Zope from
+source.  Sometimes these development files are included in a separate
+"python-devel" package that may be installed separately, but sometimes they
+are not.  The binary packages that ship with Debian have been used with
+some level of success, but it is generally advisable to compile and install
+Python from source if you wish to also compile and install Zope from
+source.
+
+After downloading, compiling, and installing Python from source, download
+the current Zope source distribution.  See the Zope.org `Downloads
+<http://www.zope.org/Products>`_ area for the latest Zope source release.
+
+Download the source to your home, or some other directory, 'cd' to that
+directory, and unpack it with something similar to::
+
+  $ mkdir ~/myzope
+  $ cd ~/myzope
+  $ gunzip -c /tmp/Zope-*.tgz | tar xvf -
+
+where * represents the Zope release version of the source tarball.
+
+Zope now uses the conventional UNIX build sequence:
+``configure``, ``make``, ``make install``.
+
+To configure Zope, 'cd' to the Zope directory and issue the configure
+command::
+
+  $ cd Zope-*
+  $ ./configure --prefix=/where/to/install/zope
+
+Replace */where/to/install/zope* above with an appropriate path, such as
+``~/myzope/zope2``.  This path is referred to as the *ZOPE_HOME*.  If you
+want to install Zope in a system directory instead of your user home,
+replace ``~/myzope/zope2`` with an appropriate path, e.g.,
+``/usr/local/zope2``, and make sure that you have suitable privileges for
+installing and starting Zope ('sudo' or 'root').
+
+If the configure script is unable to find your Python installation, it will
+report an error not unlike this one::
+
+  $ ./configure --prefix=~/myzope/zope2
+
+  Configuring Zope installation
+  Testing for an acceptable Python interpreter...
+
+  No suitable Python version found. You should install
+  Python version 2.5.4 before continuing. Versions
+  2.6.1 2.6.0 also work, but not as optimally.
+
+In this case, you must point the installer to your Python interpreter,
+which you should have installed previously, either from a binary package or
+compiled from source.
+
+Use the ``--with-python`` option to the configure script, e.g,. for a python
+living under ``/usr/local`` ::
+
+  $ ./configure --prefix=~/myzope/zope2 \
+  --with-python=/usr/local/bin/python
+
+Replace ``/usr/local/bin/python`` with the path to your Python executable.
+
+Zope is now ready to be built. From within the source directory, issue::
+
+  $ make
+  [ lots of output snipped ]
+  Zope built. Next, do 'make install' (or 'make instance'
+  to run a Zope instance directly from the build directory).
+
+You are now ready to install Zope. To do this, you will have to execute
+'make install' ::
+
+  $ make install
+  [ lots of output snipped ]
+  Zope binaries installed successfully.
+  Now run '~/myzope/zope2/bin/mkzopeinstance.py'
+
+With the Zope binaries installed, you are now ready to create a *Zope
+instance*, which holds configuration and runtime data for a single Zope
+server process.  This helps keep your own or third-party software separate
+from the main Zope source.
+
+Assuming that you want to install a Zope instance in the directory
+``~/myzope/instance``, in order to create a Zope instance, you would run
+the following command::
+
+  $ ~/myzope/zope2/bin/mkzopeinstance.py
+
+You will need to provide the following values:
+
+- The directory where your instance should be located, or the *INSTANCE_HOME*.
+  The instance home will hold your database files, log files, configuration
+  files, and scripts to start and stop the instance. For our example, we assume
+  the instance home to be located at ``~/myzope/instance``.
+
+- Username and Password for an initial Zope user. You will log in with
+  this username and password to create your own Zope users.  To change the
+  username or password for your initial Zope user, run::
+
+  $ cd ~/myzope/instance
+  $ ~/myzope/zope2/bin/zpasswd.py inituser
+
+You will have to provide the username and password you wish to set;
+optionally, you can specify the hashing method and an additional domain
+restriction.
+
+Zope installation is now complete. Read on to see how to
+start your brand-new Zope.
+
+
+Starting Zope
+-------------
+
+Zope is managed via a web browser, and Zope contains its own web server
+(called ``ZServer``).  A successful Zope startup implies that Zope's web
+server starts, which allows you to access the Zope management interface
+(ZMI) via your web browser.  You can access the ZMI from the same machine
+on which Zope runs, or you can access it from a remote machine that is
+connected to the same network as your Zope server.
+
+Zope's ZServer will "listen" for HTTP requests on TCP port 8080.  If your
+Zope instance fails to start, make sure that another application isn't
+already running on the same TCP port (8080).
+
+Zope also has the capability to listen on other TCP ports.  Zope supports
+separate TCP ports for FTP (File Transfer Protocol), "monitor" (internal
+debugging), WebDAV (Web Distributed Authoring and Versioning), and ICP
+(Internet Cache Protocol) access.  If you see messages that indicate that
+Zope is listening on ports other than the default 8080 HTTP, don't panic:
+it's likely just one of these additional ports.
+
+Using Zope With an Existing Web Server
+--------------------------------------
+
+If you wish, you can configure your existing web server to serve Zope
+content.  Zope interfaces with Microsoft IIS, Apache, and other popular
+webservers.
+
+The `Virtual Hosting Services <VirtualHosting.html>` chapter of this book
+provides rudimentary setup information for configuring Zope behind Apache.
+However, configuring Zope for use behind an existing web server can be a
+complicated task, and there is more than one way to get it done.  Here are
+some additional resources that should get you started:
+
+- IIS: see `brianh's HowTo
+  <http://www.zope.org/Members/brianh/iis_howto>`_ on using IIS with Zope.
+  Also of interest may be the ``WEBSERVER.txt`` file in your Zope
+  installation's ``doc`` directory, and hiperlogica's `Connecting IIS to
+  Zope <http://www.zope.org/Members/hiperlogica/ASP404>`_ article.
+
+If you are just getting started with Zope, note that it is not necessary to
+configure Apache, IIS, or any other web server to serve your Zope pages, as
+Zope comes with its own web server.  You typically only need to configure
+your existing web server if you want to use it to serve Zope pages in a
+production environment.
+
+Starting Zope on Windows
+------------------------
+
+If you've installed Zope to "run manually" (as opposed to installing Zope
+as a "service"), navigate to the Zope folder in your Start Menu and click
+on *Run Zope in Console*. A console window with process startup information
+will be displayed.
+
+If you chose to run Zope as a "service" on Windows NT/2000/XP, you can
+start Zope via the standard Windows "Services" control panel application.
+A Zope instance started as a service writes events to the standard Windows
+Event Log; you can keep track of the Zope service's start and stop events
+by reviewing the Event Log.  A Zope instance which has been installed as a
+"service" can also be run manually by invoking the *Run Zope in Console*
+menu entry as described earlier. Take care not to run Zope manually *and*
+as a service at one time: make sure to stop the Zope service first before
+starting it manually.
+
+Starting Zope on UNIX
+---------------------
+
+.. Important:
+   If you installed Zope from an RPM or a another "vendor distribution"
+   instead of installing a Zope Foundation-distributed source release,
+   the instructions below may be not be applicable.  Under these
+   circumstances, please read the documentation supplied by the vendor to
+   determine how to start your Zope instance instead of relying on these
+   instructions.
+
+To start your Zope instance (which we assume lives in ``~/myzope/instance``),
+issue the command::
+
+  $ ~/myzope/instance/bin/zopectl start
+
+This will start the instance in the background. Alternatively, you can
+start it in the foreground and watch its progress by issuing the command::
+
+  $ ~/myzope/instance/bin/zopectl fg
+
+Run the ``zopectl`` script with a parameter of ``help`` to get a
+list of additional commands::
+
+  $ ~/myzope/instance/bin/zopectl help
+
+
+Starting Zope as the Root User
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``ZServer`` (Zope's server) supports ``setuid()`` on POSIX systems in order
+to be able to listen on low-numbered ports, such as 21 (FTP) and 80 (HTTP),
+but drop root privileges when running; on most POSIX systems, only the
+``root`` user can do this.
+
+The most important thing to remember about this support is that you don't
+*have* to start ZServer as root, unless you want to listen for requests on
+"low" ports.  In fact, if you don't have this need, you are much better off
+just starting ZServer as a user account dedicated to running Zope.
+'nobody' is not a good idea for this user account, because if any other
+daemon on a system that ran as ``nobody`` were to be compromised, this would
+open up your Zope object data to vulnerability.
+
+If you do need to have ZServer listening on low ports, you will need to
+start ``zopectl`` as the ``root`` user, and to specify what user ZServer
+should ``setuid()`` to.  This can be done by setting the *effective-user*
+parameter in your Zope instances configuration file, residing in
+``$INSTANCE_HOME/etc/zope.conf``, and by making sure that the log and
+database files are writeable by this user.
+
+
+Your Zope Installation
+----------------------
+
+To use and manage Zope, you will need a web browser. Start a web browser on the
+same machine on which you installed Zope, and browse to the URL
+`http://localhost:8080/ <http://localhost:8080/>`_.
+
+If your Zope instance has been properly installed, and you're visiting the
+correct URL, you will be presented with the Zope "QuickStart" screen.
+
+.. figure:: Figures/quickstart.png
+
+   Zope QuickStart
+
+If you see this screen, congratulations!  You've installed Zope
+successfully.  If you don't, see the `Troubleshooting and Caveats`_ section
+below.
+
+Logging In
+----------
+
+For some of the tasks you want to do with Zope, you need to use its management
+interface: the *ZMI*. To log into the ZMI, use your web browser to navigate to
+Zope's management URL. Assuming you have Zope installed on the same machine
+from which you are running your web browser, the Zope management URL will be
+`http://localhost:8080/manage <http://localhost:8080/manage>`_.
+
+Successful contact with Zope via this URL will result in an authentication
+dialog, into which you can enter the "initial" username and password you
+chose when you installed Zope.  You will then be presented with the ZMI.
+
+.. figure:: Figures/zmi.png
+
+   The Zope Management Interface (ZMI)
+
+If you do not see an authentication dialog and the ZMI, refer to the
+`Troubleshooting and Caveats`_ section of this chapter.
+
+Controlling the Zope Process with the Control Panel
+---------------------------------------------------
+
+When you are using the ZMI, you can use the Zope *Control Panel* to control
+the Zope process.  Find and click the **Control_Panel** object in ZMI.
+
+.. figure:: Figures/controlpanel.jpg
+
+   The Control Panel
+
+The Control Panel displays information about your Zope, such as the Zope
+version you are running, the Python version that Zope is using, the system
+platform, the INSTANCE_HOME, the CLIENT_HOME, Zope's process id, the network
+services that have been started, how long Zope has been running for, and
+other installation specifics.  Several buttons and links will also be
+shown.
+
+If you are running Zope on UNIX or as a service on Windows, you will see a
+*Restart* button in the Control Panel.  Clicking *Restart* will cause Zope
+to shut down and then immediately start back up again.  It may take Zope a
+few seconds to come back up and start handling requests.  You don't need to
+shut your web browser down and restart it to resume using Zope after
+pressing *Restart*, as the page refreshes automatically; just wait for the
+Control Panel display to reappear.
+
+To shut Zope down from the ZMI, click *Shutdown*.  Shutting Zope down will
+cause the server to stop handling requests and exit. You will have to
+manually start Zope to resume using it. Shut Zope down only if you are
+finished using it and you have the ability to access the server on which
+Zope is running, so that you can manually restart it later as needed.
+
+
+Controlling the Zope Process from the Command Line
+--------------------------------------------------
+
+- If you started Zope in the foreground, press "Ctrl+C" in the terminal
+  window from which you started Zope.
+
+* If you started Zope in the background, use the ``zopectl`` script::
+
+  $ ~/myzope/instance/bin/zopectl stop
+
+* On Unix use the "kill" command against the process id in the
+  "var/Z2.pid" file inside the Zope instance directory::
+
+  $ kill `cat var/Z2.pid`
+
+
+Customizing your Zope instance
+------------------------------
+
+Zope's configuration is done via the file '$INSTANCE_HOME/etc/zope.conf'.
+This contains numerous configuration directives for customization.
+
+The ``zope.conf`` file features extensive inline documentation, which we
+will not reproduce here.  Instead, we will give an overview and some
+additional hints for the most-widely used directives:
+
+Server stanzas and ``port-base``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``port-base`` directive, together with stanzas for the individual
+servers, determine the ports on which specific servers listen for incoming
+Zope requests. The stanzas are formed with XML-like constructs::
+
+ <http-server>
+   # valid keys are "address" and "force-connection-close"
+   address 8080
+ </http-server>
+ <ftp-server>
+   ...
+ </ftp-server>
+ <webdav-source-server>
+   ...
+ </webdav-source-server>
+
+The ``address`` directive determines the port on which the respective server
+listens.  The HTTP Server in this example listens on port 8080.
+
+The ``port-base`` directive comes in handy if you want to run several Zope
+instances on one machine.  ``port-base`` specifies an offset to the port on
+which **all** servers listen.  Let us assume that our HTTP Server's
+'address' directive is set to 8080, as in our example above, and
+'port-base' is specified as 1000. The port on which the HTTP server will
+listen, will be the ``address`` value of 8080, plus the ``port-base`` offset
+value of 1000, or 9080.  Assuming the FTP server's ``address`` directive is
+set to 8021, the FTP Server will then listen on port 9021, and so on.
+
+The ``debug-mode`` directive
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This directive is a switch, specified as either ``on`` or ``off``.  When
+set to ``on`` (the default), Zope runs in *debug mode*, which causes Zope
+to reload file system-based templates, and several other settings suitable
+for development, in real time.  In a production environment, to reduce
+unnecessary overhead, you should ensure that this directive is set to
+``off`` unless you are actively troubleshooting a problem.
+
+Switch the User the Zope process runs as: ``effective-user``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This directive causes Zope to ``setuid(2)`` to the specified user when run
+as root on a UNIX system.  This method boosts system security, as a
+compromised Zope instance would not enable a compromised user to damage
+easily an entire system.  One motivation for running Zope as root in the
+first place is to be able to bind to *privileged* ports, or ports with
+values below 1024.
+
+Logging
+~~~~~~~
+
+Three log facilities are provided:
+
+- *Access logging* logs individual HTTP Requests in a common format,
+  by default to the file ``log/Z2.log`` in your instance home.
+
+- *Event logging* logs Zope events, such as start and stop
+  information and debugging messages.
+
+- *Trace logging* logs detailed Zope debugging information.
+
+Each log message has an associated severity level, ranging from
+``CRITICAL``, ``ERROR``, ``WARN``, and ``INFO``, to ``DEBUG`` and ``ALL``.
+You can specify a filter for log messages with the ``level`` directive
+inside a logger stanza.  Set the level to ``ALL`` to get all log messages,
+or to ``ERROR`` or ``CRITICAL`` to see only the most serious messages.
+
+Although the default is to write the messages to a log file, you can
+instead arrange for log messages to be mailed to you, or to go to
+``syslog(3)`` (on UNIX) or the event log (on MS Windows)
+
+For further documentation, see the inline comments in ``zope.conf``.
+
+
+Troubleshooting and Caveats
+---------------------------
+
+Browser cannot connect to port 8080
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If your browser fails to connect with anything on TCP port 8080, your Zope
+instance may be running on a non-standard TCP port (for example, some
+versions of Debian Linux ship with Zope's default TCP port as 9673).  To
+find out exactly which URL to use, look at the logging information Zope
+prints as it starts up when started in the foreground, i.e., when started
+with ``./runzope`` or ``./zopectl fg``. For example::
+
+ ...
+ ------
+ 2009-01-21T21:48:27 INFO(0) ZServer HTTP server started at Wed Jan 21 21:48:27 2009
+ Hostname: arod
+ Port: 9673
+ ------
+ 2009-01-21T21:48:27 INFO(0) ZServer FTP server started at Wed Jan 21 21:48:27 2009
+ Hostname: arod
+ Port: 8021
+ ...
+
+The first log entry indicates that Zope's web server is listening on port
+9673 on host ``arod``. This means that the management URL is
+http://arod:9673/manage.
+
+As mentioned previously, Zope only prints to the console when started in
+the foreground, with ``./runzope`` or ``runzope.bat``. This logging
+information can be found in the ``log/event.log`` file in your
+``INSTANCE_HOME`` directory.
+
+Forgot administrative password
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you forget or lose your initial Zope user name and password, shut Zope
+down, change the initial user password with the *zpasswd.py* script, and
+restart Zope. See the chapter entitled `Users and Security
+<Security.html>`_ for more information about configuring the initial user
+account.
+
+When All Else Fails
+~~~~~~~~~~~~~~~~~~~
+
+If there's a problem with your installation that you just cannot solve, do
+not despair.  You have many places to turn for help, including the Zope
+mailing lists and the ``#zope`` IRC channel.
+
+If you are new to open-source software, please realize that, for the most
+part, participants in the various "free" Zope support forums are
+volunteers.  Though they are typically friendly and helpful, they are not
+obligated to answer your questions.  Therefore, it's in your own
+self-interest to exercise your best manners in these forums in order to get
+your problem resolved quickly.
+
+The most reliable way to get installation help is to send a message to the
+general Zope mailing list detailing your installation problem.  For more
+information on the available Zope mailing lists, see the
+`Resources <http://www.zope.org/Resources>`_ section of Zope.org.  Typically,
+someone on the "zope at zope.org" list will be willing and able to help you
+solve the problem.
+
+For even more immediate help, you may choose to visit the 
+`#zope <irc://irc.freenode.net/#zope>`_ channel on
+the  IRC (Internet Relay Chat) network.  See the `Freenode
+website <http://freenode.net>`_ for more information on how to connect
+to the FreeNode IRC network.

Copied: zope2docs/branches/baijum-reorganize/zope2book/IntroducingZope.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/IntroducingZope.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/IntroducingZope.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/IntroducingZope.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,463 @@
+Introducing Zope
+================
+
+Zope is family of related Python packages focussed on web technologies. The
+first version of Zope has originated from a company called
+`Zope Corporation <http://www.zope.com/>`_.
+
+Today the `Zope Foundation <http://foundation.zope.org/>`_ holds the copyright
+of the Zope source code and supervises a diverse community of open-source
+contributers working on a variety of related projects.
+
+This book is about the original Zope project, today known as Zope2. When we
+refer to Zope in this book without a narrower specification we speak of Zope2.
+
+Other projects include the `Zope3 <http://wiki.zope.org/zope3/Zope3Wiki/>`_ web
+application framework, many individual packages located in the
+`Zope Subversion Repository <http://svn.zope.org/>`_ and projects being based
+or related to these packages like `Grok <http://grok.zope.org/>`_ and
+`Repoze <http://repoze.org/>`_. One of the more widely known applications
+based on top of Zope2 is a content management system called
+`Plone <http://plone.org/>`_.
+
+Zope2 itself is a web framework that allows developers of varying skill
+levels to build *web applications*. This chapter explains Zope's purpose,
+what problems it solves and what audience it targets in greater detail.
+It also describes what makes Zope different and more powerful than
+similar applications.
+
+*NOTE*: The moniker "Zope" stands for the *Z Object Publishing
+Environment* (the "Z" doesn't really mean anything in particular).
+
+The Static Web Site Dilemma
+---------------------------
+
+When a company or organization goes through the process of developing and
+eventually deploying a website, one of its most important goals is to
+present timely and up-to-date information to its website visitors.
+
+Let us consider two examples of such time-dependent sites:
+
+- a stock market information site that needs to be updated with
+  new information continually, maybe as often as every five or 10
+  minutes. It will also present information tailored to each
+  visitor's preferred settings (portfolios, stocks to follow, etc.)
+
+- a commercial website that helps its visitors sell and buy used
+  automobiles. It is usually required that such a site run
+  advertisements only for cars that have not yet been sold.  It is
+  also important that new ads be posted immediately after
+  they've been placed by a seller.
+
+These two examples describe two very different sites that
+nevertheless have one basic requirement in common: automated and
+periodic updates of the information presented. If this single
+requirement is not met, these sites will likely be
+unsuccessful.
+
+So, how does Zope work to fulfill such a requirement? To understand
+this, we need to consider how websites are perceived by their
+visitors and the basic ways in which websites can be constructed.
+
+In general, many website visitors think about navigation in terms
+of moving "from page-to-page" within a website.  When they click
+a hyperlink, their browser transports them to a new page.  When they
+hit their browser's *back* button, they are returned to the last page
+they visited, and so on.
+
+Some websites are *static*. A static website stores its
+information in files on a web server. Each file then represents a
+complete page on the website. This may seem like a simple and
+efficient way of creating a website; however, *updating the
+information* within those pages becomes a problem when the site consists of
+more than a few pages, and the pages, or parts of the pages, need to be updated 
+frequently.
+
+The layout of text and images that are displayed in a user's web browser
+when the user visits a website are commonly composed in a simple
+language known as Hyper Text Markup Language (HTML). When a user
+visits a typical website, a chunk of text that is "marked-up"
+with formatting in HTML is transferred between the website and the user's
+browser. The browser interprets the chunk of text and displays text
+and images to the user.  The chunk of text which is transferred is
+typically referred to as a *page*.
+
+To achieve this, the static website requires a person with a
+privileged level of access (sometimes termed the *webmaster*) to
+manually create and update the site's content.
+
+Typically, this is done by editing a set of text-based files on the *web
+server* (the machine that runs the website), where each file
+represents a single page. In some cases, a site-wide change to the "look-and-feel"
+of a static website requires that the webmaster visit and update
+each and every file that comprises the website.
+
+The webmaster responsible for our automobile advertising website
+has the additional responsibility of keeping the ads themselves
+fresh.  If each page in the website represents an ad for a
+particular automobile, he needs to delete the pages representing
+ads that have expired and create new pages for ads that have been
+recently sold.  He then needs to make sure that no hyperlinks on
+other pages point to any of these deleted pages.
+
+Obviously, this quickly becomes a lot of work.  With any more than a 
+few pages to update each day, this type of repetitive work 
+can become pretty dull.  In addition, being a human being, the webmaster 
+may also make mistakes, such as forgetting to update or remove
+critical pages.  While updating a static website with only 10 to 20
+pages might be dull, it's perfectly manageable.  However, websites
+can typically grow to encompass thousands of files, making the
+process of "timely updates" a non-trivial (and sometimes
+impossible) task.
+
+Somewhere down the line, smart webmasters begin to think to
+themselves, "Wow, this is a lot of work.  It's tedious and
+complicated, and I seem to be making a lot of mistakes.  Computers
+are really good at doing tedious and complicated tasks, and they
+don't make very many mistakes.  I bet my web server computer could
+automatically do a lot of the work I now do manually."  And he would 
+be right.
+
+At this point, the webmaster is ready to be introduced to *web
+applications*. It is in this area where Zope's strength and power
+becomes clear.
+
+
+What Is A Web Application?
+--------------------------
+
+A *web application* is a computer program that users invoke by
+using a web browser to contact a web server via the Internet. Users
+and browsers are typically unaware of the difference between
+a web server that fronts a statically-built website
+and one that fronts a web application.  But unlike a
+static website, a web application creates its "pages"
+*dynamically*, or on-the-fly, upon request.  A website that is dynamically-
+constructed uses an a computer program to provide its content.
+These kinds of dynamic applications can be written in any number of
+computer languages.
+
+Web applications are everywhere.  Common examples of web
+applications are those that let you search the web, like *Google*;
+collaborate on projects, like *SourceForge*; buy
+items at an auction, like *eBay*; communicate with other people over
+e-mail, like *Gmail*; or view the latest news ala *CNN.com*.
+
+In a dynamically-constructed website, the webmaster is not
+required to visit the site "page-by-page" in order to update its
+content or style.  Instead, he is able to instruct the web server
+to *generate the site's HTML pages dynamically*, where each page is
+made up of different bits of content. While each bit of content is
+unique, each can nevertheless appear in several pages if so 
+instructed by the web server. In this way, the webmaster is able to create
+a common "look and feel" for the set of pages that make up his
+site. The software on the web server that generates these
+pages is the web application.
+
+If our auto-classifieds webmaster chose to construct a web
+application to maintain his classifieds system, he could maintain a
+list of "current" ads separate from the HTML pages, perhaps stored
+in a database of some kind.  He could then instruct his web
+application to query this database and generate a particular chunk
+of HTML that represented an ad, or an index of ads, when a user
+visited a page in his website.
+
+A framework that allows people to construct a web application is often called a
+*web application server*, or sometimes just an *application server*. Zope is a
+web application server, as are competing products like `WebSphere
+<http://www.ibm.com/websphere/>`_, `JBoss <http://www.jboss.org/jbossas/>`_,
+and (to some extent) `SAP NetWeaver <http://www.sap.com/>`_.
+
+Zope is a web application server, which is not
+a web application in itself; rather it is *framework that allows
+people to construct web applications*. Sometimes this framework is
+called an *application server*.
+
+Using some common computer programming language, an application
+server typically allows a developer to create a web application,
+but it also provides services *beyond* the basic capabilities of
+the programming language used. Examples of such services are web
+page template creation facilities, a common security model, data
+persistence, sessions, and other features that people find useful
+when constructing a typical web application.
+
+
+How You Can Benefit From Using An Application Server
+----------------------------------------------------
+
+If you are considering writing even a moderately-sized web
+application, it is typically a good idea to start your project
+using an application server framework, unless your application
+requirements are extremely specialized.  By starting a web
+application project with an application server framework (as
+opposed to a "raw" computer language, such as Java, Perl, Python, or
+C), you are able to utilize the services of the framework that have
+already been written and proven to work, and you avoid the need to
+write the functionality yourself "from scratch" in a "raw"
+language.
+
+Many application servers allow you to perform some of the following tasks:
+
+Present Dynamic Content -- You may tailor your web site's
+presentation to its users and provide users with search features.
+Application servers allow you to serve dynamic content and typically
+come with facilities for personalization, database integration,
+content indexing, and searching.
+
+Manage Your Web Site -- A small web site is easy to manage, but a
+web site that serves thousands of documents, images, and files
+requires heavy-duty management tools. It is useful to be able to
+manage your site's data, business logic, and presentation from a
+single place.  An application server can typically help manage
+your content and presentation in this way.
+
+Build a Content Management System -- A *content management system* allows
+non-technical editors to create and manage content for your website.
+Application servers provide the tools with which you can build a
+content management system.
+
+Build an E-Commerce Application -- Application servers provide a
+framework in which sophisticated e-commerce applications can be
+created.
+
+Securely Manage Contributor Responsibility -- When you deal with
+more than a handful of web users, security becomes very important.
+You must be able to safely delegate tasks to different
+classes of system users. For example, folks in your engineering
+department may need to be able to manage their web pages and
+business logic, designers may need to update site templates, and
+database administrators need to manage database queries.
+Application servers typically provide a mechanism for access
+control and delegation.
+
+Provide Network Services -- You may want to produce or consume
+*network services*.  A network service-enabled web site must
+to be able to accept requests from other computer programs.  For
+example, if you're building a news site, you may wish to share
+your news stories with another site; you can do this by making
+the news feed a network service.  Or perhaps you want to make
+products for sale on your site automatically searchable from a
+product comparison site.  Application servers 
+offer methods for enabling these kinds of network services.
+
+Integrate Diverse Systems -- Your existing content may be
+contained in many places: relational databases, files, separate
+web sites, and so on.  Application servers typically allow you
+to present a unified view of your existing data by integrating
+diverse, third-party systems.
+
+Provide Scalability -- Application servers allow your web
+applications to scale across as many systems as necessary to
+handle the load demands of your sites.
+
+The Zope application server allows you to perform all of these
+tasks.
+
+
+Why Use Zope Instead of Another Application Server
+--------------------------------------------------
+
+If you're in the business of creating web applications, Zope can
+potentially help you create them at less cost and at a faster rate
+than you could by using another competing web application server.
+This claim is backed by a number of Zope features:
+
+- Zope is free of cost and distributed under an open-source
+  license.  There are many non-free commercial application servers
+  that are relatively expensive.
+
+- Zope itself is an inclusive platform.  It ships with all the
+  necessary components to begin developing an application.  You
+  don't need to license extra software to support Zope (e.g., a
+  relational database) in order to develop your application.  This
+  also makes Zope very easy to install.  Many other application
+  servers have "hidden" costs by requiring that you license
+  expensive software or configure complex, third-party
+  infrastructure software before you can begin to develop your
+  application.
+
+- Zope allows and encourages third-party developers to package and
+  distribute ready-made applications.  Due to this, Zope has a
+  wide variety of integrated services and add-on packages
+  available for immediate use.  Most of these components, like
+  Zope itself, are free and open-source.  Zope's popularity has
+  bred a large community of application developers.
+
+- Applications created in Zope can scale almost linearly using
+  Zope's built-in "Zope Enterprise Objects" (ZEO) clustering
+  solution.  Using ZEO, you can deploy a Zope application across
+  many physical computers without needing to change much (if any)
+  of your application code.  Many application servers don't scale
+  quite as transparently or as predictably.
+
+- Zope provides a granular and extensible security framework.  You
+  can easily integrate Zope with diverse authentication and
+  authorization systems, such as LDAP, Kerberos, and RADIUS,
+  simultaneously and using pre-built modules.  Many other application
+  servers lack support for important authentication and
+  authorization systems.
+
+- Zope runs on most popular microcomputer operating system
+  platforms: Linux, Windows, Solaris, FreeBSD, NetBSD,
+  OpenBSD, and Mac OS X.  Many
+  other application server platforms require that you run an
+  operating system of their licensor's choosing.
+
+- Zope can be extended using the interpreted `Python <http://www.python.org/>`_
+  scripting language. Python is popular and easy to learn, and it promotes
+  rapid development. Many libraries are available for Python that can be used
+  when creating your own application. Many other application servers must be
+  extended using compiled languages, such as Java, which cuts down on
+  development speed. Many other application servers use less popular languages
+  for which there are not as many ready-to-use library features.
+
+
+Zope Audiences and What Zope Isn't
+----------------------------------
+
+Managing the development process of a large-scale site can be a
+difficult task. It often takes many people working together to
+create, deploy, and manage a web application.
+
+*Information Architects*
+  make platform decisions and keep track of the "big picture".
+
+*Component Developers*
+  create software intended for reuse and distribution.
+
+*Integrators*
+  integrate the software written by component developers and native
+  application server services, building an application in the process.
+
+*Web Designers*
+  create the site's look and feel.
+
+*Content Managers*
+  create and manage the site's content.
+
+*Administrators*
+  keep the software and environment running.
+
+*Consumers*
+  use the site to locate and work with useful content.
+
+Of the parties listed above, Zope is most useful for *component
+developers*, *integrators*, and *web designers*.  These three
+groups can collaborate to produce an application using
+Zope's native services and third-party Zope *Plugins*.  They 
+typically produce applications useful to *content managers* and
+*consumers* under the guide of the *information architect*.
+*Administrators* deploy the application and tend to the
+application after it is has been created.
+
+Note that Zope is a web application construction framework that
+programmers of varying skill levels may use to create web-based
+applications.  It *is not* itself an application that is ready to
+use "out of the box" for any given application.  For example, Zope
+itself is not a blog, a content management system, or a
+"e-shop-in-a-box" application.
+
+However, freely available *Plugins* built on top of Zope offer these kinds of
+services. At the time of this writing, the `Python Package Index
+<http://pypi.python.org/pypi/>`_ lists roughly 400 `Plugins that you can browse
+<http://pypi.python.org/pypi?:action=browse&c=514>`_ and even reuse in your own
+applications. These include Plugins for blogging, content management,
+internationalization, and e-commerce.
+
+Zope is not a visual design tool.  Tools like Macromedia
+Dreamweaver and Adobe GoLive allow designers to create "look and
+feel".  You may use these tools to successfully manage Zope-based
+web sites, but Zope itself does not replace them.  You can edit
+content "through the web" using Zope, but it does not try to replace the
+features offered by these kind of tools.
+
+
+Introduction to Zope Maintenance and The Zope Community
+-------------------------------------------------------
+
+A community of developers is responsible for maintaining and
+extending the Zope application server.  Many community members are
+professional consultants, developers, and webmasters who develop
+applications using Zope for their own gain.  Others are students
+and curious amateur site developers.  Zope Corporation is a member
+of this community.
+
+The Zope Foundation controls the distribution of the defacto,
+"canonical", official Zope version, and permits its developers, as
+well as other selected developers, to modify the distribution's
+source code.
+
+The Zope community gets together occasionally at conferences, but it
+commonly discusses all things Zope on the many Zope mailing
+lists and web sites. You can find out more about Zope-related
+mailing lists at `Zope.org's mailing list page <http://mail.zope.org/mailman/listinfo>`_.
+
+Zope Corporation makes its revenue by using Zope to create web
+applications for its paying customers, by training prospective
+Zope developers, by selling support contracts to companies who use
+Zope, and by hosting Zope-powered websites; it does not make any
+direct revenues from the distribution of the Zope application
+server itself.
+
+
+Zope's Terms of Use and License
+-------------------------------
+
+Zope is free of cost. You are permitted to use Zope to create and run your web
+applications without paying licensing or usage fees. You may also include Zope
+in your own products and applications without paying royalty fees to Zope's
+licensor, *Zope Foundation*.
+
+Zope is distributed under an open source license, the `Zope Public License or
+'ZPL' <http://www.zope.org/Resources/License>`_. The terms of the ZPL license
+stipulate that you will be able to obtain and modify the source code for Zope.
+
+The ZPL is different than another popular open source license, the `GNU Public
+License <http://www.gnu.org>`_. The licensing terms of the GPL require that if
+you intend to redistribute a GPL-licensed application, and you modify or extend
+the application in a meaningful way, when you `redistribute
+<http://www.gnu.org/licenses/gpl-faq.html#GPLRequireSourcePostedPublic>`_ a
+GPL-licensed application, you must distribute it under the terms of the GPL,
+including licensing any modifications or extensions you make under the GPL. You
+must also provide the full source code, including source for your
+modifications.
+
+However, this is *not* required for ZPL-licensed applications. You may modify
+and redistribute Zope without contributing your modifications back to Zope
+Corporation, as long as you follow the other terms of the license faithfully.
+
+Note that the ZPL has been `certified`_ as `OSD`_ compliant by the
+`Open Source Initiative`_ and is listed as `GPL compliant`_ by the
+`Free Software Foundation`_.
+
+.. _certified: http://www.opensource.org/licenses/zpl.php
+.. _OSD: http://www.opensource.org/docs/definition.html
+.. _Open Source Initiative: http://www.opensource.org/
+.. _GPL compliant: http://www.gnu.org/philosophy/license-list.html#GPLCompatibleLicenses
+.. _Free Software Foundation: http://www.fsf.org/
+
+
+Zope History
+------------
+
+In 1996, Jim Fulton (the current CTO of Zope Corporation, the orginators of
+Zope) was drafted to teach a class on CGI programming, despite not knowing very
+much about the subject. CGI, or *common gateway interface*, programming is a
+commonly-used web development model that allows developers to construct dynamic
+websites. Jim studied all of the existing documentation on CGI on his way to
+the class. On the way back from the class, Jim considered what he didn't like
+about traditional, CGI-based programming environments. From these initial
+musings, the core of Zope was written on the plane flight back from the class.
+
+Zope Corporation (then known as Digital Creations) went on to release three
+open-source software packages to support web publishing: *Bobo*, *Document
+Template*, and *BoboPOS*. These packages were written in a language called
+Python, and respectively provided a web publishing facility, text templating,
+and an object database. Digital Creations developed a commercial application
+server based on their three open-source components. This product was called
+*Principia*. In November of 1998, investor Hadar Pedhazur convinced Digital
+Creations to open source Principia. These packages have evolved into what today
+are the core components of Zope.
+
+Most of Zope is written in the `Python <http://www.python.org/>`_ scripting
+language, with performance-critical pieces written in C.

Copied: zope2docs/branches/baijum-reorganize/zope2book/MaintainingZope.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/MaintainingZope.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/MaintainingZope.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/MaintainingZope.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,716 @@
+Maintaining Zope
+################
+
+Keeping a Zope site running smoothly involves a number of administrative tasks.
+This chapter covers some of these tasks, such as:
+
+  - Starting Zope automatically at boot time
+  - Installing new products
+  - Setting parameters in the Control Panel
+  - Monitoring
+  - Cleaning up log files
+  - Packing and backing up the database
+  - Database recovery tools
+
+Maintenance often is a very platform-specific task, and Zope runs on many
+platforms, so you will find instructions for several different operating
+systems here. It is not possible to provide specifics for every system;
+instead, we will supply general instructions which should be modified according
+to your specific needs and platform.
+
+Starting Zope Automatically at Boot Time
+========================================
+
+For testing and developing purposes you will start Zope manually most of the
+time, but for production systems it is necessary to start Zope automatically at
+boot time. Also, we will want to shut down Zope in an orderly fashion when the
+system goes down. We will describe the necessary steps for Microsoft Windows
+and some Linux distributions. Take a look at the Linux section for other
+Unix-like operating systems. Much of the information presented here also
+applies to System V like Unices.
+
+Debug Mode and Automatic Startup
+++++++++++++++++++++++++++++++++
+
+If you are planning to run Zope on a Unix production system you should also
+disable *debug mode*. This means removing the `-D` option in startup scripts
+(e.g. the `start` script created by Zope at installation time which calls z2.py
+with the `-D` switch) and if you've manually set it, unsetting the
+`Z_DEBUG_MODE` environment variable. In debug mode, Zope does not detach itself
+from the terminal, which could cause startup scripts to malfunction.
+
+On Windows, running Zope as a service disables debug mode by default. You still
+can run Zope in debug mode by setting the `Z_DEBUG_MODE` environment variable
+or running Zope manually from a startup script with the `-D` option. Again,
+this is not recommended for production systems, since debug mode causes
+performance loss.
+
+Automatic Startup for Custom-Built Zopes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Even if you do not want to use the prepackaged Zope that comes with your
+distribution it should be possible to re-use those startup scripts, eg. by
+installing the prepackaged Zope and editing the appropriate files and symlinks
+in `/etc/rc.d` or by extracting them with a tool like `rpm2cpio`.
+
+In the following examples we assume you installed your custom Zope to a
+system-wide directory, eg. `/usr/local/zope`. If this is not the case please
+replace every occurence of `/usr/local/zope` below with your Zope installation
+directory. There should also be a separate Zope system user present. Below we
+assume that there is a user `zope`, group `nogroup` present on your system. The
+user `zope` should of course have read access to the `$ZOPE_HOME` directory
+(the directory which contains the "top-level" Zope software and the "z2.py"
+script) and its descendants, and write access to the contents of the `var`
+directory.
+
+If you start Zope as root, which is usually the case when starting Zope
+automatically on system boot, it is required that the `var` directory belongs
+to root. Set the ownership by executing the command::
+
+  chown root var
+
+as root.
+
+To set up a Zope binary package with built-in python situated in::
+/usr/local/zope running as user `zope` , with a "WebDAV Source port" set to
+8081, you would set::
+
+  ZOPE_HOME=/usr/local/zope
+  PYTHON_BIN=$ZOPE_HOME/bin/python
+  COMMON_PARAMS="-u zope -z $ZOPE_HOME -Z /var/run/zope.pid -l /var/log/Z2.log -W 8081"
+
+You can also set up a file `/etc/sysconfig/zope` with variables ZOPE_FTP_PORT,
+ZOPE_HTTP_PORT::
+
+  ZOPE_HTTP_PORT=80
+  ZOPE_FTP_PORT=21
+
+to set the HTTP and FTP ports. The default is to start them at port 8080 and
+8021.
+
+Unfortunately, all Linux distributions start and stop services a little
+differently, so it is not possible to write a startup script that integrates
+well with every distribution. We will try to outline a crude version of a
+generic startup script which you can refine according to your needs.
+
+To do this some shell scripting knowledge and root system access is required.
+
+Linux startup scripts usually reside in::
+
+  /etc/init.d
+
+or in::
+
+  /etc/rc.d/init.d
+
+For our examples we assume the startup scripts to be in::
+
+  /etc/rc.d/init.d
+
+adjust if necessary.
+
+To let the boot process call a startup script, you also have to place a
+symbolic link to the startup script in the::
+
+  /etc/rc.d/rc?.d
+
+directories, where `?` is a number from 0-6 which stands for the SystemV run
+levels. You usually will want to start Zope in run levels 3 and 5 (3 is full
+multi-user mode, 5 is multiuser mode with X started, according to the "Linux
+Standard Base":http://www.linuxbase.org), so you would place two links in the
+/etc/rc.d' directories. Be warned that some systems (such as Debian) assume
+that runlevel 2 is full multiuser mode. As stated above, we assume the main
+startup script to located in::
+
+  /etc/rc.d/init.d/zope
+
+if your system puts the::
+
+  init.d
+
+directory somewhere else, you should accomodate the paths below::
+
+  # cd /etc/rc.d/rc3.d
+  # ln -s /etc/rc.d/init.d/zope S99zope
+  # cd /etc/rc.d/rc5.d
+  # ln -s /etc/rc.d/init.d/zope S99zope
+
+The scripts are called by the boot process with an argument::
+
+  start
+
+when starting up and::
+
+  stop
+
+on shutdown.
+
+A simple generic startup script structure could be something like this::
+
+  #!/bin/sh
+
+  # set paths and startup options
+  ZOPE_HOME=/usr/local/zope
+  PYTHON_BIN=$ZOPE_HOME/bin/python
+  ZOPE_OPTS=" -u zope -P 8000"
+  EVENT_LOG_FILE=$ZOPE_HOME/var/event.log
+  EVENT_LOG_SEVERITY=-300
+  # define more environment variables ...
+
+  export EVENT_LOG_FILE  EVENT_LOG_SEVERITY
+  # export more environment variables ...
+
+  umask 077
+  cd $ZOPE_HOME
+
+  case "$1" in 
+
+  start)
+  # start service
+  exec $PYTHON_BIN $ZOPE_HOME/z2.py $ZOPE_OPTS
+
+  # if you want to start in debug mode (not recommended for
+  # production systems):
+  # exec $PYTHON_BIN $ZOPE_HOME/z2.py $ZOPE_OPTS -D &
+  ;;
+  stop)
+  # stop service
+  kill `cat $ZOPE_HOME/var/Z2.pid`
+  ;;
+  restart)
+  # stop service and restart
+  $0 stop
+  $0 start
+  ;;            
+  *)
+  echo "Usage: $0 {start|stop|restart}"
+  exit 1
+  ;;
+  esac
+
+This script lets you perform start / stop / restart operations:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+start
+  Start Zope (and the zdaemon management process)
+
+stop
+  Stop Zope. Kill Zope and the zdaemon management process
+
+restart
+  Stop then start Zope
+
+MS Windows
+++++++++++
+
+The prevalent way to autostart Zope on MS Windows is to install
+Zope as a service.
+
+If you installed Zope on Windows NT/2000/XP to be started manually and later on
+want it started as a service, perform these steps from the command line to
+register Zope as a Windows service:::
+
+  > cd c:\Program Files\zope
+  > bin\lib\win32\PythonService.exe /register 
+  > bin\python.exe ZServer\ZService.py --startup auto install
+
+Replace::
+
+  c:\Program Files\zope
+
+with the path to your Zope installation. Zope should now be installed as a
+service which starts automatically on system boot. To start and stop Zope
+manually, go to the Windows service administration tool, right-click the Zope
+service and select the corresponding entry.
+
+Installing New Products
+=======================
+
+Zope is a framework for building websites from new and existing software, known
+as Zope *products*. A product is a Python package with special conventions that
+register with the Zope framework. The primary purpose of a Zope product is to
+create new kinds of objects that appear in the add list. This extensibility
+through products has spawned a broad market of add-on software for Zope.
+
+The guidelines for packaging a product are given in the "Packaging Products"
+section in the `Zope Products chapter of the Zope Developer Guide
+<http://www.zope.org/Products>`_. However, since these guidelines are not
+enforced, many Zope products adhere to different conventions. This section will
+discuss the different approaches to installing Zope packages.
+
+To install a Zope product, you first download an archive file from a website,
+such as the `Downloads section <http://www.zope.org/Products>`_ of zope.org.
+These archive files come in several varieties, such as tgz (gzipped tar files)
+zip (the popular ZIP format common on Windows), and others.
+
+In general, unpacking these archives will create a subdirectory containing the
+Product itself. For instance, the::
+
+  Poll-1.0.tgz
+
+archive file in the "Packaging Products" section mentioned above contains a
+subdirectory of `Poll`. All the software is contained in this directory.
+
+To install the product, you unarchive the file in the::
+
+  lib/python/Products
+
+directory. In the Poll example, this will create a directory::
+
+  lib/python/Products/Poll
+
+Unfortunately not all Zope developers adhere to this convention. Often the
+archive file will have the::
+
+  lib/python/Products
+
+part of the path included. Worse, the archive might contain no directory, and
+instead have all the files in the top-level of the archive. Thus, it is advised
+to inspect the contents of the archive first.
+
+Once you have the new directory in::
+
+  lib/python/Products
+
+you need to tell Zope that a new product has been added. You can do this by
+restarting your Zope server through the Control Panel of the Zope Management
+Interface (ZMI), or, on POSIX systems, by sending the Zope process a::
+
+  -HUP
+
+signal. For instance, from the Zope directory:::
+
+  kill -HUP `cat var/Z2.pid`
+
+If your Zope server is running in debug mode, a log message will appear
+indicating a new product has been discovered and registered.
+
+To confirm that your product is installed, log into your Zope site and visit
+the Control Panel's Products section. You should see the new product appear in
+the list of installed products.
+
+If there was a problem with the installation, the Control Panel will list it as
+a "Broken Product". Usually this is because Python had a problem importing a
+package, or the software had a syntax error. You can visit the broken product
+in the Control Panel and click on its *Traceback* tab. You will see the Python
+traceback generated when the package was imported.
+
+A traceback generally will tell you what went wrong with the import. For
+instance, a package the software depends on could be missing. To illustrate
+this take a look at the traceback below - a result of trying to install
+CMFOODocument:http://www.zope.org/Members/longsleep/CMFOODocument without the
+(required) CMF package:::
+
+  Traceback (most recent call last):
+  File "/usr/share/zope/2.6.0/lib/python/OFS/Application.py", line 541, in import_product
+  product=__import__(pname, global_dict, global_dict, silly)
+  File "/usr/share/zope/2.6.0/lib/python/Products/CMFOODocument/__init__.py", line 19, in ?
+  import OODocument
+  File "/usr/share/zope/2.6.0/lib/python/Products/CMFOODocument/OODocument.py", line 31, in ?
+  from Products.CMFCore.PortalContent import NoWL, ResourceLockedError
+  ImportError: No module named CMFCore.PortalContent
+
+Server Settings
+===============
+
+The Zope server has a number of settings that can be adjusted for performance.
+Unfortunately, performance tuning is not an exact science, that is, there is no
+recipe for setting parameters. Rather, you have to test every change. To load
+test a site, you should run a test setup with easily reproducible results. Load
+test a few significant spots in your application. The trick is to identify
+typical situations while still permitting automated testing. There are several
+tools to load test websites. One of the simple yet surprisingly useful tools
+is::
+
+  ab
+
+which comes with Apache distributions. With `ab` you can test individual URLs,
+optionally providing cookies and POST data. Other tools often allow one to
+create or record a user session and playing it back multiple times. See eg. the
+`Open System Testing Architecture <http://www.opensta.org>`_, `JMeter
+<http://jakarta.apache.org/jmeter>`_, or Microsoft's `Web Application Stress
+Tool
+<http://www.microsoft.com/technet/treeview/default.asp?url=/technet/itsolutions/intranet/downloads/webstres.asp>`_.
+
+Database Cache
+++++++++++++++
+
+The most important is the database cache setting. To adjust these settings,
+visit the Control Panel and click on the *Database* link.`Database Cache
+settings <img:23-1:Figures/dbcache.png>`_
+
+There are usually seven database connections to the internal Zope database (see
+*Database Connections* below for information about how to change the number of
+connections). Each connection gets its own database cache. The "Target number
+of objects in memory per cache" setting controls just that - the system will
+try not to put more than this number of persistent Zope objects into RAM per
+database connection. So if this number is set to 400 and there are seven
+database connections configured, there should not be more than 2800 objects
+sitting in memory. Obviously, this does not say much about memory consumption,
+since the objects might be anything in size - from a few hundred bytes upwards.
+The cache favors commonly used objects - it wholly depends on your application
+and the kind of objects which memory consumption will result from the number
+set here. As a rule, Zope objects are about as big as the data they contain.
+There is only little overhead in wrapping data into Zope objects.
+
+ZServer Threads
++++++++++++++++
+
+This number determines how many ZServer threads Zope starts to service
+requests. The default number is four (4). You may try to increase this number
+if you are running a heavily loaded website. If you want to increase this to
+more than seven (7) threads, you also should increase the number of database
+connections (see the next section).
+
+Database Connections
+++++++++++++++++++++
+
+We briefly mentioned Zope's internal database connections in the *Database
+Cache* section above. Out of the box, the number of database connections is
+hardwired to seven (7); but this can be changed. There is no "knob" to change
+this number so in order to change the number of database connections, you will
+need to enter quite deep into the systems' bowels. It is probably a wise idea
+to back up your Zope installation before following any of the instructions
+below.
+
+Each database connection maintains its own cache (see above, "Database Cache"),
+so bumping the number of connections up increases memory requirements. Only
+change this setting if you're sure you have the memory to spare.
+
+To change this setting, create a file called "custom_zodb.py" in your Zope
+installation directory. In this file, put the following code::
+
+  import ZODB.FileStorage
+  import ZODB.DB
+
+  filename = os.path.join(INSTANCE_HOME, 'var', 'Data.fs')
+  Storage = ZODB.FileStorage.FileStorage(filename)
+  DB = ZODB.DB(Storage, pool_size=25, cache_size=2000)
+
+This only applies if you are using the standard Zope FileStorage storage.
+
+The "pool_size" parameter is the number of database connections. Note that the
+number of database connections should always be higher than the number of
+ZServer threads by a few (it doesn't make sense to have fewer database
+connections than threads). See above on how to change the number of ZServer
+threads.
+
+Signals (POSIX only)
+====================
+
+Signals are a POSIX inter-process communications mechanism. If you are using
+Windows then this documentation does not apply.
+
+Zope responds to signals which are sent to the process id specified in the file
+'$ZOPE_HOME/var/Z2.pid':
+
+SIGHUP
+  close open database connections, then restart the server process. The common
+  idiom for restarting a Zope server is::
+
+    kill -HUP `cat $ZOPE_HOME/var/Z2.pid`
+
+SIGTERM
+  close open database connections then shut down. The common idiom for shutting
+  down Zope is::
+
+    kill -TERM `cat $ZOPE_HOME/var/Z2.pid`
+
+SIGINT
+  same as SIGTERM
+
+SIGUSR2
+  close and re-open all Zope log files (z2.log, event log, detailed log.) The
+  common idiom after rotating Zope log files is::
+
+    kill -USR2 `cat $ZOPE_HOME/var/Z2.pid`
+
+The process id written to the::
+
+  Z2.pid
+
+file depends on whether Zope is run under the::
+
+  zdaemon
+
+management process. If Zope is run under a management process (as it is by
+default) then the pid of the management process is recorded here. Relevant
+signals sent to the management process are forwarded on to the server process.
+Specifically, it forwards all those signals listed above, plus SIGQUIT and
+SIGUSR1. If Zope is not using a management process (-Z0 on the z2.py command
+line), the server process records its own pid into `z2.pid`, but all signals
+work the same way.
+
+Monitoring
+==========
+
+To detect problems (both present and future) when running Zope on production
+systems, it is wise to watch a few parameters.
+
+Monitor the Event Log and the Access Log
+++++++++++++++++++++++++++++++++++++++++
+
+If you set the EVENT_LOG_FILE (formerly known as the STUPID_LOG_FILE) as an
+environment variable or a parameter to the startup script, you can find
+potential problems logged to the file set there. Each log entry is tagged with
+a severity level, ranging from TRACE (lowest) to PANIC (highest). You can set
+the verbosity of the event log with the environment variable
+EVENT_LOG_SEVERITY. You have to set this to an integer value - see below::
+
+  TRACE=-300   -- Trace messages
+
+  DEBUG=-200   -- Debugging messages
+
+  BLATHER=-100 -- Somebody shut this app up.
+
+  INFO=0       -- For things like startup and shutdown.
+
+  PROBLEM=100  -- This isn't causing any immediate problems, but deserves
+                  attention.
+
+  WARNING=100  -- A wishy-washy alias for PROBLEM.
+
+  ERROR=200    -- This is going to have adverse effects.
+
+  PANIC=300    -- We're dead!
+
+So, for example setting EVENT_LOG_SEVERITY=-300 should give you all log
+messages for Zope and Zope applications that use Zopes' logging system.
+
+You also should look at your access log (usually placed in
+$ZOPE_HOME/var/Z2.log). The Z2.log file is recorded in the `Common Log Format
+<http://www.w3.org/Daemon/User/Config/Logging.html#common-logfile-format>`_.
+The sixth field of each line contains the HTTP status code. Look out for status
+codes of 5xx, server error. Server errors often point to performance problems.
+
+Monitor the HTTP Service
+++++++++++++++++++++++++
+
+You can find several tools on the net which facilitate monitoring of remote
+services, for example `Nagios <http://www.nagios.org/>`_ or `VisualPulse
+<http://www.visualware.com/visualpulse>`_.
+
+For a simple "ping" type of HTTP monitoring, you could also try to put a small
+DTML Method with a known value on your server, for instance only containing the
+character "1". Then, using something along the line of the shell script below,
+you could periodically request the URL of this DTML Method, and mail an error
+report if we are getting some other value (note the script below requires a
+Un*x-like operating system)::
+
+  #!/bin/sh
+
+  # configure the values below
+  URL="http://localhost/ping"
+  EXPECTED_ANSWER="1"
+  MAILTO="your.mailaddress at domain.name"
+  SUBJECT="There seems to be a problem with your website"
+  MAIL_BIN="/bin/mail"
+
+  resp=`wget -O - -q -t 1 -T 1 $URL`
+  if [ "$resp" != "$EXPECTED_ANSWER" ]; then
+  $MAIL_BIN -s "$SUBJECT" $MAILTO <<EOF
+  The URL 
+  ----------------------------------------------
+  $URL 
+  ----------------------------------------------
+  did not respond with the expected value of $EXPECTED_ANSWER. 
+  EOF
+  fi;
+
+Run this script eg. every 10 minutes from cron and you should be set for simple
+tasks. Be aware though that we do not handle connections timeouts well here. If
+the connection hangs, for instance because of firewall misconfiguration `wget`
+will likely wait for quite a while (around 15 minutes) before it reports an
+error.
+
+Log Files
+=========
+
+There are two main sources of log information in Zope, the access log and the
+event log.
+
+Access Log
+++++++++++
+
+The access log records every request made to the HTTP server. It is recorded in
+the `Common Log Format
+<http://www.w3.org/Daemon/User/Config/Logging.html#common-logfile-format>`_.
+
+The default target of the access log is the file $ZOPE_HOME/var/Z2.log. Under
+Unix it is however possible to direct this to the syslog by setting the
+environment variable ZSYSLOG_ACCESS to the desired domain socket (usually
+`/dev/log`)
+
+If you are using syslog, you can also set a facility name by setting the
+environment variable ZSYSLOG_FACILITY. It is also possible to log to a remote
+machine. This is also controlled, you might have guessed it, by an environment
+variable. The variable is called ZSYSLOG_SERVER and should be set to a string
+of the form "host:port" where host is the remote logging machine name or IP
+address and port is the port number the syslog daemon is listening on (usually
+514).
+
+Event Log
++++++++++
+
+The event log (formerly also called "stupid log") logs Zope and third-party
+application message. The ordinary log method is to log to a file specified by
+the EVENT_LOG_FILE, eg. `EVENT_LOG_FILE=$ZOPE_HOME/var/event.log`.
+
+On Unix it is also possible to use the syslog daemon by setting the environment
+variable ZSYSLOG to the desired Unix domain socket, usually `/dev/log` . Like
+with access logs (see above), it is possible to set a facility name by setting
+the ZSYSLOG_FACILITY environment variable, and to log to a remote logging
+machine by setting the ZSYSLOG_SERVER variable to a string of the form
+"host:port", where port usually should be 514.
+
+You can coarsely control how much logging information you want to get by
+setting the variable EVENT_LOG_SEVERITY to an integer number - see the section
+"Monitor the Event Log and the Access Log" above.
+
+Log Rotation
+++++++++++++
+
+Log files always grow, so it is customary to periodically rotate logs. This
+means logfiles are closed, renamed (and optionally compressed) and new logfiles
+get created. On Unix, there is the `logrotate` package which traditionally
+handles this. A sample configuration might look like this::
+
+  compress 
+  /usr/local/zope/var/Z2.log {
+  rotate 25
+  weekly
+  postrotate
+  /sbin/kill -USR2 `cat /usr/local/zope/var/Z2.pid`
+  endscript
+  }
+
+This would tell logrotate to compress all log files (not just Zope's!), handle
+Zopes access log file, keep 25 rotated log files, do a log rotation every week,
+and send the SIGUSR2 signal to Zope after rotation. This will cause Zope to
+close the logfile and start a new one. See the documentation to `logrotate` for
+further details.
+
+On Windows there are no widespread tools for log rotation. You might try the
+`KiWi Syslog Daemon <http://www.kiwisyslog.com>`_ and configure Zope to log to
+it. Also see the sections "Access Log" and "Event Log" above.
+
+Packing and Backing Up the FileStorage Database
+===============================================
+
+The storage used by default by Zope's built-in object database, FileStorage, is
+an undoable storage. This essentially means changes to Zope objects do not
+overwrite the old object data, rather the new object gets appended to the
+database. This makes it possible to recreate an objects previous state, but it
+also means that the file the objects are kept in (which usually resides in
+$ZOPE_HOME/var/Data.fs) always keeps growing.
+
+To get rid of obsolete objects, you need to:: `pack` the ZODB. This can be done
+manually by opening Zopes Control_Panel and clicking on the "Database
+Management" link. Zope offers you the option of removing only object version
+older than an adjustable amount of days.
+
+If you want to automatically pack the ZODB you could tickle the appropriate URL
+with a small python script (the traditional filesystem based kind, not Zopes
+"Script (Python)")::
+
+  #!/usr/bin/python
+  import sys, urllib
+  host = sys.argv[1]
+  days = sys.argv[2]
+  url = "%s/Control_Panel/Database/manage_pack?days:float=%s" % (host, days)
+  try: 
+      f = urllib.urlopen(url).read()
+  except IOError:
+      print "Cannot open URL %s, aborting" % url
+      print "Successfully packed ZODB on host %s" % host
+
+The script takes two arguments, the URL of your server (eg.
+http://mymachine.com) and the number of days old an object version has to be to
+get discarded.
+
+On Unix, put this in eg. the file::
+
+  /usr/local/sbin/zope_pack
+
+and make it executable with::
+
+  chmod +x zope_pack
+
+Then you can put in into your crontab with eg.::
+
+  5 4 * * sun     /usr/local/sbin/zope_pack http://localhost 7
+
+This would instruct your system to pack the ZODB on 4:05 every sunday. It would
+connect to the local machine, and leave object versions younger than 7 days in
+the ZODB.
+
+Under Windows, you should use the scheduler to periodically start the script.
+Put the above script in eg.::
+
+  c:\Program Files\zope_pack.py
+
+or whereever you keep custom scripts, and create a batch file::
+
+  zope_pack.bat
+
+with contents similar to the following:::
+
+  "C:\Program Files\zope\bin\python.exe" "C:\Program Files\zope_pack.py" "http://localhost" 7
+
+The first parameter to python is the path to the python script we just created.
+The second is the root URL of the machine you want to pack, and the third is
+the maximum age of object versions you want to keep. Now instruct the scheduler
+to run this `.bat` file every week.
+
+Zope backup is quite straightforward. If you are using the default storage
+(FileStorage), all you need to do is to save the file::
+
+  $ZOPE_HOME/var/Data.fs
+
+This can be done online, because Zope only appends to the `Data.fs` file - and
+if a few bytes are missing at the end of the file due to a copy while the file
+is being written to, ZODB is usually capable of repairing that upon startup.
+The only thing to worry about would be if someone were to be using the *Undo*
+feature during backup. If you cannot ensure that this does not happen, you
+should take one of two routes. The first is be to shutdown Zope prior to a
+backup, and the second is to do a packing operation in combination with backup.
+Packing the ZODB leaves a file `Data.fs.old` with the previous contents of the
+ZODB. Since Zope does not write to that file anymore after packing, it is safe
+to backup this file even if undo operations are performed on the live ZODB.
+
+To backup `Data.fs` on Linux, you should not `tar` it directly, because `tar`
+will exit with an error if files change in the middle of a `tar` operation.
+Simply copying it over first will do the trick.
+
+Database Recovery Tools
+=======================
+
+To recover data from corrupted ZODB database file (typically located in
+`$ZOPE_HOME/var/Data.fs` ) there is a script `fsrecover.py` located in
+$ZOPE_HOME/lib/python/ZODB.
+
+fsrecover.py has the following help output::
+
+  python fsrecover.py [ <options> ] inputfile outputfile
+
+  Options:
+
+  -f -- force output even if output file exists
+
+  -v level -- Set the 
+  verbosity level:
+
+  0 -- Show progress indicator (default)
+
+  1 -- Show transaction times and sizes
+
+  2 -- Show transaction times and sizes, and
+  show object (record) ids, versions, and sizes.
+
+  -p -- Copy partial transactions. If a data record in the middle of a
+  transaction is bad, the data up to the bad data are packed. The
+  output record is marked as packed. If this option is not used,
+  transaction with any bad data are skipped.
+
+  -P t -- Pack data to t seconds in the past. Note that is the "-p"
+  option is used, then t should be 0.        

Deleted: zope2docs/branches/baijum-reorganize/zope2book/Makefile
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/Makefile	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/Makefile	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,75 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS    =
-SPHINXBUILD   = sphinx-build
-PAPER         =
-
-# Internal variables.
-PAPEROPT_a4     = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS   = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
-
-.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
-
-help:
-	@echo "Please use \`make <target>' where <target> is one of"
-	@echo "  html      to make standalone HTML files"
-	@echo "  pickle    to make pickle files"
-	@echo "  json      to make JSON files"
-	@echo "  htmlhelp  to make HTML files and a HTML help project"
-	@echo "  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
-	@echo "  changes   to make an overview over all changed/added/deprecated items"
-	@echo "  linkcheck to check all external links for integrity"
-
-clean:
-	-rm -rf build/*
-
-html:
-	mkdir -p build/html build/doctrees
-	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
-	@echo
-	@echo "Build finished. The HTML pages are in build/html."
-
-pickle:
-	mkdir -p build/pickle build/doctrees
-	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle
-	@echo
-	@echo "Build finished; now you can process the pickle files."
-
-web: pickle
-
-json:
-	mkdir -p build/json build/doctrees
-	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) build/json
-	@echo
-	@echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
-	mkdir -p build/htmlhelp build/doctrees
-	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp
-	@echo
-	@echo "Build finished; now you can run HTML Help Workshop with the" \
-	      ".hhp project file in build/htmlhelp."
-
-latex:
-	mkdir -p build/latex build/doctrees
-	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex
-	@echo
-	@echo "Build finished; the LaTeX files are in build/latex."
-	@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
-	      "run these through (pdf)latex."
-
-changes:
-	mkdir -p build/changes build/doctrees
-	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes
-	@echo
-	@echo "The overview file is in build/changes."
-
-linkcheck:
-	mkdir -p build/linkcheck build/doctrees
-	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck
-	@echo
-	@echo "Link check complete; look for any errors in the above output " \
-	      "or in build/linkcheck/output.txt."

Copied: zope2docs/branches/baijum-reorganize/zope2book/ObjectOrientation.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/ObjectOrientation.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/ObjectOrientation.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/ObjectOrientation.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,278 @@
+Object Orientation
+==================
+
+To make the best use of Zope, you will need a grasp on the concept of *object
+orientation*, which is a software development pattern used in many programming
+languages (C++, Java, Python and others) and computer systems that simulate
+"real-world" behavior. It stipulates that you should design an application in
+terms of *objects*. This chapter provides a broad overview of the fundamentals
+of object orientation from the perspective of a Zope developer.
+
+Objects
+-------
+
+In Zope, as in other object-oriented systems, your application is designed
+around *objects*, or self-contained "bundles" of data and logic.  It is
+easiest to describe these bundles by comparing them to other programming
+concepts.
+
+In a typical, non-object-oriented application, you will have two things:
+
+- Code.  For example, a typical CGI-based web application may have a bit of
+  logic in the form of a PHP script, which retrieves employee data from a
+  database and displays tabular data to a user.
+
+- Data.  For example, you may have employee data stored in a database, such
+  as MySQL or Oracle, on which some code performs read or change
+  operations.  This data exists almost solely for the purpose of the code
+  that operates upon it; without this code, the data holds little to no
+  value.
+
+In a typical object-oriented application, however, you will have one thing, and
+one thing only:
+
+- Objects.  Simply stated, these objects are collections of code and data
+  wrapped up together.  For example, you may have an "Employee" object that
+  represents an employee.  It will contain data about the employee, such as
+  a phone number, name, and address, much like the information that would
+  be stored in a database.  However, the object will also contain "logic,"
+  or code, that can manipulate and display its data.
+
+In a non-object-oriented application, your data is kept separate from your
+code. But in an object-oriented application, both your data and your code are
+stored in one or more objects, each of which represents a particular "thing".
+These objects can represent just about anything. In Zope, the *Control_Panel*
+is an object, Folders that you create are objects, and even the Zope "root
+folder" is an object. When you use the Zope "add list" to create a new item in
+the Zope Management Interface, you are creating an object. People who extend
+Zope by creating add-ons define their own types of objects, which are then
+entered in to the Zope "add list" so that you can create objects based on them.
+An add-on author might define a "Form" object or a "Weblog" object. Basically,
+anything that can be defined using a noun can be modeled as a Zope object.
+
+As a programming methodology, object orientation allows software developers
+to design and create programs in terms of "real-world" things, such as
+Folders, Control_Panels, Forms, and Employees, instead of designing
+programs based around more "computerish" concepts like bits, streams, and
+integers.  Instead of teaching the computer about our problem by descending
+to its basic vocabulary (bits and bytes), we use an abstraction to teach
+the computer about the problem in terms of a vocabulary that is more
+natural to humans.  The core purpose of object orientation is to allow
+developers to create, to the largest extent possible, a system based on
+abstractions of the natural language of a computer (bits and bytes) into
+the real-world objects, like Employees and Forms, that we can understand
+more readily and quickly.
+
+The concept of abstraction also encourages programmers to break up a larger
+problem by addressing the problem as smaller, more independent
+"sub-problems," which allows developers to define and address solutions in
+much smaller, more feasible terms.  When you design an application in terms
+of objects, they become the pieces that eventually define the solution to
+all the "sub-problems" of a particular "big" problem.
+
+Attributes
+----------
+
+An object's data is defined by its *attributes*, or pieces of data that
+describe aspects of the object.  For example, an attribute of an Employee
+object might be called "phone_number," which might contain a series of
+characters that represent the employee's phone number.  Other attributes of
+an Employee object might be "first_name," "last_name", and "job_title," all
+of which give additional, detailed information about each Employee.
+
+It may help to think of the set of attributes belonging to an object as a
+sort of "mini-database" that contains information representing the
+"real-world thing" that the object is attempting to describe.  The complete
+collection of attributes assigned to an object defines that object's
+*state*.  When one or more of an object's attributes are modified, the
+object is said to have *changed its state*.
+
+Methods
+-------
+
+The set of actions that an object may perform is defined by its *methods*.
+Methods are code definitions attached to an object that perform actions
+based on the object's attributes.  For example, a method of an Employee
+object named "getFirstName" may return the value of the object's
+"first_name" attribute, while a method of an Employee object named
+"setFirstName" might *change* the value of the object's "first_name"
+attribute.  The "getTitle" method of an Employee object may return a value
+of "Vice President" or "Janitor, depending on which Employee object is
+being queried.
+
+Methods are similar to *functions* in procedural languages like 'C'.  The
+key difference between a method and a function is that a method is "bound"
+to, or attached to, an object: instead of operating solely on "external"
+data that is passed to it via arguments, it may also operate on the
+attributes of the object to which it is bound.
+
+Messages
+--------
+
+In an object-oriented system, to do any useful work, an object is required
+to communicate with other objects in the same system. For example, it
+wouldn't be particularly useful to have a single Employee object just
+sitting around in "object-land" with no way to communicate with it.  It
+would then just be as "dumb" as a regular old relational database row, just
+storing some data without the ability to do much else.  We want the
+capability to ask the object to do something useful, or more precisely: we
+want the capability for *other* objects to ask our Employee object to do
+something useful.  For instance, if we create an object named
+"EmployeeSummary," which is responsible for collecting the names of all of
+our employees for later display, we want the EmployeeSummary object to be
+able to ask a set of Employee objects for their first and last names.
+
+When one object communicates with another, it is said to send a *message*
+to another object.  Messages are sent to objects by way of the object's
+*methods*.  For example, our EmployeeSummary object may send a message to
+our Employee object by way of "calling" its "getFirstName" method.  Our
+Employee object would receive the message and return the value of its
+"first_name" attribute.  Messages are sent from one object to another when
+a "sender" object calls a method of a "receiver" object.
+
+When you access a URL that "points to" a Zope object, you are almost always
+sending that Zope object a message.  When you request a response from Zope
+by way of invoking a Zope URL with a web browser, the Zope `object
+publisher <http://www.zope.org/Documentation/Books/ZDG/current/ObjectPublishing.stx>`_
+receives the request from your browser.  It then sends a Zope object a
+message on your browser's behalf by "calling a method" on the Zope object
+specified in the URL.  The Zope object responds to the object publisher
+with a return value, and the object publisher returns the value to your
+browser.
+
+Classes and Instances
+---------------------
+
+A *class* defines an object's behavior and acts as a *constructor* for an
+object.  When we talk about a "kind" of object, like an "Employee" object,
+we actually mean "objects constructed using the Employee class" or, more
+likely, just "objects of the Employee class."  Most objects are members of
+a class.
+
+It is typical to find many objects in a system that are essentially similar
+to one another, save for the values of their attributes.  For instance, you
+may have many Employee objects in your system, each with "first_name" and
+"last_name" attributes. The only difference between these Employee objects
+is the values contained within their attributes.  For example, the
+"first_name" of one Employee object might be "Fred" while another might be
+"Jim".  It is likely that each of these objects would be *members of the
+same class*.
+
+A class is to an object as a set of blueprints is to a house: as many
+houses can be constructed using the same set of blueprints, many objects
+can be constructed using the same class. Objects that share a class
+typically behave identically to one other.  If you visit two houses that
+share the same set of blueprints, you will likely notice striking
+similarities: the layout will be the same, the light switches will be in the
+same places, and the fireplace will almost certainly be in the same
+location.  The shower curtains might be different in each house, but this
+is an *attribute* of each particular house that doesn't change its
+essential similarity with the other.  It is much the same with instances of
+a class: if you "visit" two instances of a class, you would interact with
+both instances in essentially the same way: by calling the same set of
+methods on each.  The data kept in the instance (by way of its attributes)
+might be different, but these instances *behave* in exactly the same way.
+
+The behavior of two objects constructed from the same class is similar
+because they both share the same *methods*, which are not typically defined
+by an object itself, but are instead defined by an object's *class*.  For
+instance, if the Employee class defines the 'getFirstName' method, all
+objects that are members of the Employee class share that method
+definition.  The set of methods assigned to an object's class define the
+*behavior* of that object.
+
+The objects constructed by a class are called *instances of the class*, or
+(more often) just *instances*.  For example, the Zope 'index' page is
+an *instance of* the 'Page Template' class. The 'index' page has an 'id'
+attribute of 'index', while another page may have an 'id' attribute of
+'my_page'.  However, while they have different attribute values, since
+they are both instances of the same class, they both behave identically.
+All the objects that can be administered using the ZMI are instances of a
+class.  Typically, the classes from which these objects are constructed are
+defined in the add-ons created by Zope developers and community members.
+
+Inheritance
+-----------
+
+It is sometimes desirable for objects to share the same essential behavior,
+except for small deviations.  For example, you may want to create a
+ContractedEmployee object that has all the behavior of a "normal" Employee
+object, except that you must keep track of a tax identification number on
+instances of the ContractedEmployee class that is irrelevant for "normal"
+instances of the Employee class.
+
+*Inheritance* is the mechanism that allows you to share essential behavior
+between two objects, while customizing one with a slightly modified set of
+behaviors that differ from or extend the other.
+
+Inheritance is specified at the *class level*.  Since *classes define
+behavior*, if we want to change an object's behavior, we almost always need
+to change its class.
+
+If we base our new "ContractedEmployee" class on the Employee class, but
+add a method to it named "getTaxIdNumber" and an attribute named
+"tax_id_number," the ContractedEmployee class would be said to *inherit
+from* the Employee class.  In the jargon of object orientation, the
+ContractedEmployee class would be said to *subclass from* the Employee
+class, and the *Employee* class would be said to be a *superclass of* the
+ContractedEmployee class.
+
+When a subclass inherits behavior from another class, it doesn't need to
+sit idly by and accept all the method definitions of its superclass if they
+don't suit its needs: if necessary, the subclass can *override* the method
+definitions of its superclass.  For instance, we may want our
+ContractedEmployee class to return a different "title" than instances of
+our Employee class.  In our ContractedEmployee class, we might cause the
+'getTitle' method of the Employee class to be *overridden* by creating a
+method within ContractedEmployee with a different implementation.  For
+example, it may always return "Contractor" instead of a job-specific title.
+
+Inheritance is used extensively in Zope objects.  For example, the Zope
+"Image" class inherits its behavior from the Zope "File" class, since
+images are really just another kind of file, and both classes share many
+behavior requirements.  But the "Image" class adds a bit of behavior that
+allows it to "render itself inline" by printing its content within HTML
+tags, instead of causing a file download.  It does this by *overriding* the
+'index_html' method of the File class.
+
+Object Lifetimes
+----------------
+
+Object instances have a specific *lifetime*, which is typically controlled
+by either a programmer or a user of the system in which the objects "live".
+
+Instances of web-manageable objects in Zope, such as Files, Folders, and
+Page Templates, span from the time the user creates them until they are
+deleted. You will often hear these kinds of objects described as
+*persistent* objects.  These objects are stored in Zope's object database
+(the ZODB).
+
+Other Zope object instances have different lifetimes: some object instances
+last for a "programmer-controlled" period of time.  For instance, the
+object that represents a web request in Zope (often called REQUEST) has a
+well-defined lifetime, which lasts from the moment the object publisher
+receives the request from a remote browser, until a response is sent back
+to that browser, after which it is destroyed automatically.  Zope "session
+data" objects have another well-defined lifetime, which spans from the time
+a programmer creates one on behalf of the user via code, until such time
+that the system (on behalf of the programmer or site administrator) deems
+it necessary to throw away the object in order to conserve space, or to
+indicate an "end" to the user's session.  This is defined by default as 20
+minutes of "inactivity" by the user for whom the object was created.
+
+Summary
+-------
+
+Zope is an object-oriented development environment.  Understanding Zope
+fully requires a grasp of the basic concepts of object orientation,
+including attributes, methods, classes, and inheritance, before setting out
+on a "for-production" Zope development project.
+
+For a more comprehensive treatment on the subject of object orientation,
+buy and read `The Object
+Primer <http://www.ambysoft.com/theObjectPrimer.html>`_ by Scott Ambler.
+There are also excellent object orientation tutorials available on the
+Internet.  See `The Essence of Objects
+chapter <http://www.objectcentral.com/oobook/Chapter2.html>`_ of the book 
+"The Essence of Object Oriented Programming with Java and UML," or the extensive
+`Object FAQ <http://www.objectfaq.com/oofaq2/>`_.

Copied: zope2docs/branches/baijum-reorganize/zope2book/Preface.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/Preface.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/Preface.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/Preface.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,214 @@
+Preface
+=======
+
+Welcome to *The Zope2 Book*.  This book is designed to introduce you
+to ``Zope2``, an open-source web application server.
+
+To make effective use of the book, you should know how to use a web
+browser and have a basic understanding of the ``Hyper
+Text Markup Language`` (HTML) and ``Uniform Resource Locators`` (URLs).
+
+You don't need to be a highly-skilled programmer in order to use Zope2,
+but you may find the understanding of some programming concepts (particularly
+in object-oriented programming) to be extremely helpful.
+
+Preface to the 2.12 edition
+---------------------------
+
+This book has originally been written for Zope 2.6 back in 2002. It has been
+available in an almost unmodified form for the last seven years. During those
+many years quite a bit has happened in Zope itself and the general web market.
+
+The 2.12 edition of this book does not try to write a new book on how-to do
+Zope development today. Instead it tries to update the original books content
+to be true and helpful again. Many of the underlying principles of Zope2 have
+not changed in the last years. The ZMI, security machinery, page templates and
+how-to use the ZCatalog are still there in an almost unmodified fashion.
+The general ideas behind object orientation, being Python based and the
+general architecture are still the same.
+
+If you want to understand Zope2 you still need to understand how Acquisition
+works, even though it has been discouraged as a way to design your application
+logic.
+
+One of the most notable differences between the original Zope2 approach and
+todays best-practices is in the way you develop applications with Zope2. The
+original Zope2 approach has focussed on a Through-The-Web (TTW) development
+model. You would create your entire application and manage your data through
+the same browser interface and store everything transparently in the same
+database. This model has worked very well in the beginning of "the web" as
+many dynamic websites have been rather simple and specialized projects.
+
+Over the years websites have grown their requirements and often turned into
+development projects of a considerable size. Today websites are understood
+as applications in themselves and need an approach which is no longer
+compatible with the TTW approach of the early Zope2.
+
+In this book you will still read about using the TTW approach for many of
+the examples. Please understand this as a way to quickly and easily learn
+about the underlying technologies. If you want to built an application based
+on top of Zope2, you are almost always better of approaching the project from
+the so called "file-system based approach" or using Python packages to extend
+Zope in a predictable way.
+
+
+How the Book Is Organized
+-------------------------
+
+This book is laid out in the following chapters:
+
+- Introducing Zope
+
+    This chapter explains what Zope is and what it can do for you. You'll also
+    learn about the differences between Zope and other web application servers.
+
+- Zope Concepts and Architecture
+
+    This chapter explains fundamental Zope concepts and describes the basics
+    about Zope's architecture.
+
+- Installing and Starting Zope
+
+    This chapter explains how to install and start Zope for the first time. By
+    the end of this chapter, you will have Zope installed and working.
+
+- Object Orientation
+
+    This chapter explains the concept of *object orientation*, which is the
+    development methodology most often used to create Zope applications.
+
+- Using the Zope Management Interface
+
+    This chapter explains how to use Zope's web-based management interface. By
+    the end of this chapter, you will be able to navigate around the Zope
+    object space, copy and move objects, and use other basic Zope features.
+
+- Using Basic Zope Objects
+
+    This chapter introduces *objects*, which are the most important elements of
+    Zope. You'll learn the basic Zope objects: content objects, presentation
+    objects, and logic objects, and you'll build a simple application using
+    these objects.
+
+- Acquisition
+
+    This chapter introduces *Acquisition*, which is Zope's mechanism for
+    sharing site behavior and content.
+
+- Basic Zope Scripting
+
+    This chapter will introduce you to the basics of scripting.
+
+- Using Zope Page Templates
+
+    This chapter introduces *Zope Page Templates*, another Zope tool used to
+    create dynamic web pages. You will learn about basic template statements
+    that let you insert dynamic content, and how to create and edit page
+    templates.
+
+- Creating Basic Zope Applications  
+
+    This chapter presents several real-world examples of building a Zope
+    application. You'll learn how to use basic Zope objects and how they can
+    work together to form basic applications.
+
+- Users and Security
+
+    This chapter looks at how Zope handles users, authentication,
+    authorization, and other security-related matters.
+
+- Advanced Page Templates
+
+    This chapter goes into more depth with Zope Page Templates. You will learn
+    all about template statements, expression types, and macros, which let you
+    reuse presentation elements.
+
+- Advanced Zope Scripting
+
+    This chapter covers scripting Zope with Python. You will learn how to write
+    business logic in Zope using tools more powerful than TAL, about the idea
+    of *scripts* in Zope, and about Scripts (Python).
+
+- Zope Services
+
+    This chapter covers Zope objects that are considered "services," which
+    don't readily fit into any of the basic "content," "presentation," or
+    "logic" object groups.
+
+- Basic DTML
+
+    This chapter introduces DTML, the second tag-based scripting language.
+    You'll learn DTML syntax, its basic tags, and how to use DTML templates and
+    scripting facilities. After reading this chapter, you'll be able to create
+    dynamic web pages with DTML.
+
+- Advanced DTML
+
+    This chapter takes a closer look at DTML. You'll learn about DTML security,
+    the tricky issue of how variables are looked up in DTML, advanced use of
+    basic tags, and the myriad of special purpose tags.
+
+- Searching and Categorizing Content
+
+    This chapter shows you how to index and search objects with Zope's built-in
+    search engine: the *Catalog*. You'll learn about indexing concepts,
+    different patterns for indexing and searching, metadata, and search
+    results.
+
+- Relational Database Connectivity
+
+    This chapter describes how Zope connects to external relational databases.
+    You'll learn about features that allow you to treat relational data as
+    though it were Zope objects, and security and performance considerations.
+
+- Virtual Hosting Services
+
+    This chapter explains how to set up Zope in a "virtual hosting"
+    environment, in which Zope sub-folders can be served as "top-level" host
+    names. It includes examples that allow virtual hosting to be performed
+    either "natively" or using Apache's 'mod_rewrite' facility.
+
+- Sessions
+
+    This chapter describes Zope's "sessioning" services, which allow Zope
+    developers to "keep state" between HTTP requests.
+
+- Scalability and ZEO
+
+    This chapter covers issues and solutions for building and maintaining large
+    web applications, and focuses on issues of management and scalability. In
+    particular, the Zope Enterprise Option (ZEO) is covered in detail. You'll
+    learn about the tools and techniques needed to turn a small site into a
+    large-scale site, servicing many simultaneous visitors.
+
+- Managing Zope Objects Using External Tools
+
+    This chapter explains how to use tools outside of your web browser to
+    manipulate Zope objects.
+
+- Maintaining Zope
+
+    This chapter covers Zope maintenance and administration tasks, such as
+    database "packing" and package installation.
+
+- Appendix A: DTML Reference
+
+    Reference of DTML syntax and commands.
+
+- Appendix B: API Reference
+
+    Reference of Zope object APIs.
+
+- Appendix C: Page Template Reference
+
+    Reference of Zope Page Template syntax and commands.
+
+- Appendix D: Zope Resources
+
+    Reference of "resources" which can be used to further enhance your Zope
+    learning experience.
+
+- Appendix E:
+
+    DTML Name Lookup Rules Describes DTML's name lookup rules.
+

Copied: zope2docs/branches/baijum-reorganize/zope2book/RelationalDatabases.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/RelationalDatabases.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/RelationalDatabases.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/RelationalDatabases.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,1382 @@
+Relational Database Connectivity
+================================
+
+
+.. note::
+
+    This chapter explains you how to access a relational databases directly through
+    SQL. The alternative and modern way integrating a RDBMS with Zope is using an
+    Object-Relational-Mapper (ORM). An ORM abstracts the SQL layer and allows you
+    to deal with database tables, rows etc. like standard Python objects.
+
+    The most common and most flexible ORM in the
+    Python world is `SQLAlchemy <http://www.sqlalchemy.org>`_ . You can not use
+    SQLAlchemy directly within Zope because the transaction system of the RDBMS
+    must participate with Zope transaction. This integration layer is implemented
+    through the `zope.sqlalchemy <http://pypi.python.org/pypi/zope.sqlalchemy>`_
+    module.
+
+
+The Zope Object Database (ZODB) is used to store all the pages,
+files and other objects you create. It is fast and requires almost
+no setting up or maintenance.  Like a filesystem, it is especially
+good at storing moderately-sized binary objects such as graphics.
+
+Relational Databases work in a very different way. They are based on
+tables of data such as this::
+
+  Row   First Name   Last Name  Age
+  ===   ==========   =========  ===
+  1     Bob          McBob      42
+  2     John         Johnson    24
+  3     Steve        Smith      38
+
+Information in the table is stored in rows. The table's column
+layout is called the *schema*.  A standard language, called the
+Structured Query Language (SQL) is used to query and change tables
+in relational databases. This chapter assumes a basic knowledge of SQL,
+if you do not know SQL there are many books and tutorials on the web.
+
+Relational databases and object databases are very different and
+each possesses its own strengths and weaknesses. Zope allows you to
+use either, providing the flexibility to choose the storage
+mechanism which is best for your data. The most common reasons to
+use relational databases are to access an existing database or to
+share data with other applications.  Most programming languages and
+thousands of software products work with relational
+databases. Although it is possible to access the ZODB from other
+applications and languages, it will often require more effort than
+using a relational database.
+
+By using your relational data with Zope you retain all of Zope's
+benefits including security, dynamic presentation, and
+networking. You can use Zope to dynamically tailor your data access,
+data presentation and data management.
+
+Common Relational Databases
+---------------------------
+
+There are many relational database systems. The following is a brief
+list of some of the more popular database systems:
+
+Oracle
+  Oracle is arguably the most powerful and popular
+  commercial relational database. It is, however, relatively
+  expensive and complex. Oracle can be purchased or evaluated from
+  the `Oracle Website <http://www.oracle.com/index.html>`_.
+
+PostgreSQL
+  PostgreSQL is a leading open source relational
+  database with good support for SQL standards.  You can
+  find more information about PostgreSQL at the `PostgreSQL web
+  site <http://www.postgresql.org/>`_.
+
+MySQL
+  MySQL is a fast open source relational database. You
+  can find more information about MySQL at the `MySQL web
+  site <http://www.mysql.com/>`_. 
+
+SQL Server
+  Microsoft's full featured SQL Server for the
+  Windows operating systems. For any serious use on Windows, it is
+  preferable to Microsoft Access. Information from
+  http://www.microsoft.com/sql/
+
+The mechanics of setting up relational database is different for
+each database and is thus beyond the scope of this book.  All of the
+relational databases mentioned have their own installation and
+configuration documentation that you should consult for specific
+details.
+
+Zope can connect to all the above-listed database systems; however,
+you should be satisfied that the database is running and operating
+in a satisfactory way on its own before attempting to connect it to
+Zope.  An exception to this policy is Gadfly, which is included with
+Zope and requires no setup.
+
+
+Database Adapters
+-----------------
+
+A database can only be used if a Zope Database Adapter is available,
+though a Database Adapter is fairly easy to write if the database has
+Python support. Database adapters can be found in the
+`Zope Framework category of the Python Package Index <http://pypi.python.org/pypi?:action=browse&c=514>`_.
+
+At the time of writing the following adapters were available, but this
+list constantly changes as more adapters are added.
+
+Oracle
+  `DCOracle2 <http://www.zope.org/Members/matt/dco2>`_ package
+  from Zope Corporation includes the ZoracleDA
+
+PostgreSQL
+  The newest and prefered DA is ZPsycopgDA included in 
+  `psycopg <http://initd.org/software/psycopg package>`_. The older
+  `ZpopyDA <http://sourceforge.net/projects/zpopyda/>`_ is also
+  available.
+
+MySQL
+  `ZMySQLDA <http://www.zope.org/Members/adustman/Products/ZMySQLDA>`_
+  Available as source and a Linux binary package.
+
+SQLServer
+  `mxODBC <http://www.egenix.com>`_ is written by Egenix
+  and very well maintained. There is also
+  `ZODBC DA <http://www.zope.org/Products/DA/ZODBCDA>`_ is
+  written by Zope Corporation. Available
+  for the Windows platform only. This DA is no longer actively
+  maintainted.
+
+If you will need to connect to more than one database or wish to connect
+as to the same database as different users then you may use multiple
+database connection objects.
+
+Setting up a Database Connection
+--------------------------------
+
+Once the database adapter has been downloaded and installed you may
+create a new *Database Connection* from the *Add* menu on the Zope
+management pages. All database connection management interfaces are
+fairly similar.
+
+The database connection object is used to establish and manage the
+connection to the database. Because the database runs externally to
+Zope, they may require you to specify information necessary to
+connect successfully to the database. This specification, called a
+*connection string*, is different for each kind of database. For
+example, the figure below shows the PostgreSQL database connection
+add form.
+
+.. figure:: Figures/psycopg.png
+
+   PostgreSQL Database Connection
+
+We'll be using the Gadfly database for the examples in this chapter,
+as it requires the least amount of configuration.  If you happen to
+be using a different database while "playing along", note that
+Database Connections work slightly differently depending on which
+database is being used, however most have a "Test" tab for issuing a
+test SQL query to the database and a "Browse" tab which will show
+the table structure. It is good practice to use these tabs to test
+the database connection before going any further.
+
+Select the *Z Gadfly Database Connection* from the add list.  This
+will take you to the add form for a Gadfly database connection.
+Select and add a Gadlfy connection to Zope. Note that because Gadfly
+runs inside Zope you do not need to specify a "connection string".
+
+Select the *Demo* data source, specify *Gadfly_database_connection* for
+the id, and click the *Add* button.  This will create a new Gadfly
+Database Connection. Select the new connection by clicking on it.
+
+You are looking at the *Status* view of the Gadfly Database
+Connection.  This view tells you if you are connected to the
+database, and it exposes a button to connect or disconnect from the
+database.  In general Zope will manage the connection to your
+database for you, so in practice there is little reason to manually
+control the connection.  For Gadfly, the action of connecting and
+disconnecting is meaningless, but for external databases you may
+wish to connect or disconnect manually to do database maintenance.
+
+The next view is the *Properties* view.  This view shows you the data
+source and other properties of the Database Connection.  This is useful
+if you want to move your Database Connection from one data source to
+another. The figure below shows the *Properties* view.
+
+.. figure:: Figures/10-3.png
+
+   The Properties view
+
+You can test your connection to a database by going to the *Test*
+view.  This view lets you type SQL code directly and run it on your
+database.  This view is used for testing your database and issuing
+"one-time" SQL commands (like statements for creating tables).  This
+is *not* the place where you will enter most of your SQL code. SQL
+commands typically reside in *Z SQL Methods* which will be discussed
+in detail later in this chapter.
+
+Let's create a table in your database for use in this chapter's
+examples.  The *Test* view of the Database Connection allows you to
+send SQL statements directly to your database. You can create tables
+by typing SQL code directly into the *Test* view; there is no need
+to use a SQL Method to create tables.  Create a table called
+*employees* with the following SQL code by entering it into the
+*Test* tab::
+
+  CREATE TABLE employees
+  (
+  emp_id integer,
+  first varchar,
+  last varchar,
+  salary float
+  )
+
+Click the *Submit Query* button of the *Test* tab to run the SQL
+command. Zope should return a confirmation screen that confirms that
+the SQL code was run.  It will additionally display the results, if
+any.
+
+The SQL used here works under Gadfly but may differ depending on
+your database.  For the exact details of creating tables with your
+database, check the user documentation from your specific database
+vendor.
+
+This SQL will create a new table in your Gadfly database called
+*employees*.  This table will have four columns, *emp_id*, *first*,
+*last* and *salary*.  The first column is the "employee id", which
+is a unique number that identifies the employee.  The next two
+columns have the type *varchar* which is similar to a string.  The
+*salary* column has the type *float* which holds a floating point
+number.  Every database supports different kinds of types, so you
+will need to consult your documentation to find out what kind of
+types your database supports.
+
+To examine your table, go to the *Browse* view.  This lets you view
+your database's tables and the schema of each table. Here, you can
+see that there is an *employees* table, and if you click on the
+*plus symbol*, the table expands to show four columns, *emp_id*,
+*first*, *last* and *salary* as shown in [10-3].
+
+.. figure:: Figures/10-4.png
+
+   Browsing the Database Connection
+
+This information is very useful when creating complex SQL
+applications with lots of large tables, as it lets you discover the
+schemas of your tables. However, not all databases support browsing
+of tables.
+
+Now that you've created a database connection and have defined a
+table, you can create Z SQL Methods to operate on your database.
+
+Z SQL Methods
+-------------
+
+*Z SQL Methods* are Zope objects that execute SQL code through a
+Database Connection.  All Z SQL Methods must be associated with a
+Database Connection. Z SQL Methods can both query and change
+database data.  Z SQL Methods can also contain more than one SQL
+command. In detail a Z SQL method may contain multiple INSERT
+or UPDATE statements but at most one SELECT statement.
+
+A ZSQL Method has two functions: it generates SQL to send to the
+database and it converts the response from the database into an
+object. This has the following benefits:
+
+- Generated SQL will take care of special characters that may need to be
+  quoted or removed from the query. This speeds up code development.
+
+- If the underlying database is changed (for example, from Postgres
+  to Oracle), then the generated SQL will, in some cases,
+  automatically change too, making the application more portable.
+
+- Results from the query are packaged into an easy to use object which
+  will make display or processing of the response very simple.
+
+- Transactions are mediated. Transactions are discussed in more
+  detail later in this chapter.
+
+Examples of ZSQL Methods
+-------------------------
+
+Create a new Z SQL Method called *hire_employee* that inserts a new
+employee in the *employees* table.  When a new employee is hired,
+this method is called and a new record is inserted in the
+*employees* table that contains the information about the new
+employee.  Select *Z SQL Method* from the *Add List*.  This will
+take you to the add form for Z SQL Methods, as shown in the figure
+below.
+
+.. figure:: Figures/10-5.png
+
+   The Add form for Z SQL Methods
+
+As usual, you must specify an *id* and *title* for the Z SQL Method. In
+addition you need to select a Database Connection to use with this Z SQL
+Methods. Give this new method the id *hire_employee* and select the
+*Gadfly_database_connection* that you created in the last section.
+
+Next, you can specify *arguments* to the Z SQL Method. Just like
+Scripts, Z SQL Methods can take arguments. Arguments are used to
+construct SQL statements.  In this case your method needs four
+arguments, the employee id number, the first name, the last name and
+the employee's salary. Type "emp_id first last salary" into the
+*Arguments* field. You can put each argument on its own line, or you
+can put more than one argument on the same line separated by
+spaces. You can also provide default values for argument just like
+with Python Scripts. For example, 'emp_id=100' gives the 'emp_id'
+argument a default value of 100.
+
+The last form field is the *Query template*.  This field contains
+the SQL code that is executed when the Z SQL Method is called.  In
+this field, enter the following code::
+
+  insert into employees (emp_id, first, last, salary) values
+  (<dtml-sqlvar emp_id type="int">, 
+   <dtml-sqlvar first type="string">, 
+   <dtml-sqlvar last type="string">,
+   <dtml-sqlvar salary type="float">
+  )
+
+Notice that this SQL code also contains DTML.  The DTML code in this
+template is used to insert the values of the arguments into the SQL
+code that gets executed on your database.  If the *emp_id* argument
+had the value *42*, the *first* argument had the value *Bob* your
+*last* argument had the value *Uncle* and the *salary* argument had
+the value *50000.00* then the query template would create the
+following SQL code::
+
+  insert into employees (emp_id, first, last, salary) values
+  (42,
+   'Bob',
+   'Uncle',
+   50000.00
+  )
+
+The query template and SQL-specific DTML tags are explained further
+in the next section of this chapter.
+
+You have your choice of three buttons to click to add your new Z SQL
+Method.  The *Add* button will create the method and take you back
+to the folder containing the new method.  The *Add and Edit* button
+will create the method and make it the currently selected object in
+the *Workspace*.  The *Add and Test* button will create the method
+and take you to the method's *Test* view so you can test the new
+method.  To add your new Z SQL Method, click the *Add* button.
+
+Now you have a Z SQL Method that inserts new employees in the
+*employees* table.  You'll need another Z SQL Method to query the
+table for employees.  Create a new Z SQL Method with the id
+*list_all_employees*.  It should have no arguments and contain the
+following SQL code::
+
+  select * from employees
+
+This simple SQL code selects all the rows from the *employees*
+table.  Now you have two Z SQL Methods, one to insert new employees
+and one to view all of the employees in the database.  Let's test
+your two new methods by inserting some new employees in the
+*employees* table and then listing them.  To do this, click on the
+*hire_employee* Method and click the *Test* tab.  This will take you
+to the *Test* view of the Method, as shown in the figure below.
+
+.. figure:: Figures/10-6.png
+
+   The hire_employee Test view
+
+Here, you see a form with four input boxes, one for each argument to
+the *hire_employee* Z SQL Method.  Zope automatically generates this
+form for you based on the arguments of your Z SQL Method.  Because
+the *hire_employee* Method has four arguments, Zope creates this
+form with four input boxes. You can test the method by entering an
+employee number, a first name, a last name, and a salary for your
+new employee.  Enter the employee id "42", "Bob" for the first name,
+"McBob" for the last name and a salary of "50000.00". Then click the
+*Submit Query* button. You will then see the results of your test.
+
+The screen says *This statement returned no results*.  This is
+because the *hire_employee* method only inserts new information in
+the table, it does not select any information out of the table, so
+no records were returned.  The screen also shows you how the query
+template get rendered into SQL.  As expected, the *sqlvar* DTML tags
+rendered the four arguments into valid SQL code that your database
+executed.  You can add as many employees as you'd like by repeatedly
+testing this method.
+
+To verify that the information you added is being inserted into the
+table, select the *list_all_employees* Z SQL Method and click on its
+*Test* tab.  
+
+This view says *This query requires no input*, indicating the
+*list_all_employees* does not have any argument and thus, requires
+no input to execute.  Click on the *Submit Query* button to test the
+method.
+
+The *list_all_employees* method returns the contents of your
+*employees* table.  You can see all the new employees that you
+added. Zope automatically generates this tabular report screen for
+you. Next we'll show how you can create your own user interface to
+your Z SQL Methods to integrate them into your website.
+
+Displaying Results from Z SQL Methods
+-------------------------------------
+
+Querying a relational database returns a sequence of results. The items
+in the sequence are called *result rows*.  SQL query results are always a
+sequence. Even if the SQL query returns only one row, that row is the
+only item contained in a list of results.
+
+Somewhat predictably, as Zope is `object oriented
+<ObjectOrientation.html>`_, a Z SQL method returns a *Result object*. All
+the result rows are packaged up into one object. For all practical
+purposes, the result object can be thought of as rows in the database table
+that have been turned into Zope objects.  These objects have attributes
+that match the schema of the database result.
+
+Result objects can be used from DTML to display the results of calling
+a Z SQL Method.  For example, add a new DTML Method to your site called
+*listEmployees* with the following DTML content::
+
+  <dtml-var standard_html_header>
+
+    <ul>
+    <dtml-in list_all_employees>
+      <li><dtml-var emp_id>: <dtml-var last>, <dtml-var first> 
+        makes <dtml-var salary> Euro a year.
+      </li>
+    </dtml-in>
+    </ul>
+
+  <dtml-var standard_html_footer>
+
+and the ZPT version::
+
+  <div>
+    <ul>
+      <li tal:repeat="row context/list_all_employees">
+        <span tal:content="string:${row/id}: ${row/last} ${row/first} 
+              makes ${row/salary} Euro a year.
+      </li>
+    </ul>
+  </div>
+
+This method calls the *list_all_employees* Z SQL Method from
+DTML. The *in* tag is used to iterate over each Result object
+returned by the *list_all_employees* Z SQL Method.  Z SQL Methods
+always return a list of objects, so you will almost certainly use
+them from the DTML *in* tag unless you are not interested in the
+results or if the SQL code will never return any results, like
+*hire_employee*.
+
+The body of the *in* tag is a template that defines what gets rendered
+for each Result object in the sequence returned by *list_all_employees*.
+In the case of a table with three employees in it, *listEmployees* might
+return HTML that looks like this::
+
+  <html>
+    <body>
+
+    <ul>
+      <li>42: Roberts, Bob 
+        makes $50,000 a year.
+      </li>
+      <li>101: leCat, Cheeta 
+        makes $100,000 a year.
+      </li>
+      <li>99: Junglewoman, Jane 
+        makes $100,001 a year.
+      </li>
+    </ul>
+
+    </body>
+  </html>
+
+The *in* tag rendered an HTML list item for each Result object returned
+by *list_all_employees*.
+
+Zope Database Adapters behave slightly differently regarding how
+they handle different types of data. However the more modern ones
+will return the Python type that is closest to the SQL type - as
+there are far more types in SQL than in Python there cannot be a
+complete match. For example, a date will usually be returned as a
+Zope DateTime object; char, varchar and text will all be returned as
+strings.
+
+An important difference between result objects and other Zope
+objects is that result objects do not get created and permanently
+added to Zope.  Result objects are not persistent. They exist for
+only a short period of time; just long enough for you to use them in
+a result page or to use their data for some other purpose.  As soon
+as you are done with a request that uses result objects they go
+away, and the next time you call a Z SQL Method you get a new set of
+fresh result objects.
+
+Next we'll look at how to create user interfaces in order to
+collect data and pass it to Z SQL Methods.
+
+Providing Arguments to Z SQL Methods
+------------------------------------
+
+So far, you have the ability to display employees with the
+*listEmployees* DTML Method which calls the *list_all_employees* Z
+SQL Method.  Now let's look at how to build a user interface for the
+*hire_employee* Z SQL Method. Recall that the *hire_employee*
+accepts four arguments, *emp_id*, *first*, *last*, and *salary*.
+The *Test* tab on the *hire_employee* method lets you call this
+method, but this is not very useful for integrating into a web
+application. You need to create your own input form for your Z SQL
+Method or call it manually from your application.
+
+The Z Search Interface can create an input form for you
+automatically.  In the chapter entitled `Searching and Categorizing
+Content <SearchingZCatalog.html>`_, you used the Z Search Interface to
+build a form/action pair of methods that automatically generated an
+HTML search form and report screen that queried the Catalog and
+returned results.  The Z Search Interface also works with Z SQL
+Methods to build a similar set of search/result screens.
+
+Select *Z Search Interface* from the add list and specify
+*hire_employee* as the *Searchable object*. Enter the value
+"hireEmployeeReport" for the *Report Id*, "hireEmployeeForm" for the
+*Search Id* and check the "Generate DTML Methods" button then click
+*Add*.
+
+Click on the newly created *hireEmployeeForm* and click the *View*
+tab.  Enter an employee_id, a first name, a last name, and salary
+for a new employee and click *Submit*.  Zope returns a screen that
+says "There was no data matching this query".  Because the report
+form generated by the Z Search Interface is meant to display the
+result of a Z SQL Method, and the *hire_employee* Z SQL Method does
+not return any results; it just inserts a new row in the table.
+Edit the *hireEmployeeReport* DTML Method a little to make it more
+informative.  Select the *hireEmployeeReport* Method.  It should
+contain the following long stretch of DTML::
+
+  <dtml-var standard_html_header>
+
+  <dtml-in hire_employee size=50 start=query_start>
+
+     <dtml-if sequence-start>
+
+        <dtml-if previous-sequence>
+
+          <a href="<dtml-var URL><dtml-var sequence-query
+                   >query_start=<dtml-var
+                   previous-sequence-start-number>">
+          (Previous <dtml-var previous-sequence-size> results)
+          </a>
+
+        </dtml-if previous-sequence>
+
+        <table border>
+          <tr>
+          </tr>
+
+     </dtml-if sequence-start>
+
+          <tr>
+          </tr>
+
+     <dtml-if sequence-end>
+
+        </table>
+        <dtml-if next-sequence>
+
+           <a href="<dtml-var URL><dtml-var sequence-query
+             >query_start=<dtml-var
+              next-sequence-start-number>">
+           (Next <dtml-var next-sequence-size> results)
+           </a>
+
+        </dtml-if next-sequence>
+
+     </dtml-if sequence-end>
+
+  <dtml-else>
+
+    There was no data matching this <dtml-var title_or_id> query.
+
+  </dtml-in>
+
+  <dtml-var standard_html_footer>
+
+This is a pretty big piece of DTML!  All of this DTML is meant to
+dynamically build a batch-oriented tabular result form.  Since we
+don't need this, let's change the generated *hireEmployeeReport*
+method to be much simpler::
+
+  <dtml-var standard_html_header>
+
+  <dtml-call hire_employee>
+
+  <h1>Employee <dtml-var first> <dtml-var last> was Hired!</h1>
+
+  <p><a href="listEmployees">List Employees</a></p>
+
+  <p><a href="hireEmployeeForm">Back to hiring</a></p>
+
+  <dtml-var standard_html_footer>
+
+Now view *hireEmployeeForm* and hire another new employee.  Notice
+how the *hire_employee* method is called from the DTML *call* tag.
+This is because we know there is no output from the *hire_employee*
+method. Since there are no results to iterate over, the method does not
+need to be called with the *in* tag. It can be called simply with the
+*call* tag.  
+
+You now have a complete user interface for hiring new employees.
+Using Zope's security system, you can now restrict access to this
+method to only a certain group of users whom you want to have
+permission to hire new employees.  Keep in mind, the search and
+report screens generated by the Z Search Interface are just
+guidelines that you can easily customize to suite your needs.
+
+Next we'll take a closer look at precisely controlling SQL queries.
+You've already seen how Z SQL Methods allow you to create basic SQL
+query templates. In the next section you'll learn how to make the
+most of your query templates.
+
+Dynamic SQL Queries
+-------------------
+
+A Z SQL Method query template can contain DTML that is evaluated when the
+method is called.  This DTML can be used to modify the SQL code that is
+executed by the relational database.  Several SQL specific DTML tags
+exist to assist you in the construction of complex SQL queries. In the
+next sections you'll learn about the *sqlvar*, *sqltest* and *sqlgroup*
+tags.
+
+Inserting Arguments with the *Sqlvar* Tag
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It's pretty important to make sure you insert the right kind of data
+into a column in a database.  You database will complain if you try to
+use the string "12" where the integer 12 is expected. SQL requires that
+different types be quoted differently. To make matters worse, different
+databases have different quoting rules.
+
+In addition to avoiding errors, SQL quoting is important for security.
+Suppose you had a query that makes a select::
+
+  select * from employees 
+    where emp_id=<dtml-var emp_id>
+
+This query is unsafe since someone could slip SQL code into your
+query by entering something like *12; drop table employees* as
+an *emp_id*. To avoid this problem you need to make sure that your
+variables are properly quoted. The *sqlvar* tag does this for you. Here
+is a safe version of the above query that uses *sqlvar*::
+
+    select * from employees 
+      where emp_id=<dtml-sqlvar emp_id type=int>
+
+The *sqlvar* tag operates similarly to the regular DTML *var* tag in
+that it inserts values. However it has some tag attributes targeted at
+SQL type quoting, and dealing with null values. The *sqlvar* tag
+accepts a number of arguments:
+
+*name*
+  The *name* argument is identical to the name argument for
+  the *var* tag.  This is the name of a Zope variable or Z SQL Method
+  argument. The value of the variable or argument is inserted into the
+  SQL Query Template.  A *name* argument is required, but the
+  "name=" prefix may be omitted.
+
+*type*
+  The *type* argument determines the way the *sqlvar*
+  tag should format the value of the variable or argument being
+  inserted in the query template.  Valid values for type are
+  *string*, *int*, *float*, or *nb*.  *nb* stands for non-blank
+  and means a string with at least one character in it. The *sqlvar*
+  tag *type* argument is required.
+
+*optional*
+  The *optional* argument tells the *sqlvar* tag
+  that the variable or argument can be absent or be a null
+  value.  If the variable or argument does not exist or is a
+  null value, the *sqlvar* tag does not try to render it.  The
+  *sqlvar* tag *optional* argument is optional.
+
+The *type* argument is the key feature of the *sqlvar* tag. It
+is responsible for correctly quoting the inserted variable.  See
+Appendix A for complete coverage of the *sqlvar* tag.
+
+You should always use the *sqlvar* tag instead of the *var* tag
+when inserting variables into a SQL code since it correctly
+quotes variables and keeps your SQL safe.
+
+Equality Comparisons with the *sqltest* Tag
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Many SQL queries involve equality comparison operations.  These
+are queries that ask for all values from the table that are in
+some kind of equality relationship with the input.  For example,
+you may wish to query the *employees* table for all employees
+with a salary *greater than* a certain value.
+
+To see how this is done, create a new Z SQL Method named
+*employees_paid_more_than*.  Give it one argument, *salary*,
+and the following SQL template::
+
+  select * from employees 
+    where <dtml-sqltest salary op=gt type=float>
+
+Now click *Add and Test*.  The *op* tag attribute is set to *gt*,
+which stands for *greater than*.  This Z SQL Method will only return
+records of employees that have a higher salary than what you enter in
+this input form.  The *sqltest* builds the SQL syntax necessary to
+safely compare the input to the table column. Type "10000" into the
+*salary* input and click the *Test* button. As you can see the
+*sqltest* tag renders this SQL code::
+
+  select * from employees
+    where salary > 10000
+
+The *sqltest* tag renders these comparisons to SQL taking into
+account the type of the variable and the particularities of the
+database.  The *sqltest* tag accepts the following tag parameters:
+
+*name*
+  The name of the variable to insert.
+
+*type*
+  The data type of the value to be inserted. This
+  attribute is required and may be one of *string*, *int*,
+  *float*, or *nb*. The nb data type stands for "not blank" and
+  indicates a string that must have a length that is greater
+  than 0. When using the nb type, the *sqltest* tag will not
+  render if the variable is an empty string.
+
+*column*
+  The name of the SQL column, if different than the *name*
+  attribute.
+
+*multiple*
+  A flag indicating whether multiple values may be
+  provided. This lets you test if a column is in a set of
+  variables. For example when *name* is a list of strings "Bob" ,
+  "Billy" , '<dtml-sqltest name type="string" multiple>' renders to
+  this SQL: 'name in ("Bob", "Billy")'.
+
+*optional*
+  A flag indicating if the test is optional. If
+  the test is optional and no value is provided for a variable
+  then no text is inserted. If the value is an empty string,
+  then no text will be inserted only if the type is *nb*.
+
+*op*
+  A parameter used to choose the comparison operator
+  that is rendered. The comparisons are: *eq* (equal to), *gt*
+  (greater than), *lt* (less than), *ge* (greater than or equal
+  to), *le* (less than or equal to), and  *ne* (not equal to).
+
+See `Appendix A <AppendixA.html>`_ for more information on the
+*sqltest* tag.  If your database supports additional comparison
+operators such as *like* you can use them with *sqlvar*. For
+example if *name* is the string "Mc%", the SQL code::
+
+  <dtml-sqltest name type="string" op="like">
+
+would render to::
+
+  name like 'Mc%'
+
+The *sqltest* tag helps you build correct SQL queries. In
+general your queries will be more flexible and work better with
+different types of input and different database if you use
+*sqltest* rather than hand coding comparisons.
+
+Creating Complex Queries with the *sqlgroup* Tag
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The *sqlgroup* tag lets you create SQL queries that support a
+variable number of arguments.  Based on the arguments specified, SQL
+queries can be made more specific by providing more arguments, or
+less specific by providing less or no arguments.
+
+Here is an example of an unqualified SQL query::
+
+  select * from employees
+
+Here is an example of a SQL query qualified by salary::
+
+  select * from employees
+  where(
+    salary > 100000.00
+  )
+
+Here is an example of a SQL query qualified by salary and first name::
+
+  select * from employees 
+  where(
+    salary > 100000.00
+    and
+    first in ('Jane', 'Cheetah', 'Guido')    
+  )
+
+Here is an example of a SQL query qualified by a first and a
+last name::
+
+  select * from employees 
+  where(
+    first = 'Old'
+    and
+    last = 'McDonald'     
+  )
+
+All three of these queries can be accomplished with one Z SQL
+Method that creates more specific SQL queries as more arguments
+are specified.  The following SQL template can build all three
+of the above queries::
+
+  select * from employees 
+  <dtml-sqlgroup where>
+    <dtml-sqltest salary op=gt type=float optional>
+  <dtml-and>
+    <dtml-sqltest first op="eq" type="nb" multiple optional>
+  <dtml-and>
+    <dtml-sqltest last  op="eq" type="nb" multiple optional>
+  </dtml-sqlgroup>  
+
+The *sqlgroup* tag renders the string *where* if the contents of
+the tag body contain any text and builds the qualifying
+statements into the query.  This *sqlgroup* tag will not render
+the *where* clause if no arguments are present.
+
+The *sqlgroup* tag consists of three blocks separated by *and*
+tags.  These tags insert the string *and* if the enclosing
+blocks render a value.  This way the correct number of *ands*
+are included in the query.  As more arguments are specified,
+more qualifying statements are added to the query.  In this
+example, qualifying statements restricted the search with *and*
+tags, but *or* tags can also be used to expand the search.
+
+This example also illustrates *multiple* attribute on *sqltest*
+tags.  If the value for *first* or *last* is a list, then the
+right SQL is rendered to specify a group of values instead of a
+single value.
+
+You can also nest *sqlgroup* tags.
+For example::
+
+  select * from employees
+  <dtml-sqlgroup where>
+    <dtml-sqlgroup>
+       <dtml-sqltest first op="like" type="nb">
+    <dtml-and>
+       <dtml-sqltest last op="like" type="nb">
+    </dtml-sqlgroup>
+  <dtml-or>
+    <dtml-sqltest salary op="gt" type="float">
+  </dtml-sqlgroup>
+
+Given sample arguments, this template renders to SQL like so::
+
+  select * from employees
+  where
+  ( (first like 'A%'
+     and
+     last like 'Smith'
+    )
+    or
+    salary > 20000.0
+  )
+
+You can construct very complex SQL statements with the
+*sqlgroup* tag. For simple SQL code you won't need to use the
+*sqlgroup* tag. However, if you find yourself creating a number
+of different but related Z SQL Methods you should see if you
+can't accomplish the same thing with one method that uses the
+*sqlgroup* tag.
+
+Advanced Techniques
+-------------------
+
+So far you've seen how to connect to a relational database, send
+it queries and commands, and create a user interface. These are
+the basics of relational database connectivity in Zope.
+
+In the following sections you'll see how to integrate your relational
+queries more closely with Zope and enhance performance. We'll start by
+looking at how to pass arguments to Z SQL Methods both explicitly and
+by acquisition.  Then you'll find out how you can call Z SQL Methods
+directly from URLs using traversal to result objects. Next you'll find
+out how to make results objects more powerful by binding them to 
+classes. Finally we'll look at caching to improve performance and how
+Zope handles database transactions.
+
+Calling Z SQL Methods with Explicit Arguments
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you call a Z SQL Method without argument from DTML, the arguments
+are automatically collected from the REQUEST. This is the technique 
+that we have used so far in this chapter. It works well when you want
+to query a database from a search form, but sometimes you want to 
+manually or programmatically query a database. Z SQL Methods can be
+called with explicit arguments from DTML or Python.  For example, to
+query the *employee_by_id* Z SQL Method manually, the following DTML
+can be used::
+
+  <dtml-var standard_html_header>
+
+    <dtml-in expr="employee_by_id(emp_id=42)">
+      <h1><dtml-var last>, <dtml-var first></h1>
+
+      <p><dtml-var first>'s employee id is <dtml-var emp_id>.  <dtml-var
+      first> makes <dtml-var salary> Euro per year.</p>
+    </dtml-in>
+
+  <dtml-var standard_html_footer>
+
+and the ZPT version::
+
+  <div>
+    <tal:div  tal:repeat="row python: context.employee_by_id(emp_id=42)">
+      <h1 tal:content="string: ${row/last}, ${row/first}" />
+      <p>
+       <span tal:content="string:${row/first}s employee id is ${row/emp_id}. 
+             ${row/first} makes ${row/salary} Euro per year.
+    </tal:div>
+  </div>
+
+Remember, the *employee_by_id* method returns only one record, so the
+body of the *in* tag in this method will execute only once. In the
+example you were calling the Z SQL Method like any other method and
+passing it a keyword argument for *emp_id*.  The same can be done
+easily from Python::
+
+  ## Script (Python) "join_name"
+  ##parameters=id
+  ##
+  for result in context.employee_by_id(emp_id=id):
+      return result.last + ', ' + result.first
+
+This script accepts an *id* argument and passes it to *employee_by_id*
+as the *emp_id* argument.  It then iterates over the single result and
+joins the last name and the first name with a comma.
+
+You can provide more control over your relational data by calling Z SQL
+Methods with explicit arguments. It's also worth noting that from DTML
+and Python Z SQL Methods can be called with explicit arguments just
+like you call other Zope methods.
+
+Acquiring Arguments from other Objects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Z SQL can acquire information from other objects and be used to
+modify the SQL query.  Consider the below figure, which shows a
+collection of Folders in a organization's website.
+
+.. figure:: Figures/10-7.png
+
+   Folder structure of an organizational website
+
+Suppose each department folder has a *department_id* string
+property that identifies the accounting ledger id for that
+department. This property could be used by a shared Z SQL Method to
+query information for just that department.  To illustrate,
+create various nested folders with different *department_id*
+string properties and then create a Z SQL Method with the id
+*requisition_something* in the root folder that takes four
+arguments, *department_id*, *description*, *quantity*, and *unit_cost*. and the
+following query template::
+
+  INSERT INTO requisitions 
+    (
+      department_id, description, quantity, unit_cost
+    )
+  VALUES
+    (
+      <dtml-sqlvar department_id type="string">,
+      <dtml-sqlvar description type="string">,
+      <dtml-sqlvar quantity type="int">,
+      <dtml-sqlvar unit_cost type="float">
+    )
+
+Now, create a Z Search Interface with a *Search Id* of
+"requisitionSomethingForm" and the *Report id* of
+"requisitionSomething".  Select the *requisition_something* Z
+SQL Method as the *Searchable Object* and click *Add*.
+
+Edit the *requisitionSomethingForm* and remove the first input box for
+the *department_id* field.  We don't want the value of *department_id*
+to come from the form, we want it to come from a property that is
+acquired.
+
+Now, you should be able to go to a URL like::
+
+  http://example.org/Departments/Support/requisitionSomethingForm
+
+and requisition some punching bags for the Support department.
+Alternatively, you could go to::
+
+  http://example.org/Departments/Sales/requisitionSomethingForm
+
+and requisition some tacky rubber key-chains with your logo on
+them for the Sales department.  Using Zope's security system as
+described in the chapter entitled `Users and
+Security <Security.html>`_, you can now restrict access to these forms
+so personnel from departments can requisition items just for their
+department and not any other.
+
+The interesting thing about this example is that *department_id*
+was not one of the arguments provided to the query.  Instead of
+obtaining the value of this variable from an argument, it
+*acquires* the value from the folder where the Z SQL Method is
+accessed.  In the case of the above URLs, the
+*requisition_something* Z SQL Method acquires the value from the
+*Sales* and *Support* folders. This allows you to tailor SQL
+queries for different purposes. All the departments can share a
+query but it is customized for each department.
+
+By using acquisition and explicit argument passing you can
+tailor your SQL queries to your web application.
+
+Traversing to Result Objects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+So far you've provided arguments to Z SQL Methods from web forms,
+explicit argument, and acquisition.  You can also provide
+arguments to Z SQL Methods by calling them from the web with
+special URLs. This is called *traversing* to results
+objects. Using this technique you can "walk directly up to" result
+objects using URLs.
+
+In order to traverse to result objects with URLs, you must be
+able to ensure that the SQL Method will return only one result
+object given one argument.  For example, create a new Z SQL Method
+named *employee_by_id*, with *emp_id* in the 'Arguments' field and the
+following in the SQL Template::
+
+  select * from employees where
+    <dtml-sqltest emp_id op="eq" type="int">
+
+This method selects one employee out of the *employees* table based on
+their employee id.  Since each employee has a unique id, only one
+record will be returned. Relational databases can provide these kinds
+of uniqueness guarantees.
+
+Zope provides a special URL syntax to access ZSQL Methods that always
+return a single result. The URL consists of the URL of the ZSQL Method
+followed by the argument name followed by the argument value. For
+example, *http://localhost:8080/employee_by_id/emp_id/42*. Note, this 
+URL will return a single result object as if you queried the ZSQL
+Method from DTML and passed it a single argument it would return
+a list of results that happend to only have one item in it.
+
+Unfortunately the result object you get with this URL is not
+very interesting to look at. It has no way to display itself in
+HTML. You still need to display the result object.  To do this,
+you can call a DTML Method on the result object.  This can be
+done using the normal URL acquisition rules described in Chapter
+10, "Advanced Zope Scripting".  For example, consider the
+following URL::
+
+  http://localhost:8080/employee_by_id/emp_id/42/viewEmployee
+
+Here we see the *employee_by_id* Z SQL Method being passed the *emp_id*
+argument by URL. The *viewEmployee* method is then called on the
+result object. Let's create a *viewEmployee* DTML Method and try
+it out. Create a new DTML Method named *viewEmployee* and give
+it the following content::
+
+  <dtml-var standard_html_header>
+
+    <h1><dtml-var last>, <dtml-var first></h1>
+
+    <p><dtml-var first>'s employee id is <dtml-var emp_id>.  <dtml-var
+    first> makes <dtml-var salary fmt="dollars-and-cents"> per year.</p>
+
+  <dtml-var standard_html_footer>
+
+Now when you go to the URL
+*http://localhost:8080/employee_by_id/emp_id/42/viewEmployee*
+the *viewEmployee* DTML Method is bound the result object that
+is returned by *employee_by_id*.  The *viewEmployee* method can
+be used as a generic template used by many different Z SQL
+Methods that all return employee records.
+
+Since the *employee_by_id* method only accepts one argument, it
+isn't even necessary to specify *emp_id* in the URL to qualify
+the numeric argument.  If your Z SQL Method has one argument,
+then you can configure the Z SQL Method to accept only one extra
+path element argument instead of a pair of arguments.  This
+example can be simplified even more by selecting the
+*employee_by_id* Z SQL Method and clicking on the *Advanced*
+tab.  Here, you can see a check box called *Allow "Simple" Direct
+Traversal*.  Check this box and click *Change*.  Now, you can
+browse employee records with simpler URLs like
+*http://localhost:8080/employee_by_id/42/viewEmployee*.  Notice
+how no *emp_id* qualifier is declared in the URL.
+
+Traversal gives you an easy way to provide arguments and bind
+methods to Z SQL Methods and their results.  Next we'll show you
+how to bind whole classes to result objects to make them even
+more powerful.
+
+Other Result Object Methods
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Up to now we have just been iterating through the attributes of
+the Result object in DTML. The result object does however provide
+other methods which can be easier in some situations. These
+methods can be accessed from Scripts (Python) and page templates.
+For example in Python we could write::
+
+  result=context.list_all_employees()
+  return len(result)
+
+and in ZPT::
+
+  <span tal:content="python: len(list_all_employees())" />
+
+
+Assuming that we have set 'result' to being a result object we can
+use the following methods:
+
+'len(result)'
+  this will show the number rows returned (which would be 3 in the example
+  above).
+
+'result.names()'
+  a list of all the column headings, returning a list containing 'emp_id',
+  'first', 'last' and 'salary'
+
+'result.tuples()'
+  returns a list of tuples in our example::
+
+      [(43, 'Bob', 'Roberts', 50000),
+       (101, 'Cheeta', 'leCat', 100000),
+       (99, 'Jane', 'Junglewoman', 100001)]
+
+'result.dictionaries()'
+  will return a list of dictionaries, with one dictionary for each row::
+
+        [{'emp_id': 42, 'first': 'Bob','last': 'Roberts', 'salary': 50000},
+         {'emp_id': 101, 'first: 'Cheeta', 'last': 'leCat', 'salary': 100000},
+         {'emp_id': 99, 'first': 'Jane', 'last': 'Junglewoman', 'salary': 100001}]
+
+'result.data_dictionary()'
+  returns a dictionary describing the structure of the results table. The
+  dictionary has the key 'name', 'type', 'null' and 'width'. Name and type
+  are self explanatory, 'null' is true if that field may contain a null
+  value and width is the width in characters of the field. Note that 'null'
+  and 'width' may not be set by some Database Adapters.
+
+'result.asRDB()'
+  displays the result in a similar way to a relational database. The DTML
+  below displays the result below::
+
+    <pre>
+      <dtml-var "list_all_employees().asRDB()">
+    </pre>
+
+    ... displays ...
+
+    emp_id first last salary
+    42 Bob Roberts 50000
+    101 Cheeta leCat 100000
+    99 Jane Junglewoman 100001
+
+'result[0][1]'
+  return row 0, column 1 of the result, 'bob' in this example. Be careful
+  using this method as changes in the schema will cause unexpected results.
+
+Binding Classes to Result Objects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A Result object has an attribute for each column in a results row.
+As we have seen there are some basic methods for processing these
+attributes to produce some more useful output. However we can go
+further by writing our own custom methods and adding them into the
+Result object.
+
+There are two ways to bind a method to a Result object.  As you
+saw previously, you can bind DTML and other methods to Z SQL
+Method Result objects using traversal to the results object
+coupled with the normal URL based acquisition binding mechanism
+described in the chapter entitled `Advanced Zope
+Scripting <ScriptingZope.html>`_.  You can also bind methods to Result
+objects by defining a Python class that gets *mixed in* with the
+normal, simple Result object class.  These classes are defined in
+the same location as External Methods in the filesystem, in Zope's
+*Extensions* directory.  Python classes are collections of methods
+and attributes.  By associating a class with a Result object, you
+can make the Result object have a rich API and user interface.
+
+Classes used to bind methods and other class attributes to
+Result classes are called *Pluggable Brains*, or just *Brains*.
+Consider the example Python class::
+
+  class Employee:
+
+    def fullName(self):
+      """ The full name in the form 'John Doe' """
+      return self.first + ' ' + self.last
+
+When result objects with this Brains class are created as the
+result of a Z SQL Method query, the Results objects will have
+*Employee* as a base class. This means that the record objects
+will have all the methods defined in the *Employee* class,
+giving them behavior, as well as data.
+
+To use this class, create the above class in the *Employee.py*
+file in the *Extensions* directory. Go the *Advanced* tab of the
+*employee_by_id* Z SQL Method and enter *Employee* in the *Class
+Name* field, and *Employee* in the *Class File* field and click
+*Save Changes*.  Now you can edit the *viewEmployee* DTML Method
+to contain::
+
+  <dtml-var standard_html_header>
+
+    <h1><dtml-var fullName></h1>
+
+    <p><dtml-var first>'s employee id is <dtml-var emp_id>.  <dtml-var
+    first> makes <dtml-var salary fmt="dollars-and-cents"> per year.</p>
+
+  <dtml-var standard_html_footer>
+
+Now when you go to the URL
+*http://localhost:8080/employee_by_id/42/viewEmployee* the
+*fullName* method is called by the *viewEmployee* DTML Method.
+The *fullName* method is defined in the *Employee* class of the
+*Employee* module and is bound to the result object returned by
+*employee_by_id*
+
+*Brains* provide a very powerful facility which allows you to
+treat your relational data in a more object-centric way. For
+example, not only can you access the *fullName* method using
+direct traversal, but you can use it anywhere you handle result
+objects. For example::
+
+  <dtml-in employee_by_id>
+    <dtml-var fullName>
+  </dtml-in>
+
+For all practical purposes your Z SQL Method returns a sequence
+of smart objects, not just data.
+
+This example only "scratches the surface" of what can be done with
+Brains classes. With a bit of Python, you could create brains
+classes that accessed network resources, called other Z SQL
+Methods, or performed all kinds of business logic.  Since advanced
+Python programming is not within the scope of this book, we
+regrettably cannot provide a great number of examples of this sort
+of functionality, but we will at least provide one below.
+
+Here's a more powerful example of brains. Suppose that you have
+an *managers* table to go with the *employees* table that you've
+used so far. Suppose also that you have a *manager_by_id* Z SQL
+Method that returns a manager id manager given an *emp_id* argument::
+
+  select manager_id from managers where
+    <dtml-sqltest emp_id type="int" op="eq">        
+
+You could use this Z SQL Method in your brains class like so::
+
+  class Employee:
+
+      def manager(self):
+          """
+          Returns this employee's manager or None if the
+          employee does not have a manager.
+          """
+          # Calls the manager_by_id Z SQL Method.
+          records=self.manager_by_id(emp_id=self.emp_id)
+          if records:
+              manager_id=records[0].manager_id
+              # Return an employee object by calling the
+              # employee_by_id Z SQL Method with the manager's emp_id
+              return self.employee_by_id(emp_id=manager_id)[0]
+
+This 'Employee' class shows how methods can use other Zope
+objects to weave together relational data to make it seem like a
+collection of objects. The 'manager' method calls two Z SQL
+Methods, one to figure out the emp_id of the employee's manager,
+and another to return a new Result object representing the
+manager. You can now treat employee objects as though they have
+simple references to their manager objects. For example you
+could add something like this to the *viewEmployee* DTML Method::
+
+  <dtml-if manager>
+    <dtml-with manager>
+      <p> My manager is <dtml-var first> <dtml-var last>.</p>
+    </dtml-with>
+  </dtml-if>
+
+As you can see brains can be both complex and powerful. When
+designing relational database applications you should try to
+keep things simple and add complexity slowly. It's important to make
+sure that your brains classes don't add lots of unneeded overhead. 
+
+Caching Results
+~~~~~~~~~~~~~~~
+
+You can increase the performance of your SQL queries with
+caching. Caching stores Z SQL Method results so that if you call
+the same method with the same arguments frequently, you won't
+have to connect to the database every time. Depending on your
+application, caching can dramatically improve performance.
+
+To control caching, go to the *Advanced* tab of a SQL Method. You have
+three different cache controls as shown in the figure below.
+
+.. figure:: Figures/10-8.png
+
+   Caching controls for Z SQL Methods
+
+The *Maximum number of rows received* field controls how much
+data to cache for each query. The *Maximum number of results to
+cache* field controls how many queries to cache. The *Maximum
+time (in seconds) to cache results* controls how long cached
+queries are saved for.  In general, the larger you set these
+values the greater your performance increase, but the more
+memory Zope will consume. As with any performance tuning, you
+should experiment to find the optimum settings for your application.
+
+In general you will want to set the maximum results to cache to
+just high enough and the maximum time to cache to be just long
+enough for your application. For site with few hits you should
+cache results for longer, and for sites with lots of hits you
+should cache results for a shorter period of time. For machines
+with lots of memory you should increase the number of cached
+results. To disable caching set the cache time to zero
+seconds. For most queries, the default value of 1000 for the
+maximum number of rows retrieved will be adequate. For extremely
+large queries you may have to increase this number in order to
+retrieve all your results.
+
+Transactions
+~~~~~~~~~~~~
+
+A transaction is a group of operations that can be undone all at
+once.  As was mentioned in the chapter entitled `Zope Concepts and
+Architecture <ZopeArchitecture.html>`_, all changes done to Zope are
+done within transactions.  Transactions ensure data integrity.
+When using a system that is not transactional and one of your web
+actions changes ten objects, and then fails to change the
+eleventh, then your data is now inconsistent.  Transactions allow
+you to revert all the changes you made during a request if an
+error occurs.
+
+Imagine the case where you have a web page that bills a customer
+for goods received.  This page first deducts the goods from the
+inventory, and then deducts the amount from the customers
+account.  If the second operation fails for some reason you
+want to make sure the change to the inventory doesn't take effect.
+
+Most commercial and open source relational databases support
+transactions. If your relational database supports transactions,
+Zope will make sure that they are tied to Zope transactions. This
+ensures data integrity across both Zope and your relational
+database.
+
+In our example, the transaction would start with the customer
+submitting the form from the web page and would end when the page
+is displayed. It is guaranteed that operations in this transaction
+are either all performed or none are performed even if these
+operations use a mix of Zope Object Database and external
+relational database.
+
+Further help
+------------
+
+The zope-db at zope.org is the place to ask questions about relational
+databases. You can subscribe or browse the archive of previous postings
+at http://mail.zope.org/mailman/listinfo/zope-db
+
+Summary
+-------
+
+Zope allows you to build web applications with relational
+databases. Unlike many web application servers, Zope has its own
+object database and does not require the use of relational
+databases to store information.
+
+Zope lets you use relational data just like you use other Zope
+objects. You can connect your relational data to business logic
+with scripts and brains, you can query your relational data with Z
+SQL Methods and presentation tools like DTML, and your can even
+use advanced Zope features like URL traversal, acquisition, undo
+and security while working with relational data.

Copied: zope2docs/branches/baijum-reorganize/zope2book/ScriptingZope.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/ScriptingZope.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/ScriptingZope.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/ScriptingZope.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,926 @@
+Advanced Zope Scripting
+=======================
+
+In the chapter entitled "Basic Zope Scripting", you have seen
+how to manage Zope objects programmatically.  In this chapter,
+we will explore this topic some more.  Subjects discussed
+include additional scripting objects, script security, and
+calling script objects from presentation objects like Page
+Templates.  As we have mentioned before,
+separation of logic and presentation is a key factor in
+implementing maintainable web applications.
+
+What is *logic* and how does it differ from presentation? Logic
+provides those actions which change objects, send messages, test
+conditions and respond to events, whereas presentation formats and
+displays information and reports. Typically you will use
+Page Templates to handle presentation, and Zope scripting to
+handle logic.
+
+Warning
+-------
+
+Zope *Script* objects are objects that encapsulate a small chunk of code
+written in a programming language. They first appeared in Zope 2.3, and have
+been the preferred way to write programming logic in Zope for many years. Today
+it is discouraged to use Scripts for any but the most minimal logic. If you
+want to create more than trivial logic, you should approach this by creating a
+Python package and write your logic *on the file system*.
+
+This book does not cover this development approach in its details. This
+chapter is still useful to read, as it allows you to get an understanding on
+some of the more advanced techniques and features of Zope.
+
+Calling Scripts
+---------------
+
+In the "Basic Zope Scripting" chapter, you learned how to call scripts from the
+web and, conversely, how to call Page Templates from Python-based Scripts. In
+fact scripts can call scripts which call other scripts, and so on.
+
+Calling Scripts from Other Objects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can call scripts from other objects, whether they are
+Page Templates or Scripts (Python). The
+semantics of each language differ slightly, but the same rules
+of acquisition apply. You do not necessarily have to know what
+language is used in the script you are calling; you only need to
+pass it any parameters that it requires, if any.
+
+Calling Scripts from Page Templates 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Calling scripts from Page Templates is much like calling them
+by URL or from Python. Just use standard TALES path
+expressions as described in the chapter entitled "Using Zope
+Page Templates.":ZPT.html>`_  For example::
+
+  <div tal:replace="context/hippo/feed">
+    Output of feed()
+  </div>
+
+The inserted value will be HTML-quoted. You can disable
+quoting by using the *structure* keyword, as described in
+the chapter entitled `Advanced Page Templates <AdvZPT.html>`_
+
+To call a script without inserting a value in the
+page, you can use *define* and ignore the variable assigned::
+
+  <div tal:define="dummy context/hippo/feed" />
+
+In a page template, *context* refers to the current context.  It
+behaves much like the *context* variable in a Python-based
+Script.  In other words, *hippo* and *feed* will both be
+looked up by acquisition.
+
+If the script you call requires arguments, you must use a 
+TALES python expression in your template, like so::
+
+  <div tal:replace="python:context.hippo.feed(food='spam')">
+    Output of feed(food='spam')
+  </div>
+
+Just as in Path Expressions, the 'context' variable refers to the
+acquisition context the Page Template is called in.  
+
+The python expression above is exactly like a line of
+code you might write in a Script (Python).
+
+One difference is the notation used for attribute access --
+Script (Python) uses the standard Python period notation,
+whereas in a TALES path expression, a forward slash is
+used.
+
+For further reading on using Scripts in Page Templates, refer
+to the chapter entitled `Advanced Page Templates`_.
+
+Calling scripts from Python
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Calling scripts from other scripts works similar to calling
+scripts from page templates, except that you must
+*always* use explicit calling (by using
+parentheses). For example, here is how you might call
+the *updateInfo* script from Python::
+
+  new_color='brown'
+  context.updateInfo(color=new_color, 
+                     pattern="spotted")
+
+Note the use of the *context* variable to tell Zope to find
+updateInfo by acquisition. 
+
+Zope locates the scripts you call by using acquisition the
+same way it does when calling scripts from the web.  Returning
+to our hippo feeding example of the last section, let's see
+how to vaccinate a hippo from Python. The figure
+below shows a slightly updated object hierarchy that contains
+a script named *vaccinateHippo.py*. 
+
+.. figure:: Figures/zoo-again.png 
+
+   A collection of objects and scripts
+
+Here is how you can call the *vaccinate* script on the
+*hippo* obect from the *vaccinateHippo.py* script::
+
+  context.Vet.LargeAnimals.hippo.vaccinate()
+
+In other words, you simply access the object by using the same
+acquisition path as you would use if you called it from the
+web. The result is the same as if you visited the URL
+*Zoo/Vet/LargeAnimals/hippo/vaccinate*. Note that in this Python
+example, we do not bother to specify *Zoo* before *Vet*. We can
+leave *Zoo* out because all of the objects involved, including
+the script, are in the Zoo folder, so it is implicitly part
+of the acquisition chain.
+
+Calling Scripts: Summary and Comparison
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Let's recap the ways to call a hypothetical *updateInfo* script on a *foo*
+object, with argument passing: from your web browser, from Python and from Page
+Templates.
+
+- by URL::
+
+   http://my-zope-server.com:8080/foo/updateInfo?amount=lots
+
+- from a Script (Python)::
+
+   context.foo.updateInfo(amount="lots")
+
+- from a Page Template::
+
+   <span tal:content="context/foo/updateInfo" />
+
+- from a Page Template, with arguments::
+
+   <span tal:content="python:context.foo.updateInfo(amount='lots')" />
+
+Regardless of the language used, this is a very common idiom
+to find an object, be it a script or any other kind of object:
+you ask the context for it, and if it exists in this context
+or can be acquired from it, it will be used.
+
+Zope will throw a *KeyError* exception if the script you are
+calling cannot be acquired. If you are not certain that a
+given script exists in the current context, or if you want to
+compute the script name at run-time, you can use this Python
+idiom::
+
+  updateInfo = getattr(context, "updateInfo", None)
+  if updateInfo is not None:
+      updateInfo(color="brown", pattern="spotted")
+  else:
+      # complain about missing script
+      return "error: updateInfo() not found"
+
+The *getattr* function is a Python built-in. The first
+argument specifies an object, the second an attribute
+name.  The *getattr* function will return the named
+attribute, or the third argument if the attribute cannot be
+found. So in the next statement we just have to test whether
+the *updateInfo* variable is None, and if not, we know we can
+call it.
+
+Advanced Acquisition 
+--------------------
+
+In the chapter entitled "Acquisition":Acquisition.html>`_ , we
+introduced acquisition by containment, which we have been using
+throughout this chapter. In acquisition by containment, Zope
+looks for an object by going back up the containment hierarchy
+until it finds an object with the right id. In Chapter 7 we also
+mentioned *context acquisition*, and warned that it is a tricky
+subject capable of causing your brain to explode. If you are
+ready for exploding brains, read on.
+
+The most important thing for you to understand in this chapter is
+that context acquisition exists and can interfere with whatever
+you are doing. Today it is seen as a fragile and complex topic and
+rarely ever used in practice.
+
+Recall our Zoo example introduced earlier in this chapter.
+
+.. figure:: Figures/zoo.png 
+
+   Zope Zoo Example hierarchy
+
+We have seen how Zope uses URL traversal and acquisition to find
+objects  in  higher containers.  More  complex arrangements  are
+possible. Suppose you want to call the *vaccinate* script on the
+*hippo*  object. What  URL can  you use?  If you  visit  the URL
+*Zoo/LargeAnimals/hippo/vaccinate* Zope will not be able to find
+the  *vaccinate* script  since it  isn't in  any of  the *hippo*
+object's containers.
+
+The solution is to give the path to the script as part of the
+URL. Zope allows you to combine two or more URLs into one in
+order to provide more acquisition context! By using acquisition,
+Zope will find the script as it backtracks along the URL. The
+URL to vaccinate the hippo is
+*Zoo/Vet/LargeAnimals/hippo/vaccinate*. Likewise, if you want to
+call the *vaccinate* script on the *kargarooMouse* object you
+should use the URL
+*Zoo/Vet/SmallAnimals/kargarooMouse/vaccinate*.
+
+Let's follow along as Zope traverses the URL
+*Zoo/Vet/LargeAnimals/hippo/vaccinate*. Zope starts in the root
+folder and looks for an object named *Zoo*. It moves to the
+*Zoo* folder and looks for an object named *Vet*. It moves to
+the *Vet* folder and looks for an object named
+*LargeAnimals*. The *Vet* folder does not contain an object with
+that name, but it can acquire the *LargeAnimals* folder from its
+container, *Zoo* folder. So it moves to the *LargeAnimals*
+folder and looks for an object named *hippo*.  It then moves to
+the *hippo* object and looks for an object named
+*vaccinate*. Since the *hippo* object does not contain a
+*vaccinate* object and neither do any of its containers, Zope
+backtracks along the URL path trying to find a *vaccinate*
+object. First it backs up to the *LargeAnimals* folder where
+*vaccinate* still cannot be found. Then it backs up to the *Vet*
+folder.  Here it finds a *vaccinate* script in the *Vet*
+folder. Since Zope has now come to the end of the URL, it calls
+the *vaccinate* script in the context of the *hippo* object.
+
+Note that we could also have organized the URL a bit
+differently. *Zoo/LargeAnimals/Vet/hippo/vaccinate* would also
+work. The difference is the order in which the context elements
+are searched. In this example, we only need to get *vaccinate*
+from *Vet*, so all that matters is that *Vet* appears in the URL
+after *Zoo* and before *hippo*.
+
+When Zope looks for a sub-object during URL traversal, it first
+looks for the sub-object in the current object. If it cannot
+find it in the current object it looks in the current object's
+containers. If it still cannot find the sub-object, it backs up
+along the URL path and searches again. It continues this process
+until it either finds the object or raises an error if it cannot
+be found. If several context folders are used in the URL, they
+will be searched in order from *left to right*.
+
+Context acquisition can be a very useful mechanism, and it
+allows you to be quite expressive when you compose URLs. The
+path you tell Zope to take on its way to an object will
+determine how it uses acquisition to look up the object's
+scripts.
+
+Note that not all scripts will behave differently depending on
+the traversed URL. For example, you might want your script to
+acquire names only from its parent containers and not from the
+URL context. To do so, simply use the *container* variable
+instead of the *context* variable in the script, as described
+above in the section "Using Python-based Scripts."
+
+Context Acquisition Gotchas
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Containment before context
+%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+It is important to realize that context acquisition
+*supplements* container acquisition. It does not *override*
+container acquisition.
+
+One at a time
+%%%%%%%%%%%%%
+
+Another point that often confuses new users is that each element
+of a path "sticks" for the duration of the traversal, once it is
+found. Think of it this way: objects are looked up one at a
+time, and once an object is found, it will not be looked up
+again.  For example, imagine this folder structure:
+
+.. figure:: Figures/acquisition.png
+
+   Acquisition example folder structure
+
+Now suppose that the *about_penguins* page contains a link to
+*Images/penguins.png*. Shouldn't this work? Won't
+*/Images/penguins.png* succeed when
+*/Content/Images/penguins.png* fails?  The answer is no. We
+always traverse from left to right, one item at a time. 
+First we find *Content*, then *Images* within it; *penguins.png* 
+appears in neither of those, and we haved searched all 
+parent containers of every element in the URL, so 
+there is nothing more to search in this URL.
+Zope stops there and raises an error. Zope never looks in */Images*
+because it has already found */Content/Images*.
+
+Readability
+%%%%%%%%%%%
+
+Context acquisition can make code more difficult to
+understand. A person reading your script can no longer simply
+look backwards up one containment hierarchy to see where an
+acquired object might be; many more places might be searched,
+all over the zope tree folder. And the order in which objects
+are searched, though it is consistent, can be confusing.
+
+Fragility
+%%%%%%%%%
+
+Over-use of context acquisition can also lead to fragility. In
+object-oriented terms, context acquisition can lead to a site
+with low cohesion and tight coupling. This is generally regarded
+as a bad thing. More specifically, there are many simple actions
+by which an unwitting developer could break scripts that rely on
+context acquisition. These are more likely to occur than with
+container acquisition, because potentially every part of your
+site affects every other part, even in parallel folder branches.
+
+For example, if you write a script that calls another script by
+a long and torturous path, you are assuming that the folder tree
+is not going to change. A maintenance decision to reorganize the
+folder hierarchy could require an audit of scripts in *every*
+part of the site to determine whether the reorganization will
+break anything. 
+
+Recall our Zoo example. There are several ways in which a zope
+maintainer could break the feed() script:
+
+Inserting another object with the name of the method
+  This is a normal technique for customizing behavior in Zope, but context
+  acquisition makes it more likely to happen by accident. Suppose that
+  giraffe vaccination is controlled by a regularly scheduled script that
+  calls *Zoo/Vet/LargeAnimals/giraffe/feed*. Suppose a content
+  administrator doesn't know about this script and adds a DTML page called
+  *vaccinate* in the giraffe folder, containing information about
+  vaccinating giraffes. This new *vaccinate* object will be acquired before
+  *Zoo/Vet/vaccinate*.  Hopefully you will notice the problem before your
+  giraffes get sick.
+
+Calling an inappropriate path
+  if you visit *Zoo/LargeAnimals/hippo/buildings/visitor_reception/feed*,
+  will the reception area be filled with hippo food?  One would hope not.
+  This might even be possible for someone who has no permissions on the
+  reception object. Such URLs are actually not difficult to construct. For
+  example, using relative URLs in standard_html_header can lead to some
+  quite long combinations of paths.
+
+Thanks to Toby Dickenson for pointing out these fragility issues
+on the zope-dev mailing list.
+
+
+Passing Parameters to Scripts
+-----------------------------
+
+All scripts can be passed parameters. A parameter gives a script
+more information about what to do. When you call a script from the
+web, Zope will try to find the script's parameters in the web
+request and pass them to your script. For example, if you have a
+script with parameters *dolphin* and *REQUEST* Zope will
+look for *dolphin* in the web request, and will pass the request
+itself as the *REQUEST* parameter. In practical terms this means
+that it is easy to do form processing in your script. For example,
+here is a form::
+
+  <form action="form_action">
+    Name of Hippo <input type="text" name="name" /><br />
+    Age of Hippo <input type="text" name="age" /><br />
+    <input type="submit" />
+  </form>
+
+You can easily process this form with a script named
+*form_action* that includes *name* and *age* in its parameter
+list::
+
+  ## Script (Python) "form_action"
+  ##parameters=name, age
+  ##
+  "Process form"
+  age=int(age)
+  message= 'This hippo is called %s and is %d years old' % (name, age)
+  if age < 18:
+      message += '\n %s is not old enough to drive!' % name
+  return message
+
+There is no need to process the form manually to extract values
+from it. Form elements are passed as strings, or lists of
+strings in the case of checkboxes and multiple-select input.
+
+In addition to form variables, you can specify any request
+variables as script parameters. For example, to get access to the
+request and response objects just include 'REQUEST' and 'RESPONSE'
+in your list of parameters. Request variables are detailed more
+fully in `Appendix B: API Reference <AppendixB.html>`_ .
+
+In the Script (Python) given above, there is a subtle problem. You
+are probably expecting an integer rather than a string for age,
+but all form variables are passed as strings.  You could
+manually convert the string to an integer using the Python *int*
+built-in::
+
+  age = int(age)
+
+But this manual conversion may be inconvenient. Zope provides a
+way for you to specify form input types in the form, rather than
+in the processing script. Instead of converting the *age* variable
+to an integer in the processing script, you can indicate that it
+is an integer in the form itself::
+
+  Age <input type="text" name="age:int" />
+
+The ':int' appended to the form input name tells Zope to
+automatically convert the form input to an integer. This
+process is called *marshalling*. If the user of
+your form types something that cannot be converted to an integer
+(such as "22 going on 23") then Zope will raise an exception as
+shown in the figure below.
+
+.. figure:: Figures/8-3.png
+
+   Parameter conversion error
+
+It's handy to have Zope catch conversion errors, but you may not
+like Zope's error messages. You should avoid using Zope's
+converters if you want to provide your own error messages.
+
+Zope can perform many parameter conversions. Here is a list of Zope's
+basic parameter converters.
+
+*boolean*
+  Converts a variable to true or false. Variables
+  that are 0, None, an empty string, or an empty sequence are
+  false, all others are true.
+
+*int*
+  Converts a variable to an integer.
+
+*long*
+  Converts a variable to a long integer.
+
+*float*
+  Converts a variable to a floating point number.
+
+*string*
+  Converts a variable to a string. Most variables
+  are strings already so this converter is seldom used.
+
+*text*
+  Converts a variable to a string with normalized line
+  breaks.  Different browsers on various platforms encode line
+  endings differently, so this script makes sure the line endings are
+  consistent, regardless of how they were encoded by the browser.
+
+*list*
+  Converts a variable to a Python list.
+
+*tuple*
+  Converts a variable to a Python tuple. A tuple is
+  like a list, but cannot be modified.
+
+*tokens*
+  Converts a string to a list by breaking it on white
+  spaces.
+
+*lines*
+  Converts a string to a list by breaking it on new
+  lines.
+
+*date*
+  Converts a string to a *DateTime* object. The formats
+  accepted are fairly flexible, for example '10/16/2000',
+  '12:01:13 pm'.
+
+*required*
+  Raises an exception if the variable is not present.
+
+*ignore_empty*
+  Excludes the variable from the request if
+  the variable is an empty string.
+
+These converters all work in more or less the same way to coerce
+a form variable, which is a string, into another specific
+type. You may recognize these converters from the chapter
+entitled Using Basic Zope Objects , in which we
+discussed properties. These converters are used by Zope's
+property facility to convert properties to the right type.
+
+The *list* and *tuple* converters can be used in combination with other
+converters.  This allows you to apply additional converters to each
+element of the list or tuple.  Consider this form::
+
+  <form action="processTimes"> 
+
+    <p>I would prefer not to be disturbed at the following
+    times:</p>
+
+    <input type="checkbox" name="disturb_times:list:date"
+    value="12:00 AM" /> Midnight<br />
+
+    <input type="checkbox" name="disturb_times:list:date"
+    value="01:00 AM" /> 1:00 AM<br />
+
+    <input type="checkbox" name="disturb_times:list:date"
+    value="02:00 AM" /> 2:00 AM<br />
+
+    <input type="checkbox" name="disturb_times:list:date"
+    value="03:00 AM" /> 3:00 AM<br />
+
+    <input type="checkbox" name="disturb_times:list:date"
+    value="04:00 AM" /> 4:00 AM<br />
+
+    <input type="submit" />
+  </form>
+
+By using the *list* and *date* converters together, Zope will
+convert each selected time to a date and then combine all selected
+dates into a list named *disturb_times*.
+
+A more complex type of form conversion is to convert a series of inputs
+into *records.* Records are structures that have attributes. Using
+records, you can combine a number of form inputs into one variable with
+attributes.  The available record converters are:
+
+*record*
+  Converts a variable to a record attribute.
+
+*records*
+  Converts a variable to a record attribute in a list of
+  records.
+
+*default*
+  Provides a default value for a record attribute if the
+  variable is empty.
+
+*ignore_empty*
+  Skips a record attribute if the variable is empty.
+
+Here are some examples of how these converters are used::
+
+  <form action="processPerson">
+
+    First Name <input type="text" name="person.fname:record" /><br />
+    Last Name <input type="text" name="person.lname:record" /><br />
+    Age <input type="text" name="person.age:record:int" /><br />
+
+    <input type="submit" />
+  </form>
+
+This form will call the *processPerson* script with one
+parameter, *person*. The *person* variable will have the attributes
+*fname*, *lname* and *age*. Here's an example of how you might
+use the *person* variable in your *processPerson* script::
+
+  ## Script (Python) "processPerson"
+  ##parameters=person
+  ##
+  "Process a person record"
+  full_name="%s %s" % (person.fname, person.lname)
+  if person.age < 21:
+      return "Sorry, %s. You are not old enough to adopt an aardvark." % full_name
+  return "Thanks, %s. Your aardvark is on its way." % full_name
+
+The *records* converter works like the *record* converter except
+that it produces a list of records, rather than just one. Here is
+an example form::
+
+  <form action="processPeople">
+
+    <p>Please, enter information about one or more of your next of
+    kin.</p>
+
+    <p>
+      First Name <input type="text" name="people.fname:records" />
+      Last Name <input type="text" name="people.lname:records" />
+    </p>
+
+    <p>
+      First Name <input type="text" name="people.fname:records" />
+      Last Name <input type="text" name="people.lname:records" />
+    </p>
+
+    <p>
+      First Name <input type="text" name="people.fname:records" />
+      Last Name <input type="text" name="people.lname:records" />
+    </p>
+
+    <input type="submit" />
+  </form>    
+
+This form will call the *processPeople* script with a variable
+called *people* that is a list of records. Each record will have
+*fname* and *lname* attributes.  Note the difference between the
+*records* converter and the *list:record* converter: the former
+would create a list of records, whereas the latter would produce
+a single record whose attributes *fname* and *lname* would each
+be a list of values.
+
+The order of combined modifiers does not matter; for example,
+*int:list* is identical to *list:int*.
+
+Another useful parameter conversion uses form variables to
+rewrite the action of the form. This allows you to submit a form
+to different scripts depending on how the form is filled
+out. This is most useful in the case of a form with multiple
+submit buttons. Zope's action converters are:
+
+*action*
+  Appends the attribute value to the original form
+  action of the form. This is mostly useful for the case in
+  which you have multiple submit buttons on one form.  Each
+  button can be assigned to a script that gets called when that
+  button is clicked to submit the form. A synonym for *action*
+  is *method*.
+
+*default_action*
+  Appends the attribute value to the
+  original action of the form when no other *action* converter
+  is used.
+
+Here's an example form that uses action converters::
+
+  <form action="employeeHandlers">
+
+    <p>Select one or more employees</p>
+
+    <input type="checkbox" name="employees:list" value="Larry" /> Larry<br />
+    <input type="checkbox" name="employees:list" value="Simon" /> Simon<br />
+    <input type="checkbox" name="employees:list" value="Rene" /> Rene<br />
+
+    <input type="submit" name="fireEmployees:action" value="Fire!" /><br />
+
+    <input type="submit" name="promoteEmployees:action" value="Promote!" />
+
+  </form>
+
+We assume a folder 'employeeHandlers' containing two
+scripts named 'fireEmployees' and 'promoteEmployees'.  The
+form will call either the *fireEmployees* or the
+*promoteEmployees* script, depending on which of the two
+submit buttons is used.  Notice also how it builds a list
+of employees with the *list* converter.  Form converters
+can be very useful when designing Zope applications.
+
+Script Security
+---------------
+
+All scripts that can be edited through the web are subject to
+Zope's standard security policies. The only scripts that are not
+subject to these security restrictions are scripts that must be
+edited through the filesystem.
+
+The chapter entitled `Users and Security <Security.html>`_ covers
+security in more detail. You should consult the *Roles of
+Executable Objects* and *Proxy Roles* sections for more
+information on how scripts are restricted by Zope security
+constraints.
+
+Security Restrictions of Script (Python)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Scripts are restricted in order to limit their ability
+to do harm. What could be harmful? In general, scripts
+keep you from accessing private Zope objects, making harmful
+changes to Zope objects, hurting the Zope process itself, and
+accessing the server Zope is running on. These restrictions
+are implemented through a collection of limits on what your
+scripts can do.
+
+Loop limits
+  Scripts cannot create infinite loops. If your script
+  loops a very large number of times Zope will raise an error. This
+  restriction covers all kinds of loops including *for* and *while*
+  loops. The reason for this restriction is to limit your ability to
+  hang Zope by creating an infinite loop.
+
+Import limits
+  Scripts cannot import arbitrary
+  packages and modules. You are limited to importing the
+  *Products.PythonScripts.standard* utility module, the
+  *AccessControl* module, some helper modules
+  (*string*, *random*, *math*, *sequence*), and modules
+  which have been specifically made available to scripts
+  by product authors.  See `Appendix B: API Reference`_
+  for more information on these
+  modules.
+
+Access limits
+  You are restricted by standard Zope
+  security policies when accessing objects. In other words
+  the user executing the script is checked for
+  authorization when accessing objects. As with all
+  executable objects, you can modify the effective roles a
+  user has when calling a script using *Proxy Roles* (see
+  the chapter entitled `Users and Security`_
+  for more information). In addition, you cannot access
+  objects whose names begin with an underscore, since Zope
+  considers these objects to be private. Finally, you can
+  define classes in scripts but it is not really practical
+  to do so, because you are not allowed to access
+  attributes of these classes! Even if you were allowed to
+  do so, the restriction against using objects whose names
+  begin with an underscore would prevent you from using
+  your class's __init__ method.  If you need to define
+  classes, use *packages* You may,
+  however, define functions in scripts, although it is
+  rarely useful or necessary to do so.  In practice, a
+  Script in Zope is treated as if it were a single method
+  of the object you wish to call it on.
+
+Writing limits
+  In general you cannot directly change Zope object
+  attributes using scripts. You should call the appropriate
+  methods from the Zope API instead.
+
+Despite these limits, a determined user could use large amounts
+of CPU time and memory using Python-based Scripts. So malicious
+scripts could constitute a kind of denial of service attack by
+using lots of resources. These are difficult problems to solve.
+You probably should not grant access to scripts to
+untrusted people.
+
+
+Python versus Page Templates
+----------------------------
+
+Zope gives you multiple ways to script. For small scripting
+tasks the choice of Python-based Scripts or Page Templates
+probably doesn't make a big difference.  For larger,
+logic-oriented tasks you should use Python-based Scripts or
+write packages on the file-system.
+
+For presentation, Python should *not* be used; instead you use ZPT.
+
+Just for the sake of comparison, here is a simple presentational script 
+suggested by Gisle Aas in ZPT and Python.
+
+In ZPT::
+
+  <div tal:repeat="item context/objectValues" 
+       tal:replace="python:'%s: %s\n' % (item.getId(), str(item))" />
+
+In Python::
+
+  for item in context.objectValues():
+      print "%s: %s" % (item.getId(), item)
+  print "done"
+  return printed
+
+Remote Scripting and Network Services
+-------------------------------------
+
+Web servers are used to serve content to software clients; usually
+people using web browser software.  The software client can also be
+another computer that is using your web server to access some kind of
+service.
+
+Because Zope exposes objects and scripts on the web, it can be used to
+provide a powerful, well organized, secure web API to other remote
+network application clients.
+
+There are two common ways to remotely script Zope.  The first way
+is using a simple remote procedure call protocol called
+*XML-RPC*.  XML-RPC is used to execute a procedure on a remote
+machine and get a result on the local machine.  XML-RPC is designed
+to be language neutral, and in this chapter you'll see examples in
+Python and Java.
+
+The second common way to remotely script Zope is with any HTTP
+client that can be automated with a script.  Many language
+libraries come with simple scriptable HTTP clients and there are
+many programs that let you you script HTTP from the command line.
+
+Using XML-RPC
+~~~~~~~~~~~~~
+
+XML-RPC is a simple remote procedure call mechanism that works
+over HTTP and uses XML to encode information. XML-RPC clients
+have been implemented for many languages including Python,
+Java and JavaScript.
+
+In-depth information on XML-RPC can be found at the "XML-RPC
+website":http://www.xmlrpc.com/. 
+
+All Zope scripts that can be called from URLs can be called via
+XML-RPC. Basically XML-RPC provides a system to marshal
+arguments to scripts that can be called from the web. As you saw
+earlier in the chapter Zope provides its own marshaling
+controls that you can use from HTTP. XML-RPC and Zope's own
+marshaling accomplish much the same thing. The advantage of
+XML-RPC marshaling is that it is a reasonably supported
+standard that also supports marshaling of return values as well
+as argument values.
+
+Here's a fanciful example that shows you how to remotely script
+a mass firing of janitors using XML-RPC.
+
+Here's the code in Python::
+
+  import xmlrpclib
+
+  server = xmlrpclib.Server('http://www.zopezoo.org/')
+  for employee in server.JanitorialDepartment.personnel():
+      server.fireEmployee(employee)
+
+In Java::
+
+  try {
+      XmlRpcClient server = new XmlRpcClient("http://www.zopezoo.org/");
+      Vector employees = (Vector) server.execute("JanitorialDepartment.personnel");
+
+      int num = employees.size();
+      for (int i = 0; i < num; i++) {
+          Vector args = new Vector(employees.subList(i, i+1));
+          server.execute("fireEmployee", args);
+      }
+
+  } catch (XmlRpcException ex) {
+      ex.printStackTrace();
+  } catch (IOException ioex) {
+      ioex.printStackTrace();
+  }
+
+Actually the above example will probably not run correctly, since you
+will most likely want to protect the *fireEmployee* script. This brings
+up the issue of security with XML-RPC. XML-RPC does not have any
+security provisions of its own; however, since it runs over HTTP it can
+leverage existing HTTP security controls. In fact Zope treats an
+XML-RPC request exactly like a normal HTTP request with respect to
+security controls. This means that you must provide authentication in
+your XML-RPC request for Zope to grant you access to protected
+scripts.
+
+Remote Scripting with HTTP
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Any HTTP client can be used for remotely scripting Zope.
+
+On Unix systems you have a number of tools at your
+disposal for remotely scripting Zope. One simple example
+is to use *wget* to call Zope script URLs and use *cron*
+to schedule the script calls. For example, suppose you
+have a Zope script that feeds the lions and you would like
+to call it every morning.  You can use *wget* to call the
+script like so::
+
+  $ wget --spider http://www.zopezope.org/Lions/feed
+
+The *spider* option tells *wget* not to save the response as a
+file. Suppose that your script is protected and requires
+authorization. You can pass your user name and password with *wget* to
+access protected scripts::
+
+  $ wget --spider --http-user=ZooKeeper \
+      --http-passwd=SecretPhrase \
+      http://www.zopezope.org/Lions/feed
+
+Now let's use *cron* to call this command every morning at 8am. Edit
+your crontab file with the *crontab* command::
+
+  $ crontab -e
+
+Then add a line to call wget every day at 8 am::
+
+  0 8 * * * wget -nv --spider --http_user=ZooKeeper \
+    --http_pass=SecretPhrase http://www.zopezoo.org/Lions/feed
+
+(Beware of the linebreak -- the above should be input as
+one line, minus the backslash).
+
+The only difference between using *cron* and calling *wget* manually is
+that you should use the *nv* switch when using *cron* since you don't
+care about output of the *wget* command.
+
+For our final example let's get really perverse. Since networking is
+built into so many different systems, it's easy to find an unlikely
+candidate to script Zope. If you had an Internet-enabled toaster you
+would probably be able to script Zope with it. Let's take Microsoft
+Word as our example Zope client. All that's necessary is to get Word to
+agree to tickle a URL.
+
+The easiest way to script Zope with Word is to tell word to open a
+document and then type a Zope script URL as the file name as shown in
+[8-9].
+
+.. figure:: Figures/8-9.png
+
+   Calling a URL with Microsoft Word
+
+Word will then load the URL and return the results of calling the Zope
+script. Despite the fact that Word doesn't let you POST arguments this
+way, you can pass GET arguments by entering them as part of the URL.
+
+You can even control this behavior using Word's built-in Visual Basic
+scripting. For example, here's a fragment of Visual Basic that tells
+Word to open a new document using a Zope script URL::
+
+  Documents.Open FileName:="http://www.zopezoo.org/LionCages/wash?use_soap=1&water_temp=hot" 
+
+You could use Visual Basic to call Zope script URLs in many different
+ways.
+
+Zope's URL to script call translation is the key to remote
+scripting. Since you can control Zope so easily with simple URLs you
+can easy script Zope with almost any network-aware system.
+
+Conclusion
+----------
+
+With scripts you can control Zope objects and glue together your
+application's logic, data, and presentation. You can
+programmatically manage objects in your Zope folder hierarchy by
+using the Zope API.

Copied: zope2docs/branches/baijum-reorganize/zope2book/SearchingZCatalog.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/SearchingZCatalog.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/SearchingZCatalog.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/SearchingZCatalog.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,1890 @@
+Searching and Categorizing Content
+==================================
+
+The ZCatalog is Zope's built in search engine. It allows you to
+categorize and search all kinds of Zope objects. You can also use it
+to search external data such as relational data, files, and remote
+web pages.  In addition to searching you can use the ZCatalog to
+organize collections of objects.
+
+The ZCatalog supports a rich query interface. You can perform full text
+searching, can search multiple indexes at once, and can even specify
+weighing for different fields in your results. In addition, the
+ZCatalog keeps track of meta-data about indexed objects.
+
+The two most common ZCatalog usage patterns are:
+
+Mass Cataloging
+  Cataloging a large collection of objects all at once.
+
+Automatic Cataloging
+  Cataloging objects as they are created and tracking changes made to them.
+
+Getting started with Mass Cataloging
+------------------------------------
+
+Let's take a look at how to use the ZCatalog to search documents.
+Cataloging a bunch of objects all at once is called *mass cataloging*.
+Mass cataloging involves four steps:
+
+- Creating a ZCatalog
+
+- Creating indexes
+
+- Finding objects and cataloging them
+
+- Creating a web interface to search the ZCatalog.
+
+Creating a ZCatalog
+-------------------
+
+Choose *ZCatalog* from the product add list to create a ZCatalog
+object within a subfolder named 'Zoo'.  This takes you to the
+ZCatalog add form, as shown in the figure below.
+
+.. figure:: Figures/creatingzcatalog.png
+
+   ZCatalog add form
+
+The Add form asks you for an *Id* and a *Title*.  Give your
+ZCatalog the Id 'AnimalCatalog' and click *Add* to create your new
+ZCatalog.  The ZCatalog icon looks like a folder with a small
+magnifying glass on it.  Select the *AnimalCatalog* icon to see
+the *Contents* view of the ZCatalog.
+
+A ZCatalog looks a lot like a folder, but it has a few more
+tabs.  Six tabs on the ZCatalog are the exact same six tabs you
+find on a standard folder.  ZCatalog have the following views:
+*Contents*, *Catalog*, *Properties*, *Indexes*, *Metadata*,
+*Find Objects*, *Advanced*, *Undo*, *Security*, and *Ownership*.
+When you click on a ZCatalog, you are on the *Contents*
+view. Here, you can add new objects and the ZCatalog will
+contain them just as any folder does. Although a ZCatalog is
+like a normal Zope folder, this does not imply that the objects
+contained within it are automatically searchable.  A ZCatalog
+can catalog objects at any level of your site, and it needs to
+be told exactly which ones to index.
+
+Creating Indexes
+~~~~~~~~~~~~~~~~
+
+In order to tell Zope what to catalog and where to store the
+information, we need to create a *Lexicon* and an *Index*.  A
+*Lexicon* is necessary to provide word storage services for
+full-text searching, and an *Index* is the object which stores
+the data necessary to perform fast searching.
+
+In the contents view of the *AnimalCatalog* ZCatalog, choose
+*ZCTextIndex Lexicon*, and give it an id of *zooLexicon*
+
+.. figure:: Figures/creatinglexicon.png
+
+   ZCTextIndex Lexicon add form
+
+Now we can create an index that will record the information we
+want to have in the ZCatalog.  Click on the *Indexes* tab of the
+ZCatalog.  A drop down menu lists the available indexes.  Choose
+*ZCTextIndex*; in the add form fill in the id *zooTextIdx*.
+Fill in *PrincipiaSearchSource* in the "Field name" input.  This
+tells the ZCTextIndex to index the body text of the DTML
+Documents (*PrincipiaSearchSource* is an API method of all DTML
+Document and Method objects).  Note that *zooLexicon* is
+preselected in the *Lexicon* menu.
+
+.. figure:: Figures/creatingtextindex.png
+
+   ZCTextIndex add form
+
+.. note::
+
+   When you want the textindex to work on other types of objects,
+   they have to provide a method named "PrincipiaSearchSource" which
+   returns the data of the object which has to be searched.
+
+To keep this example short we will skip over some of the options
+presented here.  In the section on indexes below, we will
+discuss this more thoroughly.
+
+Additionally, we will have to tell the ZCatalog which attributes
+of each cataloged object that it should store directly.  These
+attributes are called *Metadata*, however they should not be
+confused with the idea of metadata in Zope CMF, Plone, or other
+content management systems--here, this just means that these are
+attributes that will be stored directly in the catalog for
+performance benefits.  For now, just go to the
+*Metadata* tab of the ZCatalog and add *id* and *title*.
+
+Finding and Cataloging Objects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now that you have created a ZCatalog and an Index, you can move
+onto the next step: finding objects and cataloging them.
+Suppose you have a zoo site with information about animals.  To
+work with these examples, create two DTML Documents along-side
+the *AnimalCatalog* object (within the same folder that contains
+the *AnimalCatalog* ZCatalog) that contain information about
+reptiles and amphibians.
+
+The first should have an Id of "chilean_frog", a title "Chilean
+four-eyed frog" and its body text should read something like
+this::
+
+  The Chilean four-eyed frog has a bright
+  pair of spots on its rump that look like enormous eyes. When
+  seated, the frog's thighs conceal these eyespots. When
+  predators approach, the frog lowers its head and lifts its
+  rump, creating a much larger and more intimidating head.
+  Frogs are amphibians.
+
+For the second, fill in an id of "carpet_python" and a title of
+"Carpet Python"; its body text could be::
+
+  *Morelia spilotes variegata* averages 2.4 meters in length.  It
+  is a medium-sized python with black-to-gray patterns of
+  blotches, crossbands, stripes, or a combination of these
+  markings on a light yellowish-to-dark brown background.  Snakes
+  are reptiles.
+
+Visitors to your Zoo want to be able to search for information on
+the Zoo's animals.  Eager herpetologists want to know if you have
+their favorite snake, so you should provide them with the ability
+to search for certain words and show all the documents that
+contain those words.  Searching is one of the most useful and
+common web activities.
+
+The *AnimalCatalog* ZCatalog you created can catalog all of the
+documents in your Zope site and let your users search for specific
+words.  To catalog your documents, go to the *AnimalCatalog*
+ZCatalog and click on the *Find Objects* tab.
+
+In this view, you tell the ZCatalog what kind of objects you are
+interested in.  You want to catalog all DTML Documents so select
+*DTML Document* from the *Find objects of type* multiple selection
+and click *Find and Catalog*.
+
+The ZCatalog will now start from the folder where it is located
+and search for all DTML Documents.  It will search the folder and
+then descend down into all of the sub-folders and their
+sub-folders.  For example, if your ZCatalog is located at
+'/Zoo/AnimalCatalog', then the '/Zoo' folder and all its
+subfolders will get searched. 
+
+If you have lots and lots of objects, this may take a long time
+to complete, so be patient.
+
+After a period of time, the ZCatalog will take you to the *Catalog*
+view automatically, with a status message telling you what it just
+did.
+
+Below the status information is a list of objects that are
+cataloged, they are all DTML Documents.  To confirm that these are
+the objects you are interested in, you can click on them to visit
+them.  Viewing an object in the catalog shows you what was indexed
+for the object, and what metadata items are stored for it.
+
+You have completed the first step of searching your objects,
+cataloging them into a ZCatalog. Now your documents are in the
+ZCatalog's database. Now you can move onto the fourth step,
+creating a web page and result form to query the ZCatalog.
+
+Search and Report Forms
+~~~~~~~~~~~~~~~~~~~~~~~
+
+To create search and report forms, make sure you are inside the
+*AnimalCatalog* ZCatalog and select *Z Search Interface* from the
+add list.  Select the *AnimalCatalog* ZCatalog as the searchable
+object, as shown in the figure below.
+
+.. figure:: Figures/creatingsearchinterface.png
+
+   Creating a search form for a ZCatalog
+
+Name the *Report Id* "SearchResults", the *Search Input Id*
+"SearchForm", select "Generate Page Templates" and click *Add*.
+This will create two new Page Templates in the *AnimalCatalog*
+ZCatalog named *SeachForm* and *SearchResults*.
+
+These objects are *contained in* the ZCatalog, but they are not
+*cataloged by* the ZCatalog.  The *AnimalCatalog* has only
+cataloged DTML Documents.  The search Form and Report templates
+are just a user interface to search the animal documents in the
+ZCatalog. You can verify this by noting that the search and
+report forms are not listed in the *Cataloged Objects* tab.
+
+To search the *AnimalCatalog* ZCatalog, select the *SearchForm*
+template and click on its *Test* tab.  
+
+By typing words into the *ZooTextIdx* form element you can
+search all of the documents cataloged by the *AnimalCatalog*
+ZCatalog.  For example, type in the word "Reptiles".  The
+*AnimalCatalog* ZCatalog will be searched and return a simple
+table of objects that have the word "Reptiles" in them.  The
+search results should include the carpet python.  You can also
+try specifying multiple search terms like "reptiles OR
+amphibians".  Search results for this query should include both
+the Chilean four-eyed Frog and the carpet python.
+Congratulations, you have successfully created a ZCatalog,
+cataloged content into it and searched it through the web.
+
+Configuring ZCatalogs
+---------------------
+
+The ZCatalog is capable of much more powerful and complex searches
+than the one you just performed. Let's take a look at how the
+ZCatalog stores information. This will help you tailor your
+ZCatalogs to provide the sort of searching you want.
+
+Defining Indexes
+~~~~~~~~~~~~~~~~
+
+ZCatalogs store information about objects and their contents in
+fast databases called *indexes*.  Indexes can store and retrieve
+large volumes of information very quickly.  You can create
+different kinds of indexes that remember different kinds of
+information about your objects.  For example, you could have one
+index that remembers the text content of DTML Documents, and
+another index that remembers any objects that have a specific
+property.
+
+When you search a ZCatalog you are not searching through your
+objects one by one. That would take far too much time if you had
+a lot of objects.  Before you search a ZCatalog, it looks at
+your objects and remembers whatever you tell it to remember
+about them.  This process is called *indexing*.  From then on,
+you can search for certain criteria and the ZCatalog will return
+objects that match the criteria you provide.
+
+A good way to think of an index in a ZCatalog is just like an
+index in a book.  For example, in a book's index you can look up
+the word *Python*::
+
+  Python: 23, 67, 227
+
+The word *Python* appears on three pages.  Zope indexes work
+like this except that they map the search term, in this case the
+word *Python*, to a list of all the objects that contain it,
+instead of a list of pages in a book.
+
+In Zope 2.6, indexes can be added and removed from a ZCatalog
+using the "pluggable" index interface as shown in the figure below:
+
+.. figure:: Figures/managingindexes.png
+
+   Managing indexes
+
+Each index has a name, like *PrincipiaSearchSource*,
+and a type, like *ZCTextIndex*.
+
+When you catalog an object the ZCatalog uses each index to
+examine the object. The ZCatalog consults attributes and methods
+to find an object's value for each index. For example, in the
+case of the DTML Documents cataloged with a
+'PrincipiaSearchSource' index, the ZCatalog calls each document's
+'PrincipiaSearchSource' method and records the results in its
+'PrincipiaSearchSource' index. If the ZCatalog cannot find an
+attribute or method for an index, then it ignores it. In other
+words it's fine if an object does not support a given
+index. There are eight kinds of indexes that come standard with
+Zope 2.6, and others that can be added.  The standard eight are:
+
+ZCTextIndex
+  Searches text. Use this kind of index when you
+  want a full-text search.
+
+FieldIndex
+  Searches objects for specific values. Use this
+  kind of index when you want to search objects, numbers, or
+  specific strings.
+
+KeywordIndex
+  Searches collections of specific values. This
+  index is like a FieldIndex, but it allows you to search
+  collections rather than single values.
+
+PathIndex
+  Searches for all objects that contain certain URL
+  path elements.  For example, you could search for all the
+  objects whose paths begin with '/Zoo/Animals'.
+
+TopicIndex
+  Searches among FilteredSets;  each set contains
+  the document IDs of documents which match the set's filter
+  expression.  Use this kind of index to optimize
+  frequently-accessed searches. 
+
+DateIndex
+  A subclass of FieldIndex, optimized for date-time
+  values.  Use this index for any field known to be a date or a
+  date-time. 
+
+DateRangeIndex
+  Searches objects based on a pair of dates /
+  date-times.  Use this index to search for objects which are
+  "current" or "in effect" at a given time. 
+
+TextIndex
+  Old version of a full-text index.  Only provided
+  for backward compatibility, use ZCTextIndex instead.
+
+We'll examine these different indexes more closely later in the
+chapter. New indexes can be created from the *Indexes* view of a
+ZCatalog.  There, you can enter the *name* and select a *type*
+for your new index.  This creates a new empty index in the
+ZCatalog.  To populate this index with information, you need to
+go to the *Advanced* view and click the the *Update Catalog*
+button.  Recataloging your content may take a while if you have
+lots of cataloged objects.  For a ZCTextIndex, you will also
+need a *ZCTextIndex Lexicon* object in your ZCatalog - see below
+for details. 
+
+To remove an index from a ZCatalog, select the Indexes and click
+on the *Delete* button.  This will delete the index and all of
+its indexed content.  As usual, this operation is undoable.
+
+Defining Meta Data
+~~~~~~~~~~~~~~~~~~
+
+The ZCatalog can not only index information about your object,
+but it can also store information about your object in a
+*tabular database* called the *Metadata Table*.  The *Metadata
+Table* works similarly to a relational database table, it
+consists of one or more *columns* that define the *schema* of
+the table.  The table is filled with *rows* of information about
+cataloged objects.  These rows can contain information about
+cataloged objects that you want to store in the table. Your meta
+data columns don't need to match your ZCatalog's indexes. Indexes
+allow you to search; meta-data allows you to report search
+results.
+
+The Metadata Table is useful for generating search reports. It
+keeps track of information about objects that goes on your
+report forms.  For example, if you create a Metadata Table
+column called *Title*, then your report forms can use this
+information to show the titles of your objects that are returned
+in search results instead of requiring that you actually obtain
+the object to show its title.
+
+To add a new Metadata Table column, type in the name of the column
+on the *Metadata Table* view and click *Add*.  To remove a column
+from the Metadata Table, select the column check box and click on
+the *Delete* button.  This will delete the column and all of its
+content for each row.  As usual, this operation is undoable.  Next
+let's look more closely at how to search a ZCatalog.
+
+While metadata columns are useful, there are performance tradeoffs
+from using too many.  As more metadata columns are added, the
+catalog itself becomes larger (and slower), and getting the
+result objects becomes more memory- and performance-intensive.
+Therefore, you should choose metadata columns only for those
+fields that you'll want to show on common search results. 
+Consider carefully before adding a field that returns a large
+result (like the full text of a document) to metadata.
+
+Searching ZCatalogs
+-------------------
+
+You can search a ZCatalog by passing it search terms. These search
+terms describe what you are looking for in one or more indexes. The
+ZCatalog can glean this information from the web request, or you
+can pass this information explicitly from DTML or Python. In
+response to a search request, a ZCatalog will return a list of
+records corresponding to the cataloged objects that match the
+search terms.
+
+Searching with Forms
+~~~~~~~~~~~~~~~~~~~~
+
+In this chapter you used the *Z Search Interface* to
+automatically build a Form/Action pair to query a ZCatalog (the
+Form/Action pattern is discussed in the chapter entitled
+`Advanced Page Templates <AdvZPT.html>`_ ).  The *Z Search
+Interface* builds a very simple form and a very simple
+report. These two methods are a good place to start
+understanding how ZCatalogs are queried and how you can
+customize and extend your search interface.
+
+Suppose you have a ZCatalog that holds news items named
+'NewsCatalog'.  Each news item has 'content', an 'author' and a
+'date' attribute.  Your ZCatalog has three indexes that
+correspond to these attributes, namely "contentTextIdx",
+"author" and "date".  The contents index is a ZCTextIndex, and
+the author and date indexes are a FieldIndex and a DateIndex.
+For the ZCTextIndex you will need a ZCTextIndexLexicon, and to
+display the search results in the 'Report' template, you should
+add the 'author', 'date' and 'absolute_url' attributes as
+Metadata.  Here is a search form that would allow you to query
+such a ZCatalog::
+
+  <html><body>
+  <form action="Report" method="get">
+  <h2 tal:content="template/title_or_id">Title</h2>
+  Enter query parameters:<br><table>
+  <tr><th>Author</th>
+  <td><input name="author" width=30 value=""></td></tr>
+  <tr><th>Content</th>
+  <td><input name="contentTextIdx" width=30 value=""></td></tr>
+  <tr><th>Date</th>
+  <td><input name="date" width=30 value=""></td></tr>
+  <tr><td colspan=2 align=center>
+  <input type="SUBMIT" name="SUBMIT" value="Submit Query">
+  </td></tr>
+  </table>
+  </form>
+  </body></html>
+
+This form consists of three input boxes named 'contentTextIdx',
+'author', and 'date'.  These names must match the names of the
+ZCatalog's indexes for the ZCatalog to find the search terms.
+Here is a report form that works with the search form::
+
+  <html>
+  <body tal:define="searchResults context/NewsCatalog;">
+  <table border>
+    <tr>
+      <th>Item no.</th>
+      <th>Author</th>
+      <th>Absolute url</th>
+      <th>Date</th>
+    </tr>
+    <div tal:repeat="item searchResults">
+    <tr>
+      <td>
+        <a href="link to object" tal:attributes="href item/absolute_url">
+          #<span tal:replace="repeat/item/number">
+            search item number goes here
+          </span>
+        </a>
+      </td>
+      <td><span tal:replace="item/author">author goes here</span></td>
+      <td><span tal:replace="item/date">date goes here</span></td>
+    </tr>
+    </div>
+  </table>
+  </body></html>
+
+There are a few things going on here which merit closer
+examination.  The heart of the whole thing is in the definition
+of the 'searchResults' variable::
+
+  <body tal:define="searchResults context/NewsCatalog;">
+
+This calls the 'NewsCatalog' ZCatalog.  Notice how the form
+parameters from the search form ( 'contentTextIdx' ,
+'author', 'date' ) are not mentioned here at all.
+Zope automatically makes sure that the query parameters from the
+search form are given to the ZCatalog.  All you have to do is
+make sure the report form calls the ZCatalog.  Zope locates the
+search terms in the web request and passes them to the ZCatalog.
+
+The ZCatalog returns a sequence of *Record Objects* (just like
+ZSQL Methods).  These record objects correspond to *search
+hits*, which are objects that match the search criteria you
+typed in. For a record to match a search, it must match all
+criteria for each specified index. So if you enter an author and
+some search terms for the contents, the ZCatalog will only return
+records that match both the author and the contents.
+
+ZSQL Record objects have an attribute for every column in the
+database table.  Record objects for ZCatalogs work very
+similarly, except that a ZCatalog Record object has an attribute
+for every column in the Metadata Table.  In fact, the purpose of
+the Metadata Table is to define the schema for the Record
+objects that ZCatalog queries return.
+
+Searching from Python
+~~~~~~~~~~~~~~~~~~~~~
+
+Page Templates make querying a ZCatalog from a form very simple.
+For the most part, Page Templates will automatically make sure
+your search parameters are passed properly to the ZCatalog.
+
+Sometimes though you may not want to search a ZCatalog from a web
+form; some other part of your application may want to query a
+ZCatalog.  For example, suppose you want to add a sidebar to the
+Zope Zoo that shows news items that only relate to the animals
+in the section of the site that you are currently looking at.
+As you've seen, the Zope Zoo site is built up from Folders that
+organize all the sections according to animal.  Each Folder's id
+is a name that specifies the group or animal the folder
+contains.  Suppose you want your sidebar to show you all the
+news items that contain the id of the current section.  Here is
+a Script called 'relevantSectionNews' that queries the news
+ZCatalog with the currentfolder's id::
+
+  ## Script (Python) "relevantSectionNews"
+  ##
+  """ Returns news relevant to the current folder's id """
+  id=context.getId()
+  return context.NewsCatalog({'contentTextIdx' : id})
+
+This script queries the 'NewsCatalog' by calling it like a
+method.  ZCatalogs expect a *mapping* as the first argument when
+they are called.  The argument maps the name of an index to the
+search terms you are looking for.  In this case, the
+'contentTextIdx' index will be queried for all news items that
+contain the name of the current Folder.  To use this in your
+sidebar place you could insert this snippet where appropriate in
+the main ZopeZoo Page Template::
+
+  ...
+  <ul>
+    <li tal:repeat="item context/relevantSectionNews">
+      <a href="news link" tal:attributes="href item/absolute_url">
+        <span tal:replace="item/title">news title</span>
+      </a>
+    </li>
+  </ul>
+  ...     
+
+This template assumes that you have defined 'absolute_url' and
+'title' as Metadata columns in the 'NewsCatalog'. Now, when you
+are in a particular section, the sidebar will show a simple list
+of links to news items that contain the id of the current animal
+section you are viewing.  (Note: in reality, you shouldn't use
+an index called 'absolute_url', but should rely instead on the
+getURL() method call below, as that works even in virtual hosting
+settings.
+
+Methods of Search Results
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The list of results you get for a catalog search is actually
+a list of Catalog Brain objects.  In addition to having an
+attribute for each item of your metadata, they also have
+several useful methods:
+
+has_key(key)
+  Returns true if the result object has a meta-data element 
+  named key.
+
+getPath()
+  Returns the physical path of the result object.  This can be
+  used to uniquely identify each object if some kind of
+  post-processing is performed.
+
+getURL()
+  Returns the URL of the result object.  You should use this
+  instead of creating a metadata element for 'absolute_url',
+  This can differ from getPath() if you are using virtual hosting.
+
+getObject()
+  Returns the actual zope object from the result object.  This
+  is useful if you want to examine or show an attribute or
+  method of the object that isn't in the metadata--once we have
+  the actual object, we can get any normal attribute or method
+  of it.  However, be careful not to use this instead of defining
+  metadata.  Metadata, being stored in the catalog, is 
+  pre-calculated and quickly accessed; getting the same type of
+  information by using 'getObject().attribute_name' requires
+  actually pulling your real object from the ZODB and may be
+  a good deal slower.  On the other hand, stuffing everything
+  you might ever need into metadata will slow down all querying
+  of your catalog, so you'll want to strike a balance. A good
+  idea is to list in metadata those things that would normally
+  appear on a tabular search results form; other things that
+  might be needed less commonly (and for fewer result objects
+  at a time) can be retried with getObject.
+
+getRID()
+  Returns the Catalog's record id for the result object.  This
+  is an implementation detail, and is not useful except for
+  advanced uses.
+
+Searching and Indexing Details
+------------------------------
+
+Earlier you saw that the ZCatalog includes eight types of
+indexes.  Let's examine these indexes more closely, and look
+at some of the additional available indexes, to understand
+what they are good for and how to search them.
+
+Searching ZCTextIndexes
+~~~~~~~~~~~~~~~~~~~~~~~
+
+A ZCTextIndex is used to index text.  After indexing, you can
+search the index for objects that contain certain words.
+ZCTextIndexes support a rich search grammar for doing more
+advanced searches than just looking for a word.
+
+Boolean expressions
+%%%%%%%%%%%%%%%%%%%
+
+  Search for Boolean expressions
+  like::
+
+    word1 AND word2
+
+  This will search for all objects that contain *both* "word1"
+  and "word2".  Valid Boolean operators include AND, OR, and
+  NOT.  A synonym for NOT is a leading hyphen::
+
+    word1 -word2
+
+  which would search for occurences of "word1" but would
+  exclude documents which contain "word2".  A sequence of words
+  without operators implies AND. A search for "carpet python
+  snakes" translates to "carpet AND python AND snakes".
+
+Parentheses
+%%%%%%%%%%%
+
+  Control search order with parenthetical 
+  expressions::
+
+    (word1 AND word2) OR word3)
+
+  This will return objects containing "word1" and "word2" *or*
+  just objects that contain the term "word3".
+
+Wild cards
+%%%%%%%%%%
+
+  Search for wild cards
+  like::
+
+    Z*
+
+  which returns all words that begin with "Z", 
+  or::
+
+     Zop?
+
+  which returns all words that begin with "Zop" and have one
+  more character - just like in a Un*x shell.  Note though that
+  wild cards cannot be at the beginning of a search phrase.
+  "?ope" is an illegal search term and will be ignored.
+
+Phrase search
+%%%%%%%%%%%%%
+
+  Double-quoted text implies phrase search, 
+  for example::
+
+    "carpet python" OR frogs 
+
+  will search for all occurences of the phrase "carpet python"
+  or of the word "frogs"
+
+All of these advanced features can be mixed together.  For
+example::
+
+  ((bob AND uncle) AND NOT Zoo*)
+
+will return all objects that contain the terms "bob" and "uncle"
+but will not include any objects that contain words that start
+with "Zoo" like "Zoologist", "Zoology", or "Zoo" itself.
+
+Similarly, a search 
+for::
+
+  snakes OR frogs -"carpet python"
+
+will return all objects which contain the word "snakes" or
+"frogs" but do not contain the phrase "carpet python".
+
+Querying a ZCTextIndex with these advanced features works just
+like querying it with the original simple features.  In the HTML
+search form for DTML Documents, for example, you could enter
+"Koala AND Lion" and get all documents about Koalas and Lions.
+Querying a ZCTextIndex from Python with advanced features works
+much the same; suppose you want to change your
+'relevantSectionNews' Script to not include any news items that
+contain the word "catastrophic"::
+
+  ## Script (Python) "relevantSectionNews"
+  ##
+  """ Returns relevant, non-catastropic news """
+  id=context.getId()
+  return context.NewsCatalog(
+           {'contentTextIdx' : id + ' -catastrophic'}
+          )
+
+ZCTextIndexes are very powerful.  When mixed with the Automatic
+Cataloging pattern described later in the chapter, they give you
+the ability to automatically full-text search all of your
+objects as you create and edit them.
+
+In addition, below, we'll talk about TextIndexNG indexes, which
+are a competing index type that can be added to Zope, and offers
+even more additional features for full-text indexing.
+
+Lexicons
+~~~~~~~~
+
+Lexicons are used by ZCTextIndexes.  Lexicons process and store
+the words from the text and help in processing queries.
+
+Lexicons can:
+
+Normalize Case
+  Often you want search terms to be case insensitive, eg. a search for
+  "python", "Python" and "pYTHON" should return the same results.  The
+  lexicons' *Case Normalizer* does exactly that.
+
+Remove stop words
+  Stop words are words that are very common in a given language and should
+  be removed from the index.  They would only cause bloat in the index and
+  add little information.  In addition, stop words, being common words,
+  would appear in almost every page, without this option turned on, a user
+  searching for "the python house" would get back practically every single
+  document on the site (since they would all likely contain "the"), taking
+  longer and adding no quality to their results.
+
+Split text into words
+  A splitter parses text into words.  Different texts have different needs
+  of word splitting - if you are going to process HTML documents, you might
+  want to use the HTML aware splitter which effectively removes HTML tags.
+  On the other hand, if you are going to index plain text documents *about*
+  HTML, you don't want to remove HTML tags - people might want to look them
+  up.  Also, an eg. chinese language document has a different concept of
+  words and you might want to use a different splitter. 
+
+The Lexicon uses a pipeline architecture. This makes it possible
+to mix and match pipeline components.  For instance, you could
+implement a different splitting strategy for your language and
+use this pipeline element in conjunction with the standard text
+processing elements.  Implementing a pipeline element is out of
+the scope of this book; for examples of implementing and
+registering a pipeline element see
+eg. 'Products.ZCTextIndex.Lexicon.py'.  A pipeline
+element should conform to the 'IPipelineElement' interface.
+
+To create a ZCTextIndex, you first have to create a Lexicon
+object.  Multiple ZCTextIndexes can share the same lexicon. 
+
+Searching Field Indexes
+~~~~~~~~~~~~~~~~~~~~~~~
+
+*FieldIndexes* have a different aims than ZCTextIndexes.  A ZCTextIndex
+will treat the value it finds in your object, for example the
+contents of a News Item, like text.  This means that it breaks
+the text up into words and indexes all the individual words.
+
+A FieldIndex does not break up the value it finds.  Instead, it
+indexes the entire value it finds.  This is very useful for
+tracking object attributes that contain simple values, such as
+numbers or short string identifiers.
+
+In the news item example, you created a FieldIndex
+'author'.  With the existing search form, this field is
+not very useful.  Unless you know exactly the name of the author
+you are looking for, you will not get any results.  It would be
+better to be able to select from a list of all the *unique*
+authors indexed by the author index.
+
+There is a special method on the ZCatalog that does exactly this
+called 'uniqueValuesFor'.  The 'uniqueValuesFor' method returns
+a list of unique values for a certain index.  Let's change your
+search form and replace the original 'author' input box
+with something a little more useful::
+
+  <html><body>
+  <form action="Report" method="get">
+  <h2 tal:content="template/title_or_id">Title</h2>
+  Enter query parameters:<br><table>
+  <tr><th>Author</th>
+  <td>
+    <select name="author:list" size="6" multiple>             
+      <option 
+        tal:repeat="item python:context.NewsCatalog.uniqueValuesFor('author')" 
+        tal:content="item"
+        value="opt value">
+      </option>
+    </select>
+  </td></tr>
+  <tr><th>Content</th>
+  <td><input name="content_index" width=30 value=""></td></tr>
+  <tr><th>Date</th>
+  <td><input name="date_index" width=30 value=""></td></tr>
+  <tr><td colspan=2 align=center>
+  <input type="SUBMIT" name="SUBMIT" value="Submit Query">
+  </td></tr>
+  </table>
+  </form>
+  </body></html>
+
+The new, important bit of code added to the search form 
+is::
+
+    <select name="author:list" size="6" multiple>             
+      <option 
+        tal:repeat="item python:context.NewsCatalog.uniqueValuesFor('author')" 
+        tal:content="item"
+        value="opt value">
+      </option>
+    </select>
+
+In this example, you are changing the form element 'author' from
+just a simple text box to an HTML multiple select box.  This box
+contains a unique list of all the authors that are indexed in
+the 'author' FieldIndex.  When the form gets submitted, the
+select box will contain the exact value of an authors name, and
+thus match against one or more of the news objects.  Your search
+form should look now like the figure below.
+
+.. figure:: Figures/uniqueauthorsform.png
+
+   Range searching and unique Authors
+
+Be careful if you catalog objects with many different values; you
+can easily end up with a form with a thousand items in the drop-down
+menu. Also, items must match *exactly*, so strings that differ
+in capitalization will be considered different.
+
+That's it.  You can continue to extend this search form using HTML
+form elements to be as complex as you'd like.  In the next section,
+we'll show you how to use the next kind of index, keyword indexes.
+
+Searching Keyword Indexes
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A *KeywordIndex* indexes a sequence of keywords for objects and
+can be queried for any objects that have one or more of those
+keywords.
+
+Suppose that you have a number of Image objects that have a
+'keywords' property. The 'keywords' property is a lines property
+that lists the relevant keywords for a given Image, for example,
+"Portraits", "19th Century", and "Women" for a picture of Queen
+Victoria.  
+
+The keywords provide a way of categorizing Images. Each Image can
+belong in one or more categories depending on its 'keywords'
+property. For example, the portrait of Queen Victoria belongs to
+three categories and can thus be found by searching for any of the
+three terms. 
+
+You can use a *Keyword* index to search the 'keywords' property. Define
+a *Keyword* index with the name 'keywords' on your ZCatalog. Then
+catalog your Images. Now you should be able to find all the Images
+that are portraits by creating a search form and searching for
+"Portraits" in the 'keywords' field. You can also find all pictures
+that represent 19th Century subjects by searching for "19th
+Century". 
+
+It's important to realize that the same Image can be in more
+than one category. This gives you much more flexibility in
+searching and categorizing your objects than you get with a
+FieldIndex. Using a FieldIndex your portrait of Queen Victoria
+can only be categorized one way.  Using a KeywordIndex it can be
+categorized a couple different ways.
+
+Often you will use a small list of terms with KeywordIndexes.
+In this case you may want to use the 'uniqueValuesFor' method to
+create a custom search form. For example here's a snippet of a
+Page Template that will create a multiple select box for all the
+values in the 'keywords' index::
+
+  <select name="keywords:list" multiple>
+    <option 
+      tal:repeat="item python:context.uniqueValuesFor('keywords')"
+      tal:content="item">
+        opt value goes here
+    </option>
+  </select>
+
+Using this search form you can provide users with a range of
+valid search terms. You can select as many keywords as you want and
+Zope will find all the Images that match one or more of your
+selected keywords. Not only can each object have several indexed
+terms, but you can provide several search terms and find all
+objects that have one or more of those values.
+
+Searching Path Indexes
+~~~~~~~~~~~~~~~~~~~~~~
+
+Path indexes allow you to search for objects based on their
+location in Zope. Suppose you have an object whose path is
+'/zoo/animals/Africa/tiger.doc'. You can find this object with
+the path queries: '/zoo', or '/zoo/animals', or
+'/zoo/animals/Africa'. In other words, a path index allows you
+to find objects within a given folder (and below).
+
+If you place related objects within the same folders, you can
+use path indexes to quickly locate these objects. For example::
+
+  <h2>Lizard Pictures</h2>
+  <p tal:repeat="item
+      python:context.AnimalCatalog(pathindex='/Zoo/Lizards', 
+      meta_type='Image')">
+    <a href="url" tal:attributes="href item/getURL" tal:content="item/title">
+      document title
+    </a>
+  </p>    
+
+This query searches a ZCatalog for all images that are located
+within the '/Zoo/Lizards' folder and below. It creates a link to
+each image.  To make this work, you will have to create a
+FieldIndex 'meta_type' and a Metadata entries for 'title'.
+
+Depending on how you choose to arrange objects in your site, you
+may find that a path indexes are more or less effective.  If you
+locate objects without regard to their subject (for example, if
+objects are mostly located in user "home" folders) then path
+indexes may be of limited value.  In these cases, key word and
+field indexes will be more useful.
+
+Searching DateIndexes
+~~~~~~~~~~~~~~~~~~~~~
+
+DateIndexes work like FieldIndexes, but are optimised for
+DateTime values.  To minimize resource usage, DateIndexes have a
+resolution of one minute, which is considerably lower than the
+resolution of DateTime values.
+
+DateIndexes are used just like FieldIndexes; below in the
+section on "Advanced Searching with Records" we present an
+example of searching them.
+
+Searching DateRangeIndexes
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+DateRangeIndexes are specialised for searching for ranges of
+DateTime values.  An example application would be NewsItems
+which have two DateTime attributes 'effective' and 'expiration',
+and which should only be published if the current date would
+fall somewhere in between these two date values.  Like
+DateIndexes, DateRangeIndexes have a resolution of one minute. 
+
+DateRangeIndexes are widely used in CMF and Plone, where
+content is compared to an effective date and an expiration
+date.
+
+DateRangeIndexes also allow one or both of the boundary dates of
+the indexed objects to be left open which greatly simplifies
+application logic when querying for "active" content where expiration
+and effective dates are optional.
+
+Searching TopicIndexes
+~~~~~~~~~~~~~~~~~~~~~~
+
+A TopicIndex is a container for so-called FilteredSets. A
+FilteredSet consists of an expression and a set of internal
+ZCatalog document identifiers that represent a pre-calculated
+result list for performance reasons. Instead of executing the
+same query on a ZCatalog multiple times it is much faster to use
+a TopicIndex instead.
+
+TopicIndexes are also useful for indexing boolean attributes or
+attributes where only one value is queried for. They can do this more
+efficiently then a field index.
+
+Building up FilteredSets happens on the fly when objects are
+cataloged and uncatalogued. Every indexed object is evaluated
+against the expressions of every FilteredSet. An object is added
+to a FilteredSet if the expression with the object evaluates to
+True. Uncatalogued objects are removed from the FilteredSet.
+
+A built-in type of FilteredSet is the PythonFilteredSet - it
+would be possible to construct custom types though.
+
+A PythonFilteredSet evaluates using the eval() function inside the
+context of the FilteredSet class. The object to be indexes must
+be referenced inside the expression using "o.".  Below are some
+examples of expressions.
+
+This would index all DTML 
+Methods::
+
+  o.meta_type=='DTML Method'
+
+This would index all folderish objects which have a non-empty
+title::
+
+  o.isPrincipiaFolderish and o.title
+
+Querying of TopicIndexes is done much in the same way as with
+other Indexes.  Eg., if we named the last FilteredSet above
+'folders_with_titles', we could query our TopicIndex with a
+Python snippet like::
+
+  zcat = context.AnimalCatalog
+  results = zcat(topicindex='folders_with_titles')
+
+Provided our 'AnimalCatalog' contains a TopicIndex 'topicindex',
+this would return all folderish objects in 'AnimalCatalog' which
+had a non-empty title.  
+
+TopicIndexes also support the 'operator' parameter with Records.
+More on Records below.
+
+Advanced Searching with Records
+-------------------------------
+
+A more advanced feature is the ability to query indexes more
+precisely using record objects.  Record objects contain
+information about how to query an index.  Records are Python
+objects with attributes, or mappings.  Different indexes support
+different record attributes.
+
+Note that you don't have to use record-style queries unless you
+need the features introduced by them: you can continue to use
+traditional queries, as demonstrated above.
+
+A record style query involves passing a record (or dictionary)
+to the catalog instead of a simple query string.
+
+Keyword Index Record Attributes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+'query'
+ Either a sequence of words or a single word.
+ (mandatory)
+
+'operator'
+ Specifies whether all keywords or only one need
+ to match. Allowed values: 'and', 'or'. (optional, default:
+ 'or')
+
+For example::
+
+  # big or shiny
+  results=ZCatalog(categories=['big, 'shiny'])
+
+  # big and shiny
+  results=ZCatalog(categories={'query':['big','shiny'], 
+                                       'operator':'and'})
+
+The second query matches objects that have both the keywords
+"big" and "shiny". Without using the record syntax you can
+only match objects that are big or shiny.
+
+FieldIndex Record Attributes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+'query'
+  Either a sequence of objects or a single value to be
+  passed as query to the index (mandatory)
+
+'range'
+  Defines a range search on a Field Index (optional, default: not set).
+
+  Allowed values:
+
+    'min'
+      Searches for all objects with values larger than
+      the minimum of the values passed in the 'query' parameter.
+
+    'max'
+      Searches for all objects with values smaller than
+      the maximum of the values passed in the 'query' parameter.
+
+    'minmax'
+      Searches for all objects with values smaller than the maximum of the
+      values passed in the 'query' parameter and larger than the minimum of
+      the values passwd in the 'query' parameter. 
+
+For example, here is a PythonScript snippet using a range 
+search::
+
+  # animals with population count greater than 5
+  zcat = context.AnimalCatalog
+  results=zcat(population_count={
+                   'query' : 5,
+                   'range': 'min'}
+              )
+
+This query matches all objects in the AnimalCatalog which have a
+population count greater than 5 (provided that there is a
+FieldIndex 'population_count' and an attribute 'population_count'
+present).
+
+Or::
+
+  # animals with population count between 5 and 10
+  zcat = context.AnimalCatalog
+  results=zcat(population_count={
+                   'query': [ 5, 10 ],
+                   'range': 'minmax'}
+              )
+
+This query mathches all animals with population count
+between 5 and 10 (provided that the same FieldIndex
+'population_count' indexing the attribute 'population_count'.)
+
+Path Index Record Attributes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+'query'
+  Path to search for either as a string (e.g. "/Zoo/Birds") or list (e.g.
+  ["Zoo", "Birds"]). (mandatory)
+
+'level'
+  The path level to begin searching at.  Level defaults to 0, which means
+  searching from the root.  A level of -1 means start from anywhere in the
+  path. 
+
+Suppose you have a collection of objects with these paths:
+
+- '/aa/bb/aa'
+
+- '/aa/bb/bb'
+
+- '/aa/bb/cc'
+
+- '/bb/bb/aa'
+
+- '/bb/bb/bb'
+
+- '/bb/bb/cc'
+
+- '/cc/bb/aa'
+
+- '/cc/bb/bb'
+
+- '/cc/bb/cc'
+
+Here are some examples queries and their results to show how the
+'level' attribute works:
+
+'query="/aa/bb", level=0'
+  This gives the same behaviour as our previous examples, ie. searching
+  absolute from the root, and results in:
+
+  - '/aa/bb/aa'
+
+  - '/aa/bb/bb'
+
+  - '/aa/bb/cc'
+
+'query="/bb/bb", level=0'
+  Again, this returns the default: 
+
+  - '/bb/bb/aa'
+
+  - '/bb/bb/bb'
+
+  - '/bb/bb/cc'
+
+'query="/bb/bb", level=1'
+  This searches for all objects which have '/bb/bb' one level down from
+  the root:
+
+  - '/aa/bb/bb'
+
+  - '/bb/bb/bb'
+
+  - '/cc/bb/bb'
+
+'query="/bb/bb", level=-1'
+  Gives all objects which have '/bb/bb' anywhere in their path:
+
+  - '/aa/bb/bb'
+
+  - '/bb/bb/aa'
+
+  - '/bb/bb/bb'
+
+  - '/bb/bb/cc'
+
+  - '/cc/bb/bb'
+
+'query="/xx", level=-1'
+  Returns None
+
+You can use the level attribute to flexibly search different
+parts of the path.
+
+As of Zope 2.4.1, you can also include level information in a
+search without using a record. Simply use a tuple containing the
+query and the level. Here's an example tuple: '("/aa/bb", 1)'.
+
+DateIndex Record Attributes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The supported Record Attributes are the same as those of the
+FieldIndex:
+
+'query'
+  Either a sequence of objects or a single value to be
+  passed as query to the index (mandatory)
+
+'range'
+  Defines a range search on a DateIndex (optional,
+  default: not set).
+
+  Allowed values:
+
+    'min'
+      Searches for all objects with values larger than
+      the minimum of the values passed in the 'query' parameter.
+
+    'max'
+      Searches for all objects with values smaller than
+      the maximum of the values passed in the 'query' parameter.
+
+    'minmax'
+      Searches for all objects with values smaller
+      than the maximum of the values passed in the 'query'
+      parameter and larger than the minimum of the values passwd
+      in the 'query' parameter. 
+
+As an example, we go back to the NewsItems we created in the
+Section *Searching with Forms*.  For this example, we created
+news items with attributes 'content', 'author', and 'date'.
+Additionally, we created a search form and a report template for
+viewing search results.  
+
+Searching for dates of NewsItems was not very comfortable
+though - we had to type in exact dates to match a document.
+
+With a 'range' query we are now able to search for ranges of
+dates.  Take a look at this PythonScript snippet::
+
+  # return NewsItems newer than a week
+  zcat = context.NewsCatalog
+  results = zcat( date={'query' : context.ZopeTime() - 7,
+                        'range' : 'min'
+                })
+
+DateRangeIndex Record Attributes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+DateRangeIndexes only support the 'query' attribute on Record
+objects.  The 'query' attribute results in the same
+functionality as querying directly; returning matches where
+the date supplied to the query falls between the start and
+end dates from the indexed object.
+
+TopicIndex Record Attributes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Like KeywordIndexes, TopicIndexes support the 'operator'
+attribute:
+
+'operator'
+  Specifies whether all FieldSets or only one need to match.
+  Allowed values: 'and', 'or'. (optional, default: 'or')
+
+ZCTextIndex Record Attributes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Because ZCTextIndex operators are embedded in the query string,
+there are no additional Record Attributes for ZCTextIndexes.
+
+Creating Records in HTML
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can also perform record queries using HTML forms. Here's an
+example showing how to create a search form using records::
+
+  <form action="Report" method="get">
+  <table>
+  <tr><th>Search Terms (must match all terms)</th>
+      <td><input name="content.query:record" width=30 value=""></td></tr>
+      <input type="hidden" name="content.operator:record" value="and">
+  <tr><td colspan=2 align=center>
+  <input type="SUBMIT" value="Submit Query">
+  </td></tr>
+  </table>
+  </form>
+
+For more information on creating records in HTML see the section
+"Passing Parameters to Scripts" in Chapter 14, Advanced Zope
+Scripting.
+
+Automatic Cataloging
+--------------------
+
+Automatic Cataloging is an advanced ZCatalog usage pattern that
+keeps objects up to date as they are changed. It requires that as
+objects are created, changed, and destroyed, they are
+automatically tracked by a ZCatalog. This usually involves the
+objects notifying the ZCatalog when they are created, changed, or
+deleted.
+
+This usage pattern has a number of advantages in comparison to
+mass cataloging. Mass cataloging is simple but has drawbacks.  The
+total amount of content you can index in one transaction is
+equivalent to the amount of free virtual memory available to the
+Zope process, plus the amount of temporary storage the system has.
+In other words, the more content you want to index all at once,
+the better your computer hardware has to be.  Mass cataloging
+works well for indexing up to a few thousand objects, but beyond
+that automatic indexing works much better.
+
+If you can trade off memory for time, you can enable
+'Subtransactions' in the 'Advanced' tab of the catalog. This
+commits the work in chunks, reducing memory requirements, but
+taking longer. It is a good solution for mass cataloging with a
+very large number of records.
+
+Another major advantage of automatic cataloging is that it can
+handle objects that change. As objects evolve and change, the
+index information is always current, even for rapidly changing
+information sources like message boards.
+
+On the other hand, cataloging a complex object when it changes
+(especially if the catalog index attempts to translate the
+information, as TextIndexNG, described below, can do with
+PDF files or Microsoft Office files). Some sites may benefit
+from mass cataloging, and having a cron job or other scheduled
+job initiate the mass cataloging every night.
+
+In standard (non-CMF, non-Plone) Zope, none of the built-in
+object types attempt to automatically catalog themselves. In
+CMF and Plone, the "contentish" object (Documents, News Item,
+Event, etc.) all use automatic cataloging to add themselves
+to the standard CMF catalog, 'portal_catalog'.  The CMF
+and especially Plone offer many advantages; if you're interested
+in building a content-oriented site, you should consider
+these technologies.
+
+Advanced Catalog Topics
+-----------------------
+
+Sorting
+~~~~~~~
+
+When you execute a ZCatalog call, your result set may or may not
+be returned in a particular order:
+
+- If your query contains no text index fields, your results will
+  not be sorted in any particular order.  For example, with a
+  query based off a KeywordIndex, or query based off both
+  a KeywordIndex and a DateIndex, you will get a indeterminate
+  ordering.
+
+- For results that include a text index, your results will be
+  returned in order of revelance of the text search.  That is,
+  the result set will be sorted based how often
+  search words appear in the indexes.  A search for the word
+  'frog' against a text index will give priority toward an object
+  that uses that word many times compared with
+  an object that uses that fewer.  This is
+  a simplified version of the way that many web search engines
+  work: the more "relevant" your keywords are to an item, the
+  higher its ordering in the results. In particular, with
+  the ZCTextIndex, you have a choice between two algorithms
+  for how to weight the sorting:
+
+  - Okapi: is the best general choice. It does very well
+    when comparing an ordinary "human query" against a longer
+    text field. For example, querying a long description field
+    for a short query like 'indoor OR mammal' would work very
+    well.
+
+  - Cosine: is better suited for when the length of the
+    query comes close to matching the length of the field
+    itself.
+
+You, of course, may want to force a particular order onto your
+results.  You can do this after you get a result set using
+normal Python syntax::
+
+  # get ordered results from search
+  zcat=context.AnimalCatalog
+  results=zcat({'title':'frog'})
+  results=[(row.title, row) for row in results]
+  results.sort()
+
+This can be, however, very inefficient.
+
+When results are returned by the ZCatalog, they are in a special
+form called a `LazyResults` set.  This means that Zope hasn't
+gone to the trouble of actually creating the entire list, but
+has just sketched out the list and will fill it in at the exact
+point that you ask for each item.  This is helpful, since it lets
+you query the catalog for a result set with 10,000 items without
+Zope having to really construct a 10,000 item long list of results.
+However, when we try to sort this, Zope will have to actually
+create this list since it can't rely on it's lazy, just-in-time
+method.
+
+Normally, you'll only show the first 20 or 50 or so of a result
+set, so sorting 10,000 items just to show the first 20 is a waste
+of time and memory.  Instead, we can ask the catalog to do the
+sorting for us, saving both time and space.
+
+To do this, we'll pass along several additional keywords in our
+search method call or query:
+
+sort_on
+  The field name to sort the results on
+
+sort_order
+  'ascending' or 'descending', with the default
+    being 'ascending. Note that you can also use 'reverse'
+    as a synonym for 'descending'
+
+sort_limit
+  Since you're likely to only want to use the
+    first 20 or 50 or so items, we can give a hint to the 
+    ZCatalog not to bother to sort beyond this by passing along
+    a 'sort_limit' parameter, which is the number of records
+    to sort.
+
+For example, assuming we have a 'latin_name' FieldIndex on our
+animals, we can sort them by name in a PythonScript with::
+
+  zcat=context.AnimalCatalog
+  zcat({'sort_on':'latin_name'})
+
+or::
+
+  zcat=context.AnimalCatalog
+  zcat({'sort_on':'latin_name', 'sort_order':'descending'})
+
+or, if we know we'll only want to show the first 20 records::
+
+  zcat=context.AnimalCatalog
+  zcat({'sort_on':'latin_name',
+        'sort_order':'descending',
+        'sort_limit':20})
+
+or, combining this with a query restriction::
+
+  zcat=context.AnimalCatalog
+  zcat({'title':'frog',
+        'sort_on':'latin_name',
+        'sort_order':'descending',
+        'sort_limit':20})
+
+This gives us all records with the 'title' "frog", sorted
+by 'latin_name', and doesn't bother to sort after the first
+20 records.
+
+Note that using 'sort_limit' does not guarantee that we'll get
+exactly that number of records--we may get fewer if they're
+aren't that many matching or query, and we may get more. 
+'sort_limit' is merely a request for optimization. To
+ensure that we get no more than 20 records, we'll want to 
+truncate our result set::
+
+  zcat=context.AnimalCatalog
+  zcat({'sort_on':'latin_name',
+        'sort_order':'descending',
+        'sort_limit':20})[:20]
+
+Unsortable Fields
+%%%%%%%%%%%%%%%%%
+
+In order to sort on a index, we have to actually keep the
+full attribute or method value in that index.  For many
+index types, such as DateIndex or FieldIndex, this is
+normally done.  However, for text indexes, such as
+ZCTextIndex, TextIndex (deprecated), and TextIndexNG
+(described below), the index doesn't keep the actual
+attribute or method results in the index.  Instead, it
+cleans up the input (often removing "stop words",
+normalizing input, lowercasing it, removing duplicates,
+etc., depending on the options chosen.  So a term paper
+with an attribute value of::
+
+  "A Critique of 'Tora! Tora! Tora!'"
+
+could actually be indexed as :
+
+  ( 'critique', 'tora' )
+
+once the common stop words ("a", "of") are removed,
+it is lowercased and de-deduplicated.  (In reality,
+the indexed information is much richer, as it keeps
+track of things like how often words appear, and which
+words appear earlier in the the stream, but this gives
+you an idea of what is stored.)
+
+This is a necessary and positive step to make the index
+use less storage and less memory, and increases search
+results, as your site user doesn't have to worry about
+getting incidental words ("the", "a", etc.) correct,
+nor about capitalization, etc.
+
+**Note:** As we'll see, TextIndexNG indexes can even
+do advanced tricks, such as normalizing a word and
+stemming it, so that a search for "vehicles" could
+find "vehicle" or even "car".
+
+However, this process means that the index no longer knows
+the actual value, and, therefore, can't sort on it.
+Due to this, it is not possible to use the 'sort_on'
+feature with text indexes types.
+
+To work around this, you can either sort the results of
+the query using the normal python 'sort()' feature
+(shown above), or you can create an additional non-text
+index on the field, described below, in the section
+'Indexing a Field with Two Index Types'.
+
+Similarly, the API call 'uniqueValuesFor', described above,
+cannot be used on text-type indexes, since the exact
+values are not kept.
+
+Searching in More Than One Index Using "OR"
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As mentioned, if you search in more than one index,
+you must meet your criteria for each index you search
+in, i.e., there is an implied 'AND' between each of the
+searches::
+
+  # find sunset art by Van Gogh
+  zcat=context.ArtCatalog
+  results=zcat({'keyword':'sunsets', 'artist':'Van Gogh'})
+
+This query finds all sunset art by Van Gogh: both of
+these conditions must be true.
+
+There is no way to directly search in more than one
+index without this 'AND' condition; instead, you can
+perform two catalog searches and concatenate their
+results. For example::
+
+  # find sunset art OR art by Van Gogh
+  zcat=context.ArtCatalog
+  results=zcat({'keyword':'sunsets'}) + \
+          zcat({'artist':'Van Gogh'})
+
+This method, however, does not remove duplicates, so
+a painting of a sunset by VanGogh would appear twice.
+
+For alternate strategies about searching in two places,
+see 'PrincipiaSearchSource' and 'FieldedTextIndex', below,
+both of which can be used as possible workarounds.
+
+Indexing a Field With Two Index Types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Since the different indexes act differently, it can be advantageous
+to have the same attribute indexed by more than one index.  For
+example, our animals have a 'latin_name' attribute that gives their
+formal genus/species latin name.  A user should be able to search
+that trying to match a name *exactly*, and we should be able to
+sort results based on that, both of which suggest a FieldIndex.  In
+addition, though, users may want to search that like a text field,
+where they can match parts of words, in which case we would a
+ZCTextIndex (or TextIndexNG, described below).
+
+In a case like this, a good strategy is to create one index for the
+FieldIndex on 'latin_name'.  Let's call that index 'latin_name'.
+Then, you can create a ZCTextIndex that uses a new feature: the
+ability to have the indexed attribute be different than the index
+name itself.
+
+When you create the second index, the ZCTextIndex, you can give it
+the Id 'latin_name_text', and have the 'Indexed attributes' field
+be 'latin_name'.  Now, when we catalog our animals, their
+'latin_name' attribute is indexed in two ways: once, as a
+FieldIndex, that we can sort against and match exactly, and once as
+a ZCTextIndex, that we can search like a text field with full text
+search.
+
+The second index has a different name, so when make our catalog
+call, we'll need to be sure to use that name if we want to search
+it like a text field::
+
+  # search latin_name
+  zcat=context.AnimalCatalog
+  exact_results=zcat({'latin_name':'homo sapien'})
+  fuzzy=zcat({'latin_name_text':'sap*'})
+
+Note that a good strategy is to have the search be against the
+ZCTextIndex, but sort it by the FieldIndex::
+
+  # free text search, sorted
+  zcat=context.AnimalCatalog
+  results=zcat({'latin_name_text':'sap*',
+                'sort_on':'latin_name'})
+
+PrincipiaSearchSource
+~~~~~~~~~~~~~~~~~~~~~
+
+You can choose to create indexes on any attribute or method that
+you would find useful to search on; however, one that is
+generally helpful is 'PrincipiaSearchSource'.  Several of the
+built-in Zope objects, such as DTMLDocuments, and many add-on
+objects to Zope have a 'PrincipiaSearchSource' attribute or
+method that returns a value that is meant to be used for general
+purpose searching.  Traditionally, 'PrincipiaSearchSource'
+would include the text in an object's title, it's body, and
+anywhere else you'd want to be able to search. 
+
+For example, if you downloaded a zope product that managed
+our zoo, and it had an Animal type that you could add to your
+site, this animal type would probably expose a 
+PrincipiaSearchSource that looked something like this::
+
+  def PrincipiaSearchSource(self):
+    "used for general searching for animal"
+    return self.title + ' ' + self.latin_name + ' ' \
+         + self.description + ' ' + self.environment
+
+So that, if you create a 'PrincipiaSearchSource' index and
+search again that, you can find this animal by using words
+that are in it's 'title', 'latin_name', 'description', or
+'environment', without having to worry about which field,
+exactly, they're in.  This is similar to searching with a
+web search engine, in that you use can use a single text string
+to find the "right" information, without needing to know about
+the type of object you're looking for.  It is especially
+helpful in allowing you to create a site-wide search: searching
+animals specifically by their 'latin_name' or 'environment'
+might be useful for a biologist in the right section of your
+site, but for a general purpose visitor, they might like
+to search using the phrase "jungle" and find results without
+having to know to search for that in the 'environment' field
+of a search form.
+
+If you create custom types by using more advanced techniques described
+elsewhere, you should create a PrincipiaSearchSource method that returns
+appropriate object-wide text searching capabilities.
+
+ZCatalogs and CMF/Plone
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The CMF was built from the ground up to understand the
+difference between things that are "content", such as a news item
+or press release, and those things that are not, such as
+a DTMLMethod used to show a press release, or a ZCatalog
+object.  In addition, the CMF includes several stock items
+that are intended to be used for content, including:
+Document, Event, NewsItem, and others.  These content items
+are already set up for autocataloging, so that any changes
+made will appear in the catalog.
+
+In non-CMF Zope, the traditional name for a general-purpose
+catalog is 'Catalog' (though you can always create your own
+catalog with any id you want; we've used the example
+'AnimalCatalog' in this chapter for a special-purpose catalog
+for searching animal-specific info in our zoo.)  Even though
+'Catalog' is the traditional name, Zope does not come with
+such a catalog in the ZODB already, you have to create it.
+
+In CMF (and Plone, an out-of-the-box portal system built
+on top of the CMF), there is always a catalog created, called
+'portal_catalog', at the root of the CMF site.  All of the
+built-in content objects (and almost every add-on content
+object for the CMF/Plone) are set to autocatalog to this
+'portal_catalog'.  This is required, since many of the features
+of the CMF and Plone, such as listing current content, finding
+content of correct types, etc., rely on the 'portal_catalog'
+and the searching techniques shown here to function.
+
+In CMF and Plone, the index name 'PrincipiaSearchSource' is
+not traditionally used.  Instead, an index is created called
+'SearchableText', and used in the same manner as
+'PrincipiaSearchSource'.  All of the standard contentish
+objects have a 'SearchableText' method that returns things
+like title, description, body, etc., so that they can be
+general-text searched.
+
+Add-On Index Types
+------------------
+
+TextIndexNG
+~~~~~~~~~~~
+
+TextIndexNG is a new text index that competes with ZCTextIndex.
+Unlike ZCTextIndex, TextIndexNG is an add-on product that must be
+separately installed. It offers a large number of features:
+
+- Document Converters 
+
+  If your attribute value isn't plain text, TextIndexNG can convert
+  it to text to index it.  This will allow you to store, for
+  instance, a PDF file in Zope
+  and be able to search the text of that PDF file.  Current
+  formats it can convert are: HTML, PDF, Postscript, Word,
+  Powerpoint, and OpenOffice.
+
+- Stemmer Support
+
+  Reduces words to a stem (removes verb endings and
+  plural-endings), so a user can search for "car" and get "car"
+  and "cars", without having to try the search twice.  It
+  knows how to perform stemming in 13 different languages.
+
+- Similarity Search
+
+  Can find words that are "similar" to your words, based on
+  the Levenshtein algorithm.  Essentially, this measures the
+  distance between two terms using indicators such as how
+  many letters differ from one to another.
+
+- Near Search
+
+  Can look for words that are near each other.  For example,
+  a search for "Zope near Book" would find results where
+  these words were close to each other in the document.
+
+- Customizable Parsers
+
+  Rather than having only one way to express a query, TextIndexNG
+  uses a "pluggable" architecture where a Python programmers can
+  create new parsers.  For example, to find a document that
+  includes the word "snake" but not the word "python", you'd
+  search for "snake andnot python" in the default parser.
+  However, given your users expectations (and native language),
+  they might prefer to say "snake and not python" or "snake
+  -python" or such.  TextIndexNG comes with three different
+  parsers: a rich, default one, a simple one that is suitable for
+  more general serarching, and a German one that uses
+  german-language words ("nicht" for "not", for example).
+  Although writing a new parser is an advanced task, it would be
+  possible for you to do so if you wanted to let users express
+  the question in a different form.
+
+- Stop Words
+
+  You can customize the list of "stop words" that are too common
+  to both indexing or search for.
+
+- Wilcard Search
+
+  You can use a "wildcard" to search for part of a word, such as
+  "doc*" to find all words starting with "doc".  Unlike
+  ZCTextIndex, you can also use wildcards are the start of a
+  word, such as "\*doc" to find all words ending with "doc", as
+  well.
+
+- Normalization Support
+
+  Removing accented characters so that users can search for an
+  accented word without getting the accents exactly right.
+
+- Auto-Expansion
+
+  This optional feature allows you to get better search results
+  when some of the query terms could not be found.  In this
+  case, it uses a similarity matching to "expand" the query
+  term to find more matches.
+
+- Ranking Support
+
+  Sorting of results based on their word frequencies,
+  similar to the sorting capabilities of ZCTextIndex.
+
+TextIndexNG is an excellent replacement for ZCTextIndex,
+especially if you have non-English language documents or expect to
+have users that will want to use a rich query syntax.
+
+Full information on TextIndexNG is available at
+http://pypi.python.org/pypi/textindexng.
+
+FieldedTextIndex
+~~~~~~~~~~~~~~~~
+
+FieldTextIndex is a new index type that is not (yet) a standard
+part of Zope, but is a separate product that can be installed
+and used with a standard catalog.
+
+Often, a site will have a combined field (normally
+'PrincipiaSearchSource' or 'SearchableText', as described above)
+for site-wide searching, and individual fields for more
+content-aware searching, such as the indexes on 'latin_name',
+'environment', etc.
+
+Since it's slows down performance to concatenate catalog result
+sets directly, the best strategy for searching across many fields
+is often use the 'PrincipiaSearchSource'/'SearchableText'
+strategy of a single text index.  However, this can be *too*
+limiting, as sometimes users want to search in several fields at
+once, rather than in all.
+
+FieldedTextIndex solves these problems by extending the standard
+ZCTextIndex so that it can receive and index the textual data of an
+object's field attributes as a mapping of field names to field
+text.  The index itself performs the aggregation of the fielded
+data and allows queries to be performed across all fields (like a
+standard text index) or any subset of the fields which have been
+encountered in the objects indexed.
+
+In other words, a normal 'PrincipiaSearchSource' method would
+look something like this::
+
+  # concatenate all fields user might want to search
+  def PrincipiaSearchSource(self):
+    return self.title + ' ' + self.description \
+         + self.latin_name + ' ' + self.environment
+
+However, you have to search this all at once--you can't opt to
+search just 'title' and 'latin_name', unless you created separate
+indexes for these fields.  Creating separate indexes for these
+fields is a waste of space and memory, though, as the same
+information is indexed several times.
+
+With FieldedTextIndex, your 'PrincipiaSearchSource' method would
+look like this::
+
+  # return all fields user might want to search
+  def PrincipiaSearchSource(self):
+    return { 'title':self.title,
+             'description':self.description,
+             'latin_name':self.latin_name,
+             'environment':self.environment }
+
+This index can be searched with the normal methods::
+
+  # search like a normal index
+  zcat=context.AnimalCatalog
+  results=zcat({'PrincipiaSearchSource':'jungle'})
+
+In addition, it can be searched indicating which fields you want
+to search::
+
+  # search only specific fields
+  zcat=context.AnimalCatalog
+  results=zcat(
+    {'PrincipiaSearchSource':'query':'jungle',
+                             'fields':['title','latin_name']})
+
+In this second example, only 'title' and 'latin_name' will be
+searched.
+
+In addition, FieldedTextIndexes support *weighing*, so that
+different fields "weigh" more in the query weigh, and a match in
+that field influences the results so that it appears earlier in the
+result list.  For example, in our zoo, matching part of an animals
+'latin_name' should count very highly, matching part of the 
+'title' should count highly, and matching part of the description
+should count less so.
+
+We can specify the weighing like this::
+
+  # search with weighing
+  zcat=context.AnimalCatalog
+  results=zcat(
+    {'PrincipiaSearchSource':'query':'jungle',
+                             'field_weights':{
+                                     'latin_name':3,
+                                     'title':2,
+                                     'description':1 }})
+
+This is a *very* powerful feature for building a comprehensive
+search strategy for a site, since it lets us control the results to
+better give the user what they probaby want, rather than returning
+documents based solely on how many times their search word appears.
+
+The examples given here are for searching a FieldedIndex using
+PythonScripts, however they can be searched directly from the
+REQUEST in a form like other fields.
+
+Since a FieldedTextIndex can act just like a normal ZCTextIndex if
+queried with just a search string, yet offer additional features
+above and beyond the normal ZCTextIndex, it's a good idea to use
+this for any text index where you'd concatenate more than one
+attribute or method result together, such as for 'SearchableText'
+or 'PrincipiaSearchSource'.
+
+FieldedTextIndex can be downloaded at
+http://zope.org/Members/Caseman/FieldedTextIndex.
+Full documentation on how to create this type of index, and further
+information on how to search it, including how to search it from
+web forms, is available in the README file that comes with this
+product.
+
+Conclusion
+----------
+
+The cataloging features of ZCatalog allow you to search your objects
+for certain attributes very quickly.  This can be very useful for sites
+with lots of content that many people need to be able to search in an
+efficient manner.
+
+Searching the ZCatalog works a lot like searching a relational
+database, except that the searching is more object-oriented.  Not all
+data models are object-oriented however, so in some cases you will want
+to use the ZCatalog, but in other cases you may want to use a
+relational database.  The next chapter goes into more details about how
+Zope works with relational databases, and how you can use relational
+data as objects in Zope.

Copied: zope2docs/branches/baijum-reorganize/zope2book/Security.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/Security.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/Security.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/Security.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,1365 @@
+Users and Security
+==================
+
+Introduction to Zope Security
+-----------------------------
+
+Zope is a multi-user system. However, instead of relying upon the
+user accounts provided by the operating system under which it runs,
+Zope maintains one or more of its own user databases.  It is not
+necessary to create a user account on the operating system under
+which Zope runs in order to grant someone a user account which they
+may use to access your Zope application or manage Zope via its
+management interface.
+
+It is important to note that Zope users do not have any of the
+privileges of a "normal" user on your computer's operating system.
+For instance, they do not possess the privilege to change arbitrary
+files on your computer's filesystem.  Typically, a Zope user may
+influence the content of databases that are connected to Zope may
+execute scripts (or other "logic" objects) based on Zope's
+security-restricted execution environment.  It is also possible to
+allow users to create their own scripts and content "through the
+web" by giving them access to the Zope Management Interface.
+However, you can restrict the capability of a user or a class of
+users to whatever suits your goals.  The important concept to absorb
+is that Zope's security is entirely divorced from the operating
+system upon which it runs.
+
+In Zope, users have only the capabilities granted to them by a Zope
+*security policy*.  As the administrator of a Zope system, you have
+the power to change your Zope system's security policies to whatever
+suits your business requirements.
+
+Furthermore, using security policies you can provide the capability
+to "safely" *delegate* capabilities to users defined within
+different parts of a Zope site.  "Safe delegation" is one of the
+important and differentiating features of Zope.  It is possible to
+grant users the capability in a Zope site to administer users and
+create scripts and content via the Zope Management Interface.  This
+is called "safe" delegation because it is relatively "safe" to grant
+users these kinds of capabilities within a particular portion of a
+Zope site, as it does not compromise operating system security nor
+Zope security in other portions of the site.  Caveats to safe
+delegation pertain to denial of service and resource exhaustion (it
+is not possible to control a user's resource consumption with any
+true measure of success within Zope), but it is possible to delegate
+these capabilities to "semi-trusted" users in order to decentralize
+control of a website, allowing it to grow faster and require less
+oversight from a central source.
+
+In this chapter we will look more closely at administering users,
+building roles, mapping roles to permissions, and creating a
+security policy for your Zope site.
+
+Review:  Logging In and Logging Out of the Zope Management Interface
+--------------------------------------------------------------------
+
+As we first saw in the chapter entitled `Installing Zope
+<InstallingZope.html>`_ , you may log into the Zope Management
+Interface by visiting a "management" URL in your web browser,
+entering a username and password when prompted. We also pointed
+out in `Using the Zope Management Interface <UsingZope.html>`_ that
+due to the way many web browsers work, you often must perform an
+extra step when an authentication dialog is raised or you must
+quit your browser to log out of Zope.  Review these chapters for
+more information about the basics of logging in and out of the
+Zope Management Interface.
+
+Zope's "Stock" Security Setup
+-----------------------------
+
+"Out of the box", a vanilla Zope site has two different classes of
+users: *Managers* and *Anonymous* users.  You have already seen
+via the `Installing Zope`_ chapter how you can
+log into the Zope management interface with the "initial" user
+called "admin".  The initial "admin" user is a user with the
+*Manager* role, which allows him to perform almost any duty that
+can be performed within a Zope instance.
+
+By default, in the "stock" Zope setup, Managers have the rights to
+alter Zope content and logic objects and view the management
+interface, while the Anonymous users are only permitted to view
+rendered content. This may be sufficient for many simple websites
+and applications, especially "public-facing" sites which have no
+requirement for users to "log in" or compose their own content.
+
+Identification and Authentication
+---------------------------------
+
+When a user accesses a protected resource (for example, by attempting to view a
+"protected" Page Template) Zope will ask the user to log in by presenting an
+authentication dialog. Once the dialog has been "filled out" and submitted,
+Zope will look for the user account represented by this set of credentials. By
+default Zope uses HTTP basic authentication. A cookie-based authentication can
+be implemented by adding a CookieCrumbler to the site's base folder.
+
+Zope *identifies* a user by examining the username and password
+provided during the entry into the authentication dialog.  If Zope
+finds a user within one of its user databases with the username
+provided, the user is identified.
+
+Once a user has been identified, *authentication* may or may not
+happen.  Authentication succeeds if the password provided by the
+user in the dialog matches the password registered for that user
+in the database.
+
+Zope will only attempt to identify and authenticate a user if he
+attempts to perform an action against Zope which an anonymous user
+has not been permitted the capability to perform; if a user never
+attempts to access a protected resource, Zope will continue to
+treat the user as an anonymous user.
+
+Zope prompts a user for authentication if the user attempts to
+access a "protected" resource without an adequate set of
+credentials, as determined by the resource's security policy.  For
+example, if a user attempts to access a method of an object which
+has a restrictive security policy (like all of Zope's management
+interface methods) the user will be prompted for authentication if
+he is not logged in.  You've seen this behavior already if you've
+ever attempted to log in to Zope and have been asked for a
+username and password to access the ZMI.  The ZMI is an example of
+a Zope application.  Zope's security machinery performs security
+checks on behalf of the ZMI; it "pops up" an authentication dialog
+requesting that the user enter a username and password.
+
+Different things can happen with respect to being prompted for
+authentication credentials in response to a request for a protected
+resource depending on the current state of a login session.  If
+the user has not not yet logged in, Zope will prompt the user for
+a username and password.  If the user is logged in but the account
+under which he is logged in does not have sufficient privilege to
+perform the action he has requested, Zope will prompt him for a
+*different* username and password.  If he is logged in and the
+account under which he has logged in *does* have sufficient
+privileges to perform the requested action, the action will be
+performed.  If a user cannot be authenticated because he provides
+a nonexistent username or an incorrect password to an existing
+authentication dialog, Zope re-prompts the user for authentication
+information as necessary until the user either "gets it right" or
+gives up.
+
+In general, there is no need for a user to log in to Zope if he
+only wishes to use public resources.  For example, to view the
+parts of your Zope website that are publically available, a user
+should not need to log in.
+
+Authorization, Roles, and Permissions
+-------------------------------------
+
+Once a user has been authenticated, Zope determines whether or not
+he has access to the resource which is being protected. This
+process is called *authorization*.  Remember that the only reason
+that Zope asked for credentials is because the user was attempting
+to view a resource which was not viewable by an anonymous user.
+The "resource which is being protected" referred to above is the
+object which the user requested to perform an action against,
+which caused the authentication process to begin.
+
+The process of authorization involves two intermediary layers
+between the user and the protected resource: *roles* and
+*permissions*.
+
+Users have *roles* which describe "what they can do" such as
+"Author", "Manager", and "Editor".  These roles are controlled by
+the Zope system administrator.  Users may have more than one role,
+and may have a different set of roles in different contexts.  Zope
+objects have permissions which describe "what can be done with
+them" such as "View", "Delete objects", and "Manage properties".
+These permissions are defined either within Zope itself or by Zope
+*Products*, each of which may define its own set of permissions.
+
+A *context* in Zope is a "place" within the Zope object hierarchy.
+In relation to security, a context is an object that has a
+location within the Zope Object Database.  For example, a
+description of a context could be expressed as "a folder object named zoo'
+within the Zope root object". In essence, a context can be thought of as an
+object's "location" within the Zope Object Database, described by
+its "path".  Each object that exists in the Zope Object Database
+which has a web-manageable interface can be associated with its
+own security policy.  Objects can also "acquire" security policies
+from containing objects in order to ease the burden of creating a
+security policy.  In fact, most Zope objects acquire their
+security policies from their containers because it makes a given
+security policy easier to maintain.  Only when there are
+exceptions to the "master" security policy in a context are
+individual objects associated with a differing policy.
+
+In essence, *security policies map roles to permissions in a
+context*; in other words they say "who" can do "what", and
+"where". For example, the security policy for a Folder (the
+context) may associate the "Manager" role (the roles) with the
+"Delete objects" permission (the permissions). Thus, this security
+policy allows managers to delete objects in this folder.  If
+objects created within this folder do not override their parents'
+security policy, they acquire this policy.  So, for example, if a
+Page Template is created within this folder, it may also be deleted
+by users with the Manager role.  Subobjects within subfolders of
+the original folder have the same policy unless they override it
+themselves, ad infinitum.
+
+Managing Users
+--------------
+
+In the chapter entitled `Installing Zope`_, you
+were provided with an "initial" account named 'admin', which
+possesses the 'Manager' role, allowing you to manage the objects
+in your Zope instance.  To allow other people to log into Zope,
+and to further understand Zope security, you should create user
+accounts under which different users may authenticate.
+
+Creating Users in User Folders
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A Zope *User* object defines a user account. A Zope *User* has a
+name, a password, one or more *roles*, and various other
+properties.  Roles are granted to a user in order to make it
+easier to control the scope of what he or she may do within a
+Zope site.
+
+To create user accounts in Zope, you create users within *User
+Folders*.  A user folder contains user objects that define Zope
+user accounts.  User Folder objects always have a Zope "id" of
+'acl_users'.  More than one user folder can exist within a Zope
+instance, but more than one user folder may not exist within the
+*same* Zope Folder.
+
+To create a new account, visit the root Zope folder. Click on
+the object named *acl_users*.  Click the *Add* button to create
+a new user.
+
+.. figure:: Figures/6-1.png
+
+   Adding a user to a user folder
+
+The form shown above lets you define the user. Type a username
+in the *Name* field (for example, "bob").  The username can
+contain letters, spaces, and numbers. The username is case
+sensitive.  Choose a password for your new user and enter it in
+the *Password* and *(Confirm)* fields.  In the next section, we
+will provide information about allowing a user to change his or
+her own password.
+
+The *Domains* field lets you restrict Internet domains from
+which the user can log in. This allows you to add another safety
+control to your account. For example if you always want your a
+user to log in from work you could enter your work's Internet
+domain name, for example "myjob.com", in the Domains field. You
+can specify multiple domains separated by spaces to allow the
+user to log in from multiple domains. For example if you decide
+that your coworker should be able to manage Zope from their home
+account too, you could set the domains to "myjob.com
+myhome.net". You can also use IP numbers with asterisks to
+indicate wildcard names instead of domain names to specify
+domains. For example, "209.67.167.*" will match all IP addresses
+that start with "209.67.167".
+
+The *Roles* multiple select list indicates which roles the user
+should have.  The Zope default roles include *Manager* and
+*Owner*.  In general users who need to perform management tasks
+using the Zope Management Interface should be given the
+*Manager* role.  The *Owner* role is not appropriate to grant in
+most cases because a user normally only has the Owner role in
+the context of a specific object. Granting the Owner role to a
+user in the User Folder management interface grants that user
+ownership of all objects within the folder in which the user
+folder is placed as well as all subfolders and subobjects of
+that folder.  It is unfortunate that the Owner role is present
+in the list of roles to choose from in the User Folder
+management interface, as it is confusing, little-used, and only
+now exists to service backwards compatibility.  In most cases it
+can be ignored completely.
+
+You may define your own roles such as *Editor* and *Reviewer*.
+In the section later in this chapter named "Defining Roles", we
+will create a new set of roles.  For now, we will work with the
+"stock" Zope roles.
+
+To create the new user click the *Add* button. You should see a
+new user object in the user folder.
+
+Zope User accounts defined in the "stock" user folder
+implementation do not support additional properties like
+email addresses and phone numbers.  For support of properties
+like these, you will have to use external User products like the
+CMF Membership Component (in the `CMF <http://cmf.zope.org>`_).
+
+Users can not be copied and pasted between User Folders.  The
+facility does not exist to perform this.
+
+Editing Users
+~~~~~~~~~~~~~
+
+You can edit existing users by clicking on their name within the
+User Folder management interface screen. Performing this action
+causes a form to be displayed which is very similar to the form
+you used to create a user. In fact, you may control most of the
+same settings that we detailed in the "Adding Users" section
+from within this form.  It is possible to visit this management
+screen and change a user's password, his roles, and his domain
+settings.  In the "stock" user folder implementation, you cannot
+change a user's name, however, so you will need to delete and
+recreate a user if you need to change his name.
+
+It is not possible for someone to find out a user's password by
+using the management interface.  Another manager may have access
+to *change* another user's password, but he may not find out
+what the current password is from within the management
+interface.  If a user's password is lost, it is lost forever.
+
+Like all Zope management functions, editing users is protected
+by the security policy. Users can only change their password if
+they have the *Manage Users* permission in the context of their
+own user folder, which managers have by default.  It is often
+desirable to allow users to change their own passwords.  One
+problem is that by giving a user the *Manage Users* permission,
+they are also able to edit other user accounts and add/delete
+users.  This may or may not be what you want.  
+
+To grant the capability for users to change their own passwords
+without being able to influence other users' information, set up
+a script with *Proxy Roles* to do the work for you after reading
+the section within this chapter entitled "Proxy Roles".
+
+In general, user folders work like normal Zope folders; you can
+create, edit and delete contained objects. However, user folders
+are not as capable as normal folders. You cannot cut and paste
+users in a user folder, and you can't create anything besides a
+user in a user folder.
+
+To delete an existing user from a user folder, select the user and
+click the *Delete* button. 
+
+Defining a User's Location
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Zope can contain multiple user folders at different locations in
+the object database hierarchy. A Zope user cannot access
+protected resources above the user folder in which their account
+is defined.  The location of a user's account information
+determines the scope of the user's access.
+
+If an account is defined in a user folder within the root
+folder, the user may access protected objects defined within the
+root folder. This is probably where the account you are using
+right now is defined.  You can however, create user folders
+within any Zope folder.  If a user folder is defined in a
+subfolder, the user may only access protected resources within
+that subfolder and within subfolders of that subfolder, and so
+on.  
+
+Consider the case of a user folder at
+*/BeautySchool/Hair/acl_users*. Suppose the user *Ralph
+Scissorhands* is defined in this user folder.  Ralph cannot
+access protected Zope resources above the folder at
+*/BeautySchool/Hair*. Effectively Ralph's view of protected
+resources in the Zope site is limited to things in the
+*BeautySchool/Hair* folder and below. Regardless of the roles
+assigned to Ralph, he cannot access protected resources "above"
+his location.  If Ralph was defined as having the 'Manager'
+role, he would be able to go directly to
+/BeautySchool/Hair/manage to manage his resources, but could not
+access /BeautySchool/manage at all.
+
+To access the Zope Management Interface as Manager user who is
+*not* defined in the "root" user folder, use the URL to the
+folder which contains his user folder plus 'manage'.  For
+example, if Ralph Scissorhands above has the Manager role as
+defined within a user folder in the *BeautySchool/Hair* folder,
+he would be able to access the Zope Management Interface by
+visiting 'http://zopeserver/BeautySchool/Hair/manage'.
+
+Of course, any user may access any resource which is *not*
+protected, so a user's creation location is not at all relevant
+with respect to unprotected resources.  The user's location only
+matters when he attempts to use objects in a way that requires
+authentication and authorization, such as the objects which
+compose the Zope Management Interface.
+
+It is straightforward to delegate responsibilities to site
+managers using this technique. One of the most common Zope
+management patterns is to place related objects in a folder
+together and then create a user folder in that folder to define
+people who are responsible for those objects.  By doing so, you
+"safely" *delegate* the responsibility for these objects to
+these users.
+
+For example, suppose people in your organization wear
+uniforms. You are creating an intranet that provides information
+about your organization, including information about
+uniforms. You might create a 'uniforms' folder somewhere in the
+intranet Zope site. In that folder you could put objects such as
+pictures of uniforms and descriptions for how to wear and clean
+them.  Then you could create a user folder in the 'uniforms'
+folder and create an account for the head tailor. When a new
+style of uniform comes out the tailor doesn't have to ask the
+web master to update the site, he or she can update their own
+section of the site without bothering anyone else.
+Additionally, the head tailor cannot log into any folder above
+the 'uniforms' folder, which means the head tailor cannot manage
+any objects other than those in the 'uniforms' folder.
+
+*Delegation* is a very common pattern in Zope applications. By
+delegating different areas of your Zope site to different users,
+you can take the burden of site administration off of a small
+group of managers and spread that burden around to different
+specific groups of users.
+
+Working with Alternative User Folders  
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It may be that you don't want to manage your user account through the web using
+Zope's "stock" user folder implementation. Perhaps you already have a user
+database, or perhaps you want to use other tools to maintain your account
+information. Zope allows you to use alternate sources of data as user
+information repositories. The most popular user folder implementation is called
+`PluggableAuthService`_ which allows you to mix-in and combine a vast number of
+different authentication schemes and backends, like LDAP or MySQL.
+
+.. _PluggableAuthService: http://pypi.python.org/pypi/Products.PluggableAuthService
+
+Some user folders provide alternate login and logout controls in
+the form of web pages, rather than relying on Basic HTTP
+Authentication controls. Despite this variety, all user folders
+use the same general log in procedure of prompting you for
+credentials when you access a protected resource.
+
+While most users are managed with user folders of one kind or
+another, Zope has a few special user accounts that are not
+managed with user folder.
+
+Special User Accounts
+~~~~~~~~~~~~~~~~~~~~~
+
+Zope provides three special user accounts which are not defined
+with user folders, the *anonymous user*, the *emergency user*,
+and the *initial manager*. The anonymous user is used
+frequently, while the emergency user and initial manager
+accounts are rarely used but are important to know about.
+
+Zope Anonymous User
+%%%%%%%%%%%%%%%%%%%
+
+Zope has a built-in user account for "guests" who possess no
+credentials.  This is the 'Anonymous' user. If you don't have
+a user account on Zope, you'll be considered to be the
+'Anonymous' user.
+
+The 'Anonymous' *user* additionally possesses the 'Anonymous'
+*role*. The "stock" Zope security policy restricts users which
+possess the 'Anonymous' role from accessing nonpublic
+resources. You can tailor this policy, but most of the time
+you'll find the default anonymous security settings adequate.
+
+As we mentioned earlier in the chapter, you must try to access
+a protected resource in order for Zope to attempt
+authentication.  Even if you've got a user account on the
+system, Zope will consider you the 'Anonymous' user until you
+been prompted for login and you've successfully logged in.
+
+Zope Emergency User
+%%%%%%%%%%%%%%%%%%%
+
+Zope has a special user account for emergency use known as the
+*emergency user*. The emergency user is not restricted
+by normal security settings. However, the emergency user
+cannot create any new objects with the exception of new user
+objects.
+
+The emergency user is typically only useful for two things:
+fixing broken permissions, and creating and changing user
+accounts.
+
+You may use the emergency user account to create or change
+other user accounts.  Typically, you use the emergency user
+account to define accounts with the 'Manager' role or change
+the password of an existing account which already possesses
+the 'Manager' role.  This is useful in case you lose your
+management user password or username.  Typically, after you
+create or change an existing a manager account you will log
+out as the emergency user and log back in as the manager.
+
+Another reason to use the emergency user account is to "fix"
+broken permissions.  If you lock yourself out of Zope by
+removing permissions you need to manage Zope, you can use the
+emergency user account to repair the permissions. In this case
+log in as the emergency user and make sure that your manager
+account has the 'View management screens' and 'Change
+permissions' permissions with respect to the object you're
+attempting to view. Then log out and log back with your
+manager account and you should have enough access to fix
+anything else that is broken.
+
+The emergency user cannot create new "content", "logic" or
+"presentation" objects.  A common error message seen by users
+attempting to use the emergency user account in trying to
+create a new object is shown below.
+
+.. figure:: Figures/6-2.png
+
+   Error caused by trying to create a new object when logged in
+   as the emergency user
+
+The error above lets you know that the emergency user cannot
+create new objects. This is "by design", and the reasoning
+behind this policy may become clearer later in the chapter
+when we cover ownership.  
+
+Creating an Emergency User
+%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Unlike normal user accounts that are defined through the Zope
+Management Interface, the emergency user account is defined
+through a file in the filesystem. You can change the emergency
+user account by editing or generating the file named 'access'
+in the Zope home directory (the main Zope directory). Zope
+comes with a command line utility in the Zope home directory
+named 'zpasswd.py' to manage the emergency user account.  On
+UNIX, run 'zpasswd.py' by passing it the 'access' file path as
+its only argument::
+
+  $ cd (... where your ZOPE_HOME is... )
+  $ python zpasswd.py access
+
+  Username: superuser
+  Password:
+  Verify password:
+
+  Please choose a format from:
+
+  SHA - SHA-1 hashed password
+  CRYPT - UNIX-style crypt password
+  CLEARTEXT - no protection.
+
+  Encoding: SHA
+  Domain restrictions:         
+
+Due to pathing differences, Windows users usually need to
+enter this into a command prompt to invoke zpasswd::
+
+  > cd (... where your ZOPE_HOME is ...)
+  > cd bin
+  > python ..\zpasswd.py ..\access
+
+The 'zpasswd.py' script steps you through the process of
+creating an emergency user account. Note that when you type in
+your password it is not echoed to the screen. You can also run
+'zpasswd.py' with no arguments to get a list of command line
+options.  When setting up or changing the emergency user's
+details, you need to restart the Zope process for your changes
+to come into effect.
+
+Zope Initial Manager
+%%%%%%%%%%%%%%%%%%%%
+
+The initial manager account is created by the Zope installer
+so you can log into Zope the first time. When you first
+install Zope you should see a message like this::
+
+  creating default inituser file
+  Note:
+          The initial user name and password are 'admin'
+          and 'IVX3kAwU'.
+
+          You can change the name and password through the web
+          interface or using the 'zpasswd.py' script.
+
+This lets you know the initial manager's name and
+password. You can use this information to log in to Zope for
+the first time as a manager. 
+
+Initial users are defined in a similar way to the emergency
+user; they are defined in a file on the filesystem named
+'inituser'.  On UNIX, the 'zpasswd.py' program can be used to
+edit or generate this file the same way it is used to edit or
+generate the emergency user 'access' file::
+
+  $ cd ( ... were your ZOPE_HOME is ... )
+  $ python zpasswd.py inituser
+
+  Username: bob
+  Password:
+  Verify password:
+
+  Please choose a format from:
+
+  SHA - SHA-1 hashed password
+  CRYPT - UNIX-style crypt password
+  CLEARTEXT - no protection.
+
+  Encoding: SHA
+  Domain restrictions:    
+
+This will create an 'inituser' file which contains a user
+named "bob" and will set its password.  The password is not
+echoed back to you when you type it in.  The effect of
+creating an 'inituser' file depends on the state of the
+existing Zope database.
+
+When Zope starts up, if there are *no* users in the root user
+folder (such as when you start Zope with a "fresh" ZODB
+database), and an 'inituser' file exists, the user defined
+within 'inituser' will be created within the root user folder.
+If any users already exist within the root user folder, the
+existence of the 'inituser' file has no effect.  Normally,
+initial users are created by the Zope installer for you, and
+you shouldn't have to worry about changing them.  Only in
+cases where you start a new Zope database (for example, if you
+delete the 'var/Data.fs' file) should you need to worry about
+creating an 'inituser' file.  Note that if Zope is being used
+in an INSTANCE_HOME setup, the created "inituser" file must be
+copied to the INSTANCE_HOME directory. Most Zope setups are
+not INSTANCE_HOME setups (unless you've explicitly made it
+so), so you typically don't need to worry about this.  The
+'inituser' feature is a convenience and is rarely used in
+practice except by the installer.
+
+Protecting Against Password Snooping
+------------------------------------
+
+The HTTP Basic Authentication protocol that Zope uses as part of
+its "stock" user folder implementation passes login information
+"over the wire" in an easily decryptable way.  It is employed,
+however, because it has the widest browser support of any
+available authentication mechanism.
+
+If you're worried about someone "snooping" your username/password
+combinations, or you wish to manage your Zope site ultra-securely,
+you should manage your Zope site via an SSL (Secured Sockets
+Layer) connection.  The easiest way to do this is to use Apache or
+another webserver which comes with SSL support and put it "in
+front" of Zope. The chapter of this book entitled
+`Virtual Hosting <VirtualHosting.html>`_ provides some background that may be
+helpful to set up an SSL server in front of Zope.
+
+Managing Custom Security Policies
+---------------------------------
+
+Zope security policies control authorization; they define *who*
+can do *what* and *where* they can do it. Security policies
+describe how roles are associated with permissions in the context
+of a particular object. Roles label classes of users, and
+permissions protect objects. Thus, security policies define which
+classes of users (roles) can take what kinds of actions
+(permissions) in a given part of the site.
+
+Rather than stating which specific user can take which specific
+action on which specific object, Zope allows you to define which
+kinds of users can take which kinds of action in which areas of
+the site. This sort of generalization makes your security policies
+simple and more powerful. Of course, you can make exceptions to
+your policy for specific users, actions, and objects.
+
+Working with Roles
+~~~~~~~~~~~~~~~~~~
+
+Zope users have *roles* that define what kinds of actions they
+can take. Roles define classes of users such as *Manager*,
+*Anonymous*, and *Authenticated*.
+
+Roles are similar to UNIX groups in that they abstract groups of
+users. And like UNIX groups, each Zope user can have one or more
+roles.
+
+Roles make it easier for administrators to manage
+security. Instead of forcing an administrator to specifically
+define the actions allowed by each user in a context, the
+administrator can define different security policies for
+different user roles in a context.  Since roles are classes of
+users, he needn't associate the policy directly with a user.
+Instead, he may associate the policy with one of the user's
+roles.
+
+Zope comes with four built-in roles:
+
+Manager
+  This role is used for users who perform standard Zope
+  management functions such as creating and edit Zope folders and
+  documents.
+
+Anonymous
+  The Zope 'Anonymous' user has this role. This
+  role should be authorized to view public resources. In general
+  this role should not be allowed to change Zope objects.
+
+Owner
+  This role is assigned automatically to users in the
+  context of objects they create. We'll cover ownership later in
+  this chapter.
+
+Authenticated
+  This role is assigned automatically to users
+  whom have provided valid authentication credentials.  This
+  role means that Zope "knows" who a particular user is. When
+  Users are logged in they are considered to also have the
+  Authenticated role, regardless of other roles.
+
+For basic Zope sites you can typically "get by" with only having
+'Manager' and 'Anonymous' roles. For more complex sites you may
+want to create your own roles to classify your users into
+different categories.
+
+Defining Global Roles
+~~~~~~~~~~~~~~~~~~~~~
+
+A "global" role is one that shows up in the "roles" column of
+the 'Security' tab of your Zope objects.  To create a new
+"global" role go to the *Security* tab of your root Zope object
+(or any other 'folderish' Zope object) and scroll down to the
+bottom of the screen. Type the name of the new role in the *User
+defined role* field, and click *Add Role*. Role names should be
+short one or two word descriptions of a type of user such as
+"Author", "Site Architect", or "Designer". You should pick role
+names that are relevant to your application.
+
+You can verify that your role was created, noticing that there
+is now a role column for your new role at the top of the screen.
+You can delete a role by selecting the role from the select list
+at the bottom of the security screen and clicking the *Delete
+Role* button.  You can only delete your own custom roles, you
+cannot delete any of the "stock" roles that come with Zope.
+
+You should notice that roles can be used at the level at which
+they are defined and "below" in the object hierarchy.  For
+example, if you create a role in a 'myfolder' folder that
+exists in the Zope root folder, that role cannot be used outside
+of the 'myfolder' folder and any of its subfolders and
+subobjects.  If you want to create a role that is appropriate
+for your entire site, create it in the root folder.
+
+In general, roles should be applicable for large sections of
+your site. If you find yourself creating roles to *limit* access
+to parts of your site, chances are there are better ways to
+accomplish the same thing. For example you could simply change
+the security settings for existing roles on the folder you want
+to protect, or you could define users deeper in the object
+hierarchy to limit their access. 
+
+Understanding Local Roles
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+*Local roles* are an advanced feature of Zope security.
+Specific *users* can be granted extra roles when working within
+the context of a certain object by using a local role.  If an
+object has local roles associated with a user then that user
+gets those additional roles while working with that object,
+without needing to reauthenticate.
+
+For example, if a user creates an object using the Zope
+Management Interface, they are always given the additional local
+role of *Owner* in the context of that object. A user might not
+have the ability to edit Page Templates in general if he does not
+possess a set of global roles which allow him to do so, but for
+Page Templates he owns, the user may edit the Page Template by
+virtue of possessing the *Owner* local role.
+
+Local roles are a fairly advanced security control. Zope's
+automatic control of the *Owner* local role is likely the only
+place you'll encounter local roles unless you create an
+application which makes use of them.  The main reason you might
+want to manually control local roles is to give a specific user
+special access to an object. In general you should avoid setting
+security for specific users if possible. It is easier to manage
+security settings that control groups of users instead of
+individuals.
+
+Understanding Permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A permission defines a single action which can be taken upon a
+Zope object. Just as roles abstract users, permissions abstract
+objects. For example, many Zope objects, including Page Templates
+and Folders, can be viewed. This action is protected by
+the *View* permission.  Permissions are defined by Zope
+developers in Python packages and the Zope "core" itself. Packages are
+responsible for creating a set of permissions which are relevant
+to the types of objects they expose.
+
+Some permissions are only relevant for one type of object.
+Other permissions protect many types of objects, such
+as the *FTP access* and *WebDAV access* permissions which
+control whether objects are available via FTP and WebDAV.
+
+You can find out what permissions are available on a given object
+by going to the *Security* management tab.
+
+The default Zope permissions are described in `appendix A
+<http://www.zope.org/Documentation/Books/ZDG/current/AppendixA.stx>`_
+of the Zope Developer's Guide.
+
+.. figure:: Figures/6-3.png     
+
+   Security settings for a mail host object
+
+As you can see in the figure above, a mail host has a limited
+palette of permissions available. Contrast this to the many
+permissions that you see when setting security on a folder.
+
+Defining Security Policies
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Security policies are where roles meet permissions. Security
+policies define "who" can do "what" in a given part of the site.
+
+You can set a security policy on almost any Zope object. To set
+a security policy on an object, go the object's *Security* tab.
+For example, click on the security tab of the root folder.
+
+.. figure:: Figures/6-4.png
+
+   Security policy for the root folder
+
+In the figure above, the center of the screen displays a grid of
+check boxes. The vertical columns of the grid represent roles,
+and the horizontal rows of the grid represent permissions.
+Checking the box at the intersection of a permission and a role
+grants users with that role the ability to take actions
+protected by that permission in the context of the object being
+managed.  In this case, the context is the root folder.
+
+Many Zope Products add custom security permissions to your site
+when you install them.  This can make the permissions list grow
+quite large, and unwieldy.  Product authors should take care to
+re-use suitable existing permissions if possible, but many times
+it's not possible, so the permission list grows with each new
+Product that is installed.
+
+You'll notice by virtue of visiting the Security tab of the root
+folder that Zope comes with a default security policy that
+allows users which possess the 'Manager' role to perform most
+tasks, and that allows anonymous users to perform only a few
+restricted tasks.  The simplest (and most effective) way to
+tailor this policy to suit your needs is to change the security
+settings in the root folder.
+
+For example, you can make your site almost completely "private"
+by disallowing anonymous users the ability to view objects. To
+do this deny all anonymous users View access by unchecking the
+*View* Permission where it intersects the *Anonymous* role.  You
+can make your entire site private by making this security policy
+change in the root folder. If you want to make one part of your
+site private, you could make this change in the folder you want
+to make private.
+
+This example points out a very important point about security
+policies: they control security for a given part of the site
+only. The only global security policy is the one on the root
+folder.
+
+Security Policy Acquisition
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+How do different security policies interact? We've seen that you
+can create security policies on different objects, but what
+determines which policies control which objects? The answer is
+that objects use their own policy if they have one, additionally
+they acquire their parents' security policies through a process
+called *acquisition*.  We explored acquisition in the
+`Acquisition <Acquisition.html>`_ chapter.  Zope security makes
+extensive use of acquisition.
+
+Acquisition is a mechanism in Zope for sharing information among
+objects contained in a folder and its subfolders. The Zope
+security system uses acquisition to share security policies so
+that access can be controlled from high-level folders.
+
+You can control security policy acquisition from the
+*Security* tab.  Notice that there is a column of check boxes
+to the left of the screen labeled *Acquire permission
+settings*. Every check box in this column is checked by
+default. This means that security policy will acquire its
+parent's setting for each permission to role setting in
+addition to any settings specified on this screen.  Keep in mind
+that for the root folder (which has no parent to acquire from)
+this left most check box column does not exist.
+
+Suppose you want to make a folder private. As we saw before this
+merely requires denying the *Anonymous* role the *View*
+permission in the context of this object. But even though the
+"View" permission's box may be unchecked the folder might not be
+private. Why is this?  The answer is that the *Acquire
+permission settings* option is checked for the View
+permission. This means that the current settings are augmented
+by the security policies of this folder's parents. Somewhere
+above this folder the *Anonymous* role must be assigned to the
+*View* permission. You can verify this by examining the security
+policies of this folder's parents. To make the folder private we
+must uncheck the *Acquire permission settings* option. This will
+ensure that only the settings explicitly in this security policy
+are in effect.
+
+Each checked checkbox gives a role permission to do an action or
+a set of actions. With 'Acquire permission settings' checked,
+these permissions are *added* to the actions allowed in the
+parent folder.  If 'Acquire permission settings' is unchecked on
+the other hand, checkboxes must be explicitly set, and the
+security setting of the parent folder will have no influence.
+
+In general, you should always acquire security settings unless
+you have a specific reason to not do so. This will make managing
+your security settings much easier as much of the work can be
+done from the root folder.
+
+Security Usage Patterns
+-----------------------
+
+The basic concepts of Zope security are simple: roles and
+permissions are mapped to one another to create security policies.
+Users are granted roles (either global roles or local roles).
+User actions are restricted by the roles they possess in the
+context of an object.  These simple tools can be put together in
+many different ways. This can make managing security
+complex. Let's look at some basic patterns for managing security
+that provide good examples of how to create an effective and easy
+to manage security architecture.
+
+Security Rules of Thumb
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Here are a few simple guidelines for Zope security
+management. The security patterns that follow offer more
+specific recipes, but these guidelines give you some guidance
+when you face uncharted territory.
+
+1. Define users at their highest level of control, but no higher.
+
+2. Group objects that should be managed by the same people
+   together in folders.
+
+3. Keep it simple.
+
+Rules one and two are closely related. Both are part of a more
+general rule for Zope site architecture. In general you should
+refactor your site to locate related resources and users near
+each other. Granted, it's almost never possible to force
+resources and users into a strict hierarchy. However, a well
+considered arrangement of resources and users into folders and
+sub-folders helps tremendously.
+
+Regardless of your site architecture, try to keep things
+simple. The more you complicate your security settings the
+harder time you'll have understanding it, managing it and making
+sure that it's effective. For example, limit the number of new
+roles you create, and try to use security policy acquisition to
+limit the number of places you have to explicitly define
+security settings. If you find that your security policies,
+users, and roles are growing into a complex thicket, you should
+rethink what you're doing; there's probably a simpler way.
+
+Global and Local Policies
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The most basic Zope security pattern is to define a global
+security policy on the root folder and acquire this policy
+everywhere. Then as needed you can add additional policies
+deeper in the object hierarchy to augment the global policy. Try
+to limit the number of places that you override the global
+policy. If you find that you have to make changes in a number of
+places, consider consolidating the objects in those separate
+locations into the same folder so that you can make the security
+settings in one place.
+
+You should choose to acquire permission settings in your
+sub-policies unless your sub-policy is more restrictive than the
+global policy. In this case you should uncheck this option for
+the permission that you want to restrict.
+
+This simple pattern will take care of much of your security
+needs. Its advantages are that it is easy to manage and easy to
+understand. These are extremely important characteristics for
+any security architecture.
+
+Delegating Control to Local Managers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The pattern of *delegation* is very central to Zope. Zope
+encourages you to collect like resources in folders together and
+then to create user accounts in these folders to manage their
+contents.
+
+Lets say you want to delegate the management of the *Sales*
+folder in your Zope site over to the new sales web manager,
+Steve.  First, you don't want Steve changing any objects which
+live outside the Sales folder, so you don't need to add him to
+the acl_users folder in the root folder.  Instead, you would
+create a new user folder in the *Sales* folder.
+
+Now you can add Steve to the user folder in *Sales* and give him the
+Role *Manager*.  Steve can now log directly into the Sales folder to
+manage his area of control by pointing his browser to
+*http://www.zopezoo.org/Sales/manage*.
+
+.. figure:: Figures/6-5.png
+
+   Managing the Sales folder
+
+Notice in the figure above that the navigation tree on the left
+shows that *Sales* is the root folder.  The local manager
+defined in this folder will never have the ability to log into
+any folders above *Sales*, so it is shown as the top folder.
+
+This pattern is very powerful since it can be applied
+recursively. For example, Steve can create a sub-folder for
+multi-level marketing sales. Then he can create a user folder in
+the multi-level marketing sales folder to delegate control of
+this folder to the multi-level marketing sales manager. And so
+on. This allows you to create websites managed by thousands of
+people without centralized control.  Higher level managers need
+not concern themselves too much with what their underlings
+do. If they choose they can pay close attention, but they can
+safely ignore the details since they know that their delegates
+cannot make any changes outside their area of control, and they
+know that their security settings will be acquired.
+
+Different Levels of Access with Roles
+-------------------------------------
+
+The local manager pattern is powerful and scalable, but it takes
+a rather coarse view of security. Either you have access or you
+don't. Sometimes you need to have more fine grained
+control. Many times you will have resources that need to be used
+by more than one type of person. Roles provides you with a
+solution to this problem. Roles allow you to define classes of
+users and set security policies for them.
+
+Before creating new roles make sure that you really need
+them. Suppose that you have a website that publishes
+articles. The public reads articles and managers edit and publish
+articles, but there is a third class of user who can author
+articles, but not publish or edit them.
+
+One solution would be to create an authors folder where author
+accounts are created and given the *Manager* role. This folder
+would be private so it could only be viewed by
+managers. Articles could be written in this folder and then
+managers could move the articles out of this folder to publish
+them. This is a reasonable solution, but it requires that
+authors work only in one part of the site and it requires extra
+work by managers to move articles out of the authors
+folder. Also, consider that problems that result when an author
+wants to update an article that has been moved out of the
+authors folder.
+
+A better solution is to add an *Author* role.  Adding a role
+helps us because it allows access controls not based on
+location. So in our example, by adding an author role we make it
+possible for articles to be written, edited, and published
+anywhere in the site. We can set a global security policy that
+gives authors the ability to create and write articles, but
+doesn't grant them permissions to publish or edit articles.
+
+Roles allow you to control access based on who a user is, not
+just where they are defined.
+
+Controlling Access to Locations with Roles
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Roles can help you overcome a problem with the
+local manager pattern. The problem is that the local manager
+pattern requires a strict hierarchy of control.  There is no
+provision to allow two different groups of people to access the
+same resources without one group being the manager of the other
+group. Put another way, there is no way for users defined in one
+part of the site to manage resources in another part of the
+site.
+
+Let's take an example to illustrate the second limitation of the
+local manager pattern. Suppose you run a large site for a
+pharmaceutical company. You have two classes of users,
+scientists and salespeople. In general the scientists and the
+salespeople manage different web resources.  However, suppose
+that there are some things that both types of people need to
+manage, such as advertisements that have to contain complex
+scientific warnings. If we define our scientists in the *Science*
+folder and the salespeople in the *Sales* folder, where should we
+put the *AdsWithComplexWarnings* folder? Unless the Science folder
+is inside the Sales folder or vice versa there is no place that
+we can put the *AdsWithComplexWarnings* folder so that both
+scientists and salespeople can manage it. It is not a good
+political or practical solution to have the salespeople manage
+the scientists or vice versa; what can be done?
+
+The solution is to use roles. You should create two roles at a
+level above both the Science and Sales folders, say *Scientist*,
+and *SalesPerson*. Then instead of defining the scientists and
+salespeople in their own folders define them higher in the
+object hierarchy so that they have access to the
+*AdsWithComplexWarnings* folder.
+
+When you create users at this higher level, you should not give them
+the *Manager* role, but instead give them Scientist or SalesPerson as
+appropriate. Then you should set the security policies using the 
+checkboxes in the Security panel.  On the
+*Science* folder the *Scientist* role should have the equivalent of
+*Manager* control. On the *Sales* folder, the *Salesperson* role
+should have the same permissions as *Manager*. Finally on the
+*AdsWithComplexWarnings* folder you should give both *Scientist* and
+*Salesperson* roles adequate permissions. This way roles are used not
+to provide different levels of access, but to provide access to
+different locations based on who you are.
+
+Another common situation when you might want to employ this
+pattern is when you cannot define your managers locally. For
+example, you may be using an alternate user folder that requires
+all users to be defined in the root folder. In this case you
+would want to make extensive use of roles to limit access to
+different locations based on roles.
+
+This wraps up our discussion of security patterns. By now you
+should have a reasonable grasp of how to use user folders,
+roles, and security policies, to shape a reasonable security
+architecture for your application.  Next we'll cover two
+advanced security issues, how to perform security checks, and
+securing executable content.
+
+Performing Security Checks
+--------------------------
+
+Most of the time when developing a Zope application, you needn't
+perform any "manual" security checks. The term for this type of
+security which does not require manual effort on the part of the
+application developer is "declarative".  Zope security is
+typically declarative.  If a user attempts to perform a secured
+operation, Zope will prompt them to log in. If the user doesn't
+have adequate permissions to access a protected resource, Zope
+will deny them access.
+
+However, sometimes you may wish to manually perform security
+checks. The main reason to do this is to limit the choices you
+offer a user to those for which they are authorized. This doesn't
+prevent a sneaky user from trying to access secured actions, but
+it does reduce user frustration, by not giving to user the option
+to try something that will not work.
+
+The most common security query asks whether the current user has a
+given permission. We use Zope's 'checkPermission' API to do this.
+For example, suppose your application allows some users to upload
+files. This action may be protected by the "Add Documents, Images,
+and Files" standard Zope permission. You can test to see if the
+current user has this permission in a Page Template::
+
+  <form action="upload" 
+    tal:condition="python:
+      modules['AccessControl'].getSecurityManager().checkPermission(
+         'Add / Documents, Images, and Files', context)">
+  ...
+  </form>
+
+A Python Script can be employed to perform the same task on behalf
+of a Page Template.  In the below example, we move the security
+check out of the Page Template and into a Python Script named
+'check_security', which we call from the Page Template.  Here is
+the Page template::
+
+  <form action="upload"
+        tal:condition="python: context.check_security(
+           'Add Documents, Images and Files', here)">
+
+Here is the 'check_security' Python Script which is referenced
+within the Page Template::
+
+  ## Script (Python) "check_security"
+  ##bind container=container
+  ##bind context=context
+  ##bind namespace=
+  ##bind script=script
+  ##bind subpath=traverse_subpath
+  ##parameters=permission, object
+  ##title=Checks security on behalf of a caller
+
+  from AccessControl import getSecurityManager
+  sec_mgr = getSecurityManager()
+  return sec_mgr.checkPermission(permission, object)
+
+You can see that permission checking may take place manually in
+any of Zope's logic objects.  Other functions exist in the Zope
+API for manually performing security checks, but 'checkPermission'
+is arguably the most useful.
+
+By passing the current object to 'checkPermission', we make sure
+that local roles are taken into account when testing whether the
+current user has a given permission.
+
+You can find out about the current user by accessing the user object. 
+The current user is a Zope object like any other and you can
+perform actions on it using methods defined in the API
+documentation.
+
+Suppose you wish to display the current user name on a web page to
+personalize the page. You can do this easily in Page Template::
+
+  <p tal:content="user/getUserName">username</p>
+
+The Zope security API for Scripts is explained in
+`Appendix B: API Reference <AppendixB.html>`_. The Zope security API for Page
+Templates is explained in
+`Appendix C: Zope Page Templates Reference <AppendixC.html>`_.
+
+Advanced Security Issues: Ownership and Executable Content
+----------------------------------------------------------
+
+You've now covered all the basics of Zope security. What remains
+are the advanced concepts of *ownership* and *executable
+content*. Zope uses ownership to associate objects with users who
+create them, and executable content refers to objects such as
+Scripts, which execute user code.
+
+For small sites with trusted users you can safely ignore these
+advanced issues. However for large sites where you allow untrusted
+users to create and manage Zope objects, it's important to
+understand ownership and securing executable content.
+
+The Problem: Trojan Horse Attacks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The basic scenario that motivates both ownership and executable
+content controls is a *Trojan horse* attack. A Trojan horse is
+an attack on a system that operates by tricking a user into
+taking a potentially harmful action. A typical Trojan horse
+masquerades as a benign program that causes harm when you
+unwittingly run it.
+
+All computer systems are vulnerable to this style of attack.
+For web-based platforms, all that is required is to trick an
+authorized, but unsuspecting user to visit a URL that performs a
+harmful action that the attacker himself is not authorized to
+perform.
+
+This kind of attack is very hard to protect against. You can
+trick someone into clicking a link fairly easily, or you can use
+more advanced techniques such as Javascript to cause a user to
+visit a malicious URL.
+
+Zope offers some protection from this kind of Trojan horse. Zope
+helps protect your site from server-side Trojan attacks by
+limiting the power of web resources based on who authored them.
+If an untrusted user authors a web page, then the power of the
+web pages to do harm to unsuspecting visitors will be
+limited. For example, suppose an untrusted user creates a
+Script (Python) that deletes all the pages in your
+site. If anyone attempt to view the page, it will fail since the
+owner of the object does not have adequate permissions. If a
+manager views the page, it will also fail, even though the
+manager does have adequate permissions to perform the dangerous
+action.
+
+Zope uses ownership information and executable content
+controls to provide this limited protection.
+
+Managing Ownership
+~~~~~~~~~~~~~~~~~~
+
+When a user creates a Zope object, the user *owns* that object.
+An object that has no owner is referred to as *unowned.*
+Ownership information is stored in the object itself.  This is
+similar to how UNIX keeps track of the owner of a file.
+
+You find out how an object is owned by viewing the *Ownership*
+management tab, as shown in the figure below.
+
+.. figure:: Figures/6-6.png
+
+   Managing ownership settings
+
+This screen tells you if the object is owned and if so by
+whom.  If the object is owned by someone else, and you have the
+*Take ownership* permission, you can take over the ownership of an
+object.  You also have the option of taking ownership of all
+sub-objects by checking the *Take ownership of all sub-objects* box.
+Taking ownership is mostly useful if the owner account has been
+deleted, or if objects have been turned over to you for
+continued management.
+
+As we mentioned earlier in the chapter, ownership affects
+security policies because users will have the local role *Owner*
+on objects they own. However, ownership also affects security
+because it controls the role's executable content.
+
+Note that due to the way Zope "grew up" that the list of users
+granted the Owner local role in the context of the object is
+*not* related to its actual "owner".  The concepts of the owner
+"role" and executable content ownership are distinct.  Just
+because someone has the Owner local role in the context of an
+executable object does not mean that he is the *owner* of the
+object.
+
+Roles of Executable Content
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Python-based Scripts are said to be *executable* since their content is
+generated dynamically. Their content is also editable through the web.
+
+When you view an executable object by visiting its URL or
+calling it from a script, Zope runs the object's
+executable content. The objects actions are restricted by the
+roles of its owner and your roles. In other words an executable
+object can only perform actions that *both* the owner and the
+viewer are authorized for. This keeps an unprivileged user from
+writing a harmful script and then tricking a powerful user into
+executing the script. You can't fool someone else into
+performing an action that you are not authorized to perform
+yourself. This is how Zope uses ownership to protect against
+server-side Trojan horse attacks.
+
+It is important to note that an "unowned" object is typically no
+longer executable.  If you experience problems running an
+executable object, make sure that its ownership settings are
+correct.
+
+Proxy Roles
+~~~~~~~~~~~
+
+Sometimes Zope's system of limiting access to executable objects
+isn't exactly what you want. Sometimes you may wish to clamp
+down security on an executable object despite its ownership as a
+form of extra security. Other times you may want to provide an
+executable object with extra access to allow an unprivileged
+viewer to perform protected actions. *Proxy roles* provide you
+with a way to tailor the roles of an executable object.
+
+Suppose you want to create a mail form that allows anonymous
+users to send email to the webmaster of your site. Sending email
+is protected by the 'Use mailhost services'
+permission. Anonymous users don't normally have this permission
+and for good reason. You don't want just anyone to be able to
+anonymously send email with your Zope server.
+
+The problem with this arrangement is that your Script (Python) that
+sends email will fail for anonymous users. How can you get
+around this problem? The answer is to set the proxy roles on the
+Script (Python) that sends email so that when it executes it has the
+"Manager" role. Visit the Proxy management tab on your Python
+script, as shown in the figure below.
+
+.. figure:: Figures/6-7.png
+
+   Proxy role management
+
+Select *Manager* and click the *Change* button. This will set
+the proxy roles of the mail sending method to *Manager*. Note
+you must have the *Manager* role yourself to set it as a proxy
+role. Now when anyone, anonymous or not runs your mail sending
+method, it will execute with the *Manager* role, and thus will
+have authorization to send email.
+
+Proxy roles define a fixed amount of permissions for executable
+content. Thus you can also use them to restrict security. For
+example, if you set the proxy roles of a script to *Anonymous*
+role, then the script will never execute as having any other
+roles besides *Anonymous* despite the roles of the owner and
+viewer.
+
+Use Proxy roles with care, since they can be used to skirt the
+default security restrictions.
+
+Summary
+-------
+
+Security consists of two processes, authentication and
+authorization. User folders control authentication, and security
+policies control authorization. Zope security is intimately tied
+with the concept of location; users have location, security
+policies have location, even roles can have location. Creating an
+effective security architecture requires attention to
+location. When in doubt refer to the security usage patterns
+discussed in this chapter.

Copied: zope2docs/branches/baijum-reorganize/zope2book/Sessions.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/Sessions.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/Sessions.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/Sessions.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,1435 @@
+Session Management
+##################
+
+This chapter describes Zope's built-in Session Management.
+
+Terminology
+===========
+
+Here's a mini-glossary of of key terms used within this document:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Web session
+  a series of HTTP requests from the same browser to the same server during
+  that browser's execution life-span.
+
+Browser Id
+  the string or integer used to represent a single anonymous visitor to the
+  part of the Zope site managed by a single browser id manager. E.g.
+  "12083789728".
+
+Browser Id Name
+  the name which is looked for in places enumerated by the currently configured
+  browser id namespaces. E.g. "_ZopeId".
+
+Browser Id Namespaces
+  the browser id name will be found in one of three possible places
+  ("namespaces"): in form elements and/or query strings (aka "form"), in a
+  cookie, or in the URL.
+
+Session Data Object
+  an transient data object that is found by asking a session data container for
+  the item with a key that is the current browser id value.
+
+Session Id
+  the identifier for a session data object. This is different than the browser
+  id. Instead of representing a single - *visitor*- , it represents a single -
+  *visit*- .
+
+Session Managers
+================
+
+Web browsers communicate with Web Servers using HTTP. HTTP does not provide
+tools that can track users and data in the context of a web session. Zope's
+session management works-around the problem: it provides methods able to track
+site visitor activity. Applications like "shopping carts" use session
+management for this reason.
+
+Zope's session management makes use of name-spaces like cookies, HTTP form
+elements, and/or parts of URLs "in the background" to keep track of user
+sessions. Which of these name-spaces are used is configurable using the
+browser_id manager (described later).
+
+Session data is valid for the duration of a **configurable inactivity** timeout
+value or browser shut-down, which ever comes first. Zope's session management
+keeps track of anonymous users as well as those who have Zope login accounts.
+
+Important! Data maintained by Zope's session management is no more secure than
+HTTP itself. A session is secure if and only if:
+
+- the connection between a browser and Zope uses strong encryption (SSL
+  normally).
+
+- precautions specific to the security exposure are taken.
+
+It's clear that you should not store sensitive information like credit card
+numbers in a session container unless you understand the vulnerabilities. See
+the section entitled *Security Considerations* near the end of this document.
+
+It is advisable to use sessions only on pages where they are necessary because
+of a performance impact on your application. The severity varies depending on
+usage and configuration. A good "rule of thumb" is to account for a 5% - 10%
+speed-of-execution penalty.
+
+Some hints:
+
+- Do not use SESSION to store REQUEST variables. They are already available in
+  the REQUEST.
+
+- Do not store any data in SESSION that you can get from the Zope API. Its
+  faster (and more secure) to get user Id from Zope's Security Manager then it
+  is from the SESSION object.
+
+Session Manager Components
+==========================
+
+Browser Id Manager
+++++++++++++++++++
+
+This component determines a remote client's "browser id", which uniquely
+identifies a particular browser. The browser id is encoded in a
+form/querystring variable, a cookie variable, or as part of the URL. The
+browser id manager examines cookies, form and querystring elements, and URLs
+to determine the client's browser id. It can also modify cookies and URLs
+automatically in order to differentiate users between requests.
+
+- There may be more than one browser id manager in a Zope installation, but
+  commonly there will only be one. Application developers will generally not
+  talk directly to a browser id manager. Instead, they will use the Transient
+  Data Object (REQUEST.SESSION) which delegates some calls to a browser_id
+  manager.
+
+- Browser id managers have "fixed" Zope ids so they can be found via
+  acquisition by session data managers. Browser id managers also have
+  interfaces for encoding a URL with browser id information and performing
+  other utility functions.
+
+- The default sessioning configuration provides a Browser Id Manager as the::
+
+    /browser_id_manager object
+
+Session Data Manager
+++++++++++++++++++++
+
+This component is responsible for handing out session data to callers. When
+session data is required, the session data manager:
+
+* talks to a browser id manager to determine the current browser id-
+
+* creates a new session data object or hands back an existing session data
+  object based on the browser id.
+
+- Developers generally do not directly use methods of session data managers to
+  obtain session data objects. Instead, they rely on the built-in
+  REQUEST.SESSION object, which represents *the current session data object
+  related to the user's browser id*.
+
+- The session data object has an identifier distinct from the browser id. This
+  identifier represents a single user session with the server (unlike the
+  browser id, which represents a single browser). Many session data managers
+  can use one browser id manager. Many session data managers can be
+  instantiated on a single Zope installation. Different session data managers
+  can implement different policies related to session data object storage (e.g.
+  to which session data container the session data objects are stored).
+
+- The default sessioning configuration provides a Session Data Manager named::
+
+    /session_data_manager
+
+Transient Object Container
+++++++++++++++++++++++++++
+
+Also known as Session Data Containers, these components actually hold
+information related to sessions.
+
+- Currently, a Transient Object Container is used to hold a special "transient
+  data object" instance for each ongoing session. Developers will generally not
+  interact with transient data containers. Transient data containers are
+
+- responsible for expiring the session data objects which live within them.
+
+- The default sessioning configuration provides a Transient Object Container
+  named::
+
+    /temp_folder/session_data
+
+  The session data objects in the default::
+
+    session_data
+
+  Transient Object container are lost each time Zope is restarted.
+
+Transient Data Object
++++++++++++++++++++++
+
+Also known as the Session Data Object. These are the objects which are stored
+in session data containers and managed by transient data managers.
+
+- Developers interact with a transient data object after obtaining one via
+  REQUEST.SESSION or from a session data manager directly. A single transient
+  data object actually stores the useful information related to a single user's
+  session.
+
+- Transient data objects can be expired automatically by transient data
+  containers as a result of inactivity, or they can be manually invalidated in
+  the course of a script.
+
+Using Session Data
+==================
+
+You will typically access session data through the::
+
+  SESSION
+
+attribute of the REQUEST object. Session data objects are like Python
+dictionaries: they can hold almost any kind of object as a key or a value. It's
+likely you will almost always use "normal" Python objects such as lists,
+dictionaries, strings, and numbers.
+
+Here's an example of how to work with a session using a Python Script::
+
+  ## Script (Python) "sessionTest"
+  secs_per_day=24*60*60
+  session=context.REQUEST.SESSION
+  if session.has_key('last view'):
+      # The script has been viewed before, since the 'last view'
+      then=session['last view']
+      now=context.ZopeTime()
+      session['last view']=now # reset last view to now
+      return 'Seconds since last view %.2f' % ((now - then) * secs_per_day)
+
+  # The script hasn't been viewed before, since there's no 'last view' 
+  session['last view']=context.ZopeTime()
+  return 'This is your first view'
+
+This example shows how to access SESSION data. But it is not a "best practice"
+example. If performance is an issue, you should not attempt to keep
+last-accessed time in this manner in a production application because it might
+slow your application down dramatically and cause problems under high load.
+
+Create a script with this body named *sessionTest* in your root folder and
+then click its *Test* tab. While viewing the output, reload the frame a few
+times. Note that the script keeps track of when you last viewed it and
+calculates how long it has been since you last viewed it. Notice that if you
+quit your browser and come back to the script it forgets you were ever there.
+However, if you simply visit some other pages and then return within 20 minutes
+or so, it still remembers the last time you viewed it.
+
+See the *Concepts and Caveats* section at the end of this document for things
+to watch out for while accessing Zope's Session Manager "naively".
+
+You can use sessions in Page Templates and DTML Documents, too. For example,
+here's a template snippet that displays the users favorite color (as stored in
+a session)::
+
+  <p tal:content="request/SESSION/favorite_color">Blue</p>
+
+Sessions have additional configuration parameters and usage patterns detailed
+below.
+
+Default Configuration
+=====================
+
+Zope is preconfigured with a default sessioning setup.
+
+The Zope "default" browser id manager lives in the root folder and is named::
+
+  browser_id_manager
+
+The Zope "default" session data manager lives in the root folder and is named::
+
+  session_data_manager
+
+A "default" transient data container (session data container) is created as::
+
+  /temp_folder/session_data
+
+when Zope starts up. The::
+
+  temp_folder
+
+object is a "mounted, nonundoing" database that keeps information in RAM, so
+"out of the box", Zope stores session information in RAM. The temp folder is a
+"nonundoing" storage (meaning you cannot undo transactions which take place
+within it) because accesses to transient data containers are very
+write-intensive, and undoability adds unnecessary overhead.
+
+A transient data container stores transient data objects. The default
+implementation the transient data object shipped with Zope is engineered to
+reduce the potential inherent in the ZODB for "conflict errors" related to the
+ZODB's "optimistic concurrency" strategy.
+
+You needn't change any of these default options to use sessioning under Zope
+unless you want to customize your setup. However, if you have custom needs, can
+create your own session data managers, browser id managers, temporary folders,
+and transient object containers by choosing these items from Zope's "add" list
+in the place of your choosing.
+
+Advanced Development Using Sessioning
+=====================================
+
+Overview
+++++++++
+
+When you work with the REQUEST.SESSION object, you are working with a "session
+data object" that is related to the current site user.
+
+Session data objects have methods of their own, including methods with allow
+developers to get and set data. Session data objects are also "wrapped" in the
+acquisition context of their session data manager, so you may additionally call
+any method on a session data object that you can call on a session data
+manager.
+
+Obtaining A Session Data Object
++++++++++++++++++++++++++++++++
+
+The session data object associated with the browser id in the current request
+may be obtained via REQUEST.SESSION. If a session data object does not exist in
+the session data container, one will be created automatically when you
+reference REQUEST.SESSION::
+
+  <dtml-let data="REQUEST.SESSION">
+      The 'data' name now refers to a new or existing session data object.
+  </dtml-let>
+
+You may also use the::
+
+  getSessionData()
+
+method of a session data manager to do the same thing::
+
+  <dtml-let data="session_data_manager.getSessionData()">
+      The 'data' name now refers to a new or existing session data object.
+  </dtml-let>
+
+A reference to REQUEST.SESSION or::
+
+  getSessionData()
+
+implicitly creates a new browser id if one doesn't exist in the current
+request. These mechanisms also create a new session data object in the session
+data container if one does not exist related to the browser id in the current
+request. To inhibit this behavior, use the create=0 flag to the::
+
+  getSessionData()
+
+method. In ZPT::
+
+  <span tal:define="data python:context.session_data_manager.getSessionData(create=0)">
+
+Note: create=0 means return a reference to the session or None. create=1 means
+return a reference if one exists or create a new Session object and the
+reference.
+
+Modifying A Session Data Object
++++++++++++++++++++++++++++++++
+
+Once you've used REQUEST.SESSION or::
+
+  session_data_manager.getSessionData()
+
+to obtain a session data object, you can set key/value pairs of that session
+data object.
+
+In ZPT::
+
+  <span tal:define="data python: request.SESSION">
+      <tal:block define="temp python: data.set('foo','bar')">
+          <p tal:content="python: data.get('foo')">bar will print here"</p>
+      </tal:block>
+  </span>
+
+An essentially arbitrary set of key/value pairs can be placed into a session
+data object. Keys and values can be any kinds of Python objects (note: see
+*Concepts and Caveats* section below for exceptions to this rule). The session
+data container which houses the session data object determines its expiration
+policy. Session data objects will be available across client requests for as
+long as they are not expired.
+
+Clearing A Session Data Object
+++++++++++++++++++++++++++++++
+
+You can clear all keys and values from a SESSION object by simply calling its
+clear() method.
+
+In ZPT::
+
+  <span tal:define="dummy python:request.SESSION.clear()"></span>
+
+Manually Invalidating A Session Data Object
++++++++++++++++++++++++++++++++++++++++++++
+
+Developers can manually invalidate a session data object. When a session data
+object is invalidated, it will be flushed from the system.
+
+There is a caveat. If you invalidate the session object in a script then you
+**must** obtain a fresh copy of the session object by calling getSessionData
+and not by reference (REQUEST.SESSION).
+
+Here is an example using DTML:::
+
+  <!-- set a SESSION key and value -->
+  <dtml-let data="REQUEST.SESSION">
+  <dtml-call "data.set('foo','bar')      
+
+  <!-- Now invalidate the SESSION -->
+  <dtml-call "data.invalidate()">
+
+  <!-- But REQUEST.SESSION gives us stale data which is bad.
+  The next statement will still show 'foo' and 'bar'
+  <dtml-var "REQUEST.SESSION>
+
+  <!-- Heres the work-around: -->
+  data = session_data_manager.getSessionData()
+
+  <!-- Now we get a fresh copy and life is good as 'foo' and 'bar' have gone away as expected -->
+  <dtml-var data>
+
+Manual invalidation of session data is useful when you need a "fresh" copy of a
+session data object.
+
+If an "onDelete" event is defined for a session data object, the onDelete
+method will be called before the data object is invalidated. See a following
+section for information about session data object "onDelete" and "onAdd"
+events.
+
+Manually Invalidating A Browser Id Cookie
++++++++++++++++++++++++++++++++++++++++++
+
+Invalidating a session data object does not invalidate the browser id cookie
+stored on the user's browser. Developers may manually invalidate the cookie
+associated with the browser id. To do so, they can use the::
+
+  flushBrowserIdCookie()
+
+method of a browser id manager. For example::
+
+  <dtml-call "REQUEST.SESSION.getBrowserIdManager().flushBrowserIdCookie()">
+
+If the::
+
+  cookies
+
+namespace isn't a valid browser id key namespace when this call is performed,
+an exception will be raised.
+
+Using Session Data with TAL
++++++++++++++++++++++++++++
+
+Here's an example of using the session data object with TAL::
+
+  <span tal:define="a python:request.SESSION;
+                    dummy python:a.set('zopetime',context.ZopeTime())">
+      <p tal:content="python: a.get('zopetime')"></p>
+  </span>
+
+Using Session Data From Python
+++++++++++++++++++++++++++++++
+
+Here's an example of using a session data manager and session data object from
+a set of Python external methods::
+
+  import time
+  def setCurrentTime(self):
+      a = self.REQUEST.SESSION
+      a.set('thetime', time.time())
+
+  def getLastTime(self):
+      a = self.REQUEST.SESSION
+      return a.get('thetime')
+
+Calling the setCurrentTime will set the value of the current session's
+"thetime" key to an integer representation of the current time. Calling the
+getLastTime external method will return the integer representation of the last
+known value of "thetime".
+
+Interacting with Browser Id Data
+++++++++++++++++++++++++++++++++
+
+You can obtain the browser id value associated with the current request::
+
+  <dtml-var "REQUEST.SESSION.getBrowserIdManager().getBrowserId()">
+
+Another way of doing this, which returns the same value is::
+
+  <dtml-var "REQUEST.SESSION.getContainerKey()">
+
+If no browser id exists for the current request, a new browser id is created
+implicitly and returned.
+
+If you wish to obtain the current browser id value without implicitly creating
+a new browser id for the current request, you can ask the browser_id_manager
+object explicitly for this value with the `create=0` parameter::
+
+  <dtml-var "browser_id_manager.getBrowserId(create=0)">
+
+This snippet will print a representation of the None value if there isn't a
+browser id associated with the current request, or it will print the browser id
+value if there is one associated with the current request. Using `create=0` is
+useful if you do not wish to cause the sessioning machinery to attach a new
+browser id to the current request, perhaps if you do not wish a browser id
+cookie to be set.
+
+The browser id is either a string or an integer and has no business meaning. In
+your code, you should not rely on the browser id value composition, length, or
+type as a result, as it is subject to change.
+
+Determining Which Namespace Holds The Browser Id
+++++++++++++++++++++++++++++++++++++++++++++++++
+
+For some applications, it is advantageous to know from which namespace (
+"cookies", "form", or "url") the browser id has been gathered.
+
+It should be noted that you can configure the browser_id_manager (its in Zope
+root by default) so that it searches whatever combination of namespaces you
+select.
+
+There are three methods of browser id managers which allow you to accomplish
+this::
+
+  <dtml-if "REQUEST.SESSION.getBrowserIdManager().isBrowserIdFromCookie()">
+      The browser id came from a cookie.
+  </dtml-if>
+
+  <dtml-if "REQUEST.SESSION.getBrowserIdManager().isBrowserIdFromForm()">
+      The browser id came from a form.
+  </dtml-if>
+
+  <dtml-if "REQUEST.SESSION.getBrowserIdManager().isBrowserIdFromUrl()">
+      The browser id came from the URL.
+  </dtml-if>
+
+The::
+
+  isBrowserIdFromCookie()
+
+method will return true if the browser id in the current request comes from
+the::
+
+  REQUEST.cookies
+
+namespace. This is true if the browser id was sent to the Zope server as a
+cookie.
+
+The::
+
+  isBrowserIdFromForm()
+
+method will return true if the browser id in the current request comes from
+the::
+
+  REQUEST.form
+
+namespace. This is true if the browser id was sent to the Zope server encoded
+in a query string or as part of a form element.
+
+The::
+
+  isBrowserIdFromUrl()
+
+method will return true if the browser id in the current request comes from the
+leading elements of the URL.
+
+If a browser id doesn't actually exist in the current request when one of these
+methods is called, an error will be raised.
+
+During typical operations, you shouldn't need to use these methods, as you
+shouldn't care from which namespace the browser id was obtained. However, for
+highly customized applications, this set of methods may be useful.
+
+Obtaining the Browser Id Name/Value Pair and Embedding It Into A Form
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+You can obtain the browser id name from a browser id manager instance. We've
+already determined how to obtain the browser id itself. It is useful to also
+obtain the browser id name if you wish to embed a browser id name/value pair as
+a hidden form field for use in POST requests. Here's a TAL example::
+
+    <span tal:define="idManager python:request.SESSION.getBrowserIdManager()">
+        <form action="thenextmethod">
+            <input type=submit name="submit" value=" GO ">
+            <input type="hidden" name="name" value="value"
+                   tal:attributes="name python: idManager.getBrowserIdName();
+                                   value python: idManager.getBrowserId()">
+        </form>
+    </span>
+
+A convenience function exists for performing this action as a method of a
+browser id manager named "getHiddenFormField"::
+
+  <html>
+  <body>
+    <form action="thenextmethod">
+      <input type="submit" name="submit" value=" GO ">
+      <dtml-var "REQUEST.SESSION.getBrowserIdManager().getHiddenFormField()">
+    </form>
+  </body>
+  </html>
+
+When the above snippets are rendered, the resulting HTML will look something
+like this::
+
+  <html>
+  <body>
+    <form action="thenextmethod">
+      <input type="submit" name="submit" value=" GO ">
+      <input type="hidden" name="_ZopeId" value="9as09a7fs70y1j2hd7at8g">
+    </form>
+  </body>
+  </html>
+
+Note that to maintain state across requests when using a form submission, even
+if you've got
+
+- Automatically Encode
+- Zope-Generated URLs With a Browser Id
+
+checked off in your browser id manager, you'll either need to encode the form
+"action" URL with a browser id (see "Embedding A Browser Id Into An HTML Link"
+below) or embed a hidden form field.
+
+Using formvar-based sessioning.
++++++++++++++++++++++++++++++++
+
+To use formvar-based sessioning, you need to encode a link to its URL with the
+browser id by using the browser id manager's::
+
+  encodeUrl()
+
+method.
+
+Determining Whether A Browser Id is "New"
++++++++++++++++++++++++++++++++++++++++++
+
+A browser id is "new" if it has been set in the current request but has not yet
+been acknowledged by the client. "Not acknowledged by the client" means it has
+not been sent back by the client in a request. This is the case when a new
+browser id is created by the sessioning machinery due to a reference to
+REQUEST.SESSION or similar as opposed to being received by the sessioning
+machinery in a browser id name namespace. You can use the::
+
+  isBrowserIdNew()
+
+method of a browser id manager to determine whether the session is new::
+
+  <dtml-if "REQUEST.SESSION.getBrowserIdManager().isBrowserIdNew()">
+      Browser id is new.
+  <dtml-else>
+      Browser id is not new.
+  </dtml-if>
+
+This method may be useful in cases where applications wish to prevent or detect
+the regeneration of new browser ids when the same client visits repeatedly
+without sending back a browser id in the request (such as may be the case when
+a visitor has cookies "turned off" in their browser and the browser id manager
+only uses cookies).
+
+If there is no browser id associated with the current request, this method will
+raise an error.
+
+You shouldn't need to use this method during typical operations, but it may be
+useful in advanced applications.
+
+
+Determining Whether A Session Data Object Exists For The Browser Id Associated With This Request
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+If you wish to determine whether a session data object with a key that is the
+current request's browser id exists in the session data manager's associated
+session data container, you can use the::
+
+  hasSessionData()
+
+method of the session data manager. This method returns true if there is
+session data associated with the current browser id::
+
+  <dtml-if "session_data_manager.hasSessionData()">
+    The sessiondatamanager object has session data for the browser id
+    associated with this request.
+  <dtml-else>
+    The sessiondatamanager object does not have session data for
+    the browser id associated with this request.
+  </dtml-if>
+
+The::
+
+  hasSessionData()
+
+method is useful in highly customized applications, but is probably less useful
+otherwise. It is recommended that you use REQUEST.SESSION instead, allowing the
+session data manager to determine whether or not to create a new data object
+for the current request.
+
+Embedding A Browser Id Into An HTML Link
+++++++++++++++++++++++++++++++++++++++++
+
+You can embed the browser id name/value pair into an HTML link for use during
+HTTP GET requests. When a user clicks on a link with a URL encoded with the
+browser id, the browser id will be passed back to the server in the
+REQUEST.form namespace. If you wish to use formvar-based session tracking, you
+will need to encode all of your "public" HTML links this way. You can use the::
+
+  encodeUrl()
+
+method of browser id managers in order to perform this encoding::
+
+  <html>
+  <body>
+    <a href="<dtml-var "REQUEST.SESSION.getBrowserIdManager().encodeUrl('/amethod')">">
+      Here
+    </a>
+    is a link.
+  </body>
+  </html>
+
+The above dtml snippet will encode the URL "/amethod" (the target of the word
+"Here") with the browser id name/value pair appended as a query string. The
+rendered output of this DTML snippet would look something like this::
+
+  <html>
+  <body>
+    <a href="/amethod?_ZopeId=7HJhy78978979JHK">Here</a>
+    is a link.
+  </body>
+  </html>
+
+You may successfully pass URLs which already contain query strings to the::
+
+  encodeUrl()
+
+method. The encodeUrl method will preserve the existing query string and append
+its own name/value pair.
+
+You may choose to encode the browser id into the URL using an "inline" style if
+you're checking for browser ids in the URL (e.g. if you've checked::
+
+  URLs
+
+in the "Look for Browser Id in" form element of your browser id manager)::
+
+  <html>
+  <body>
+    <a href="<dtml-var "REQUEST.SESSION.getBrowserIdManager().encodeUrl('/amethod', style='inline')">">Here</a>
+    is a link.
+  </body>
+  </html>
+
+The above dtml snippet will encode the URL "/amethod" (the target of the word
+"Here") with the browser id name/value pair embedded as the first two elements
+of the URL itself. The rendered output of this DTML snippet would look
+something like this::
+
+  <html>
+  <body>
+    <a href="/_ZopeId/7HJhy78978979JHK/amethod">Here</a>
+    is a link.
+  </body>
+  </html>
+
+Using Session onAdd and onDelete Events
++++++++++++++++++++++++++++++++++++++++
+
+The configuration of a Transient Object Container (aka a session data
+container) allows a method to be called when a session data object is created
+(onAdd) or when it is invalidated or timed out (onDelete).
+
+The events are independent of each other. You might want an onAdd method but
+not an onDelete method. You may define one, both or none of the TOC event
+methods.
+
+Here are examples of the kinds of things Session onAdd and onDelete methods are
+used to do:
+
+- The onAdd method can be used to populate a session data object with "default"
+  values before it's used by application code.
+
+- The onDelete method can write the contents of a session data object out to a
+  permanent data store before it is timed out or invalidated.
+
+You can manually configure the onAdd and onDelete methods. Click the
+*management tab* of '\temp_folder\session_data. Enter "a physical path" to
+either a an external method or python script. NOTE: This configuration is only
+good until the next Zope shutdown because::
+
+  \temp_folder\session_data
+
+is in a RAM database, Configure the onAdd and onDelete methods for this data
+container via the::
+
+  zope.conf
+
+configuration file for your Zope instance. This is covered in some detail in
+*Setting Initial Transient Object Container Parameters* later in this document.
+
+Note: the onAdd and onDelete events do not raise exceptions if logic in the
+method code fails. Instead, an error is logged in the Zope event log. In recent
+versions of Zope, the event.log defaults to Zope-Instance/log/event.log. This
+is configurable in::
+
+  zope.conf
+
+Writing onAdd and onDelete Methods
+++++++++++++++++++++++++++++++++++
+
+Session data objects optionally call a Zope method when they are created and
+when they are timed out or invalidated.
+
+Specially-written Script (Python) scripts can be written to serve the purpose
+of being called on session data object creation and invalidation.
+
+The Script (Python) should define two arguments, "sdo" and "toc". "sdo"
+represents the session data object being created or terminated, and "toc"
+represents the transient object container in which this object is stored.
+
+For example, to create a method to handle a session data object onAdd event
+which prepopulates the session data object with a DateTime object, you might
+write a Script (Python) named::
+
+  onAdd
+
+which had function parameters "sdo" and "toc" and a body of::
+
+  sdo['date'] = context.ZopeTime()
+
+If you set the path to this method as the onAdd event, before any application
+handles the new session data object, it will be prepopulated with a key::
+
+  date
+
+that has the value of a DateTime object set to the current time.
+
+To create a method to handle a session onDelete event which writes a log
+message, you might write an External Method with the following body::
+
+  from zLOG import LOG, WARNING
+  def onDelete(sdo, toc):
+      logged_out = sdo.get('logged_out', None)
+      if logged_out is None:
+          LOG('session end', WARNING,
+              'session ended without user logging out!')
+
+If you set the path to this method as the onDelete event, a message will be
+logged if the::
+
+  logged_out
+
+key is not found in the session data object.
+
+Note that for onDelete events, there is no guarantee that the onDelete event
+will be called in the context of the user who originated the session! Due to
+the "expire-after-so-many-minutes-of-inactivity" behavior of session data
+containers, a session data object onDelete event initiated by one user may be
+called while a completely different user is visiting the application. Your
+onDelete event method should not naively make any assumptions about user state.
+For example, the result of the Zope call "getSecurityManager().getUser()" in an
+onDelete session event method will almost surely *not* be the user who
+originated the session.
+
+The session data object onAdd method will always be called in the context of
+the user who starts the session.
+
+For both onAdd and onDelete events, it is almost always desirable to set proxy
+roles on event methods to replace the roles granted to the executing user when
+the method is called because the executing user will likely not be the user for
+whom the session data object was generated. For more information about proxy
+roles, see the chapter entitled `Users and Security <Security.stx>`_.
+
+For additional information about using session onDelete events in combination
+with data object timeouts, see the section entitled "Session Data Object
+Expiration Considerations" in the Concepts and Caveats section below.
+
+
+Configuration and Operation
+===========================
+
+Setting the default Transient Object Container Parameters
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Click on::
+
+  /temp_folder/session_data
+
+and you'll see options to control inactivity time-outs and the maximum
+allowable number of Session objects. You can even include paths to python
+scripts that handle a Session's after-add and before-delete events.
+
+Because::
+
+  /temp_folder/session_data
+
+is stored in a RAM database, it disappears and is recreated after each restart
+of your Zope server. This means that any changes to parameters will be lost the
+next time you restart your Zope server.
+
+If you need to permanently alter the default Transient Object Container's
+configuration you must edit Zope's startup configuration file::
+
+  zope.conf
+
+Note that additional Transient Object Containers can be instantiated in
+permanent storage. They are rarely needed. If you do need this its covered in
+detail later in this document.
+
+Here is the relevant portion of zope.conf::
+
+  # Directive: maximum-number-of-session-objects
+  # Description: An integer value representing the maximum number 
+  #              of subobjects" 
+  # allowable in the '/temp_folder/session_data' transient object container.
+  #         
+  # Default: 1000
+  # Example: maximum-number-of-session-objects 10000
+
+  # Directive: session-add-notify-script-path
+  #
+  # Description:
+  #     An optional fill Zope path name of a callable object to be set as the
+  #     "script to call on object addition" of the session_data transient
+  #     object container created in the /temp_folder folder at startup.
+  #
+  # Default: unset
+  # Example: session-add-notify-script-path /scripts/add_notifier
+
+  # Directive: session-delete-notify-script-path
+  #
+
+  # Description:
+  #     An optional fill Zope path name of a callable object to be set as the
+  #     "script to call on object deletion" of the session_data transient
+  #     object container created in the /temp_folder folder at startup.
+  #
+  # Default: unset
+  # Example: session-delete-notify-script-path /scripts/del_notifier
+
+  # Directive: session-timeout-minutes
+  #
+  # Description:
+  #     An integer value representing the number of minutes to be used as the
+  #     "data object timeout" of the '/temp_folder/session_data' transient
+  #     object container.
+  #
+  # Default: 20
+  # Example: session-timeout-minutes 30
+
+  # Directive: session-resolution-seconds
+  #
+  # Description:
+  #    An integer value representing the number of seconds to be used as the
+  #    "timeout resolution" of the '/temp_folder/session_data' transient
+  #    object container.
+  #
+  # Default: 20
+  # Example: session-resolution-seconds 60
+
+Instantiating Multiple Browser Id Managers (Optional)
++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Transient data objects depend on a session data manager, which in turn depends
+on a browser id manager. A browser id manager doles out and otherwise manages
+browser ids. All session data managers need to talk to a browser id manager to
+get browser id information.
+
+You needn't create a browser id manager to use sessioning. One is already
+created as a result of the initial Zope installation. If you've got special
+needs, you may want to instantiate more than one browser id manager. Having
+multiple browser id managers may be useful in cases where you have a "secure"
+section of a site and an "insecure" section of a site, each using a different
+browser id manager with respectively restrictive security settings.
+
+In the container of your choosing, select "Browser Id Manager" from the add
+drop-down list in the Zope management interface. When you add a new browser id
+manager, the form options available are:
+
+Id
+  You cannot choose an id for your browser id manager. It must always be
+  "browser_id_manager". Additionally, you cannot rename a browser id manager.
+  This is required in the current implementation so that session data managers
+  can find session id managers via Zope acquisition.
+
+Title
+  the browser id manager title.
+
+Browser Id Name
+  the name used to look up the value of the browser id. This will be the name
+  looked up in the `cookies` or `form` REQUEST namespaces when the browser id
+  manager attempts to find a cookie, form variable, or URL with a browser id in
+  it.
+
+Look for Browser Id Name In
+  choose the request elements to look in when searching for the browser id
+  name. You may choose "cookies", "Forms and Query Strings", and "URLs".
+
+Automatically Encode Zope-Generated URLs With A Browser Id
+
+  if this option is checked, all URLs generated by Zope (such as URLs obtained
+  via the `absolute_url` method of all Zope objects) will have a browser id
+  name/value pair embedded within them. This typically only make sense if
+  you've also got the `URLs` setting of "Look for Browser Id in" checked off.
+
+Cookie Path
+  this is the `path` element which should be sent in the browser id cookie.
+
+Cookie Domain
+  this is the "domain" element which should be sent in the browser id cookie.
+  Leaving this form element blank results in no domain element in the cookie.
+  If you change the cookie domain here, the value you enter must have at least
+  two dots (as per the cookie spec).
+
+Cookie Lifetime In Days
+  browser id cookies sent to browsers will last this many days on a remote
+  system before expiring if this value is set. If this value is 0, cookies will
+  persist on client browsers for only as long as the browser is open.
+
+Only Send Cookie Over HTTPS
+
+  if this flag is set, only send cookies to remote browsers if they're
+  communicating with us over https. The browser id cookie sent under this
+  circumstance will also have the `secure` flag set in it, which the remote
+  browser should interpret as a request to refrain from sending the cookie back
+  to the server over an insecure (non-https) connection. NOTE: In the case you
+  wish to share browser id cookies between https and non-https connections from
+  the same browser, do not set this flag.
+
+After reviewing and changing these options, click the "Add" button to
+instantiate a browser id manager. You can change any of a browser id manager's
+initial settings by visiting it in the management interface.
+
+Instantiating A Session Data Manager (Optional)
++++++++++++++++++++++++++++++++++++++++++++++++
+
+After instantiating at least one browser id manager, it's possible to
+instantiate a session data manager. You don't need to do this in order to begin
+using Zope's sessioning machinery, as a default session data manager is created
+as::
+
+  /session_data_manager
+
+You can place a session data manager in any Zope container,as long as a browser
+id manager object named::
+
+  browser_id_manager
+
+can be acquired from that container. The session data manager will use the
+first acquired browser id manager.
+
+Choose "Session Data Manager" within the container you wish to house the
+session data manager from the "Add" drop-down box in the Zope management
+interface.
+
+The session data manager add form displays these options:
+
+Id
+  choose an id for the session data manager
+
+Title
+  choose a title for the session data manager
+
+Transient Object Container Path
+  enter the Zope path to a Transient Object Container in this text box in order
+  to use it to store your session data objects. Note: session manager's should
+  not share transient object paths. This is an example path:
+
+  Zope transient object container is::
+
+    /MyTransientSessionFolder
+
+After reviewing and changing these options, click the "Add" button to
+instantiate a session data manager.
+
+You can manage a session data manager by visiting it in the management
+interface. You may change all options available during the add process by doing
+this.
+
+Instantiating a Transient Object Container
+++++++++++++++++++++++++++++++++++++++++++
+
+The default transient object container at::
+
+  /temp_folder/session_data
+
+stores its objects in RAM, so these objects and their data disappear when you
+restart Zope.
+
+If you want your session data to persist across server reboots, or if you have
+a very large collection of session data objects, or if you'd like to share
+sessions between ZEO clients, you will want to instantiate a transient data
+container in a more permanent storage.
+
+A heavily-utilized transient object container *should be instantiated inside a
+database which is nonundoing*! Although you may instantiate a transient data
+container in any storage, if you make heavy use of an external session data
+container in an undoing database (such as the default Zope database which is
+backed by "FileStorage", an undoing and versioning storage), your database will
+grow in size very quickly due to the high-write nature of session tracking,
+forcing you to pack very often. You can "mount" additional storages within the
+`zope.conf` file of your Zope instance. The default `temp_folder` is mounted
+inside a `TemporaryStorage` , which is nonundoing and RAM-based. There are
+other nonundoing storages, such as BerkeleyStorage, although none quite as
+well-supported as TemporaryStorage.
+
+Here are descriptions of the add form of a Transient Object Container, which
+may be added by selecting "Transient Object Container" for the Zope Add list.:
+
+  Special note: When you add a transient object container to a non-RAM-based
+  storage, unlike the the default transient objects contained in temp_folder,
+  these instances of TOC maintain their parameter settings between Zope
+  Restarts. Importantly, they *do not* read zope.conf.
+
+Id
+  the id of the transient object container
+
+Title (optional)
+  the title of the transient object container
+
+Data object timeout in minutes
+  enter the number of minutes of inactivity which causes a contained transient
+  object be be timed out. "0" means no expiration.
+
+Maximum number of subobjects
+  enter the maximum number of transient objects that can be added to this
+  transient object container. This value helps prevent "denial of service"
+  attacks to your Zope site by effectively limiting the number of concurrent
+  sessions.
+
+Script to call upon object add (optional)
+  when a session starts, you may call an external method or Script (Python).
+  This is the Zope path to the external method or Script (Python) object to be
+  called. If you leave this option blank, no onAdd function will be called. An
+  example of a method path is `/afolder/amethod`.
+
+Script to call upon object delete (optional)
+  when a session ends, you may call an external method or Script (Python). This
+  is the Zope path to the external method or Script (Python) object to be
+  called. If you leave this option blank, no onDelete function will be called.
+  An example of a method path is `/afolder/amethod`.
+
+
+Multiple session data managers can make use of a single transient object
+container to the extent that they may share the session data objects placed in
+the container between them. This is not a recommended practice, however, as it
+has not been tested at all.
+
+The `data object timeout in minutes` value is the number of minutes that
+session data objects are to be kept since their last-accessed time before they
+are flushed from the data container. For instance, if a session data object is
+accessed at 1:00 pm, and if the timeout is set to 20 minutes, if the session
+data object is not accessed again by 1:19:59, it will be flushed from the data
+container at 1:20:00 or a time shortly thereafter. "Accessed", in this
+terminology, means "pulled out of the container" by a call to the session data
+manager's getSessionData() method or an equivalent (e.g. a reference to
+REQUEST.SESSION). See "Session Data Object Expiration Considerations" in the
+*Concepts and Caveats* section below for details on session data expiration.
+
+Configuring Sessioning Permissions
+++++++++++++++++++++++++++++++++++
+
+You need only configure sessioning permissions if your requirements deviate
+substantially from the norm. In this case, here is a description of the
+permissions related to sessioning.
+
+Permissions related to browser id managers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Add Browser Id Manager
+  allows a role to add browser id managers. By default, enabled for `Manager`.
+
+Change Browser Id Manager
+  allows a role to change an instance of a browser id manager. By default,
+  enabled for `Manager`.
+
+Access contents information
+  allows a role to obtain data about browser ids. By default, enabled for
+  `Manager` and `Anonymous`.
+
+
+Permissions related to session data managers:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Add Session Data Manager
+  allows a role to add session data managers. By default, enabled for
+  `Manager`.
+
+Change Session Data Manager
+  allows a role to call management-related methods of a session data manager.
+  By default, enabled for `Manager`.
+
+Access session data
+  allows a role to obtain access to the session data object related to the
+  current browser id. By default, enabled for `Manager` and `Anonymous`. You
+  may wish to deny this permission to roles who have DTML or Web-based Python
+  scripting capabilities who should not be able to access session data.
+
+Access arbitrary user session data
+  allows a role to obtain and otherwise manipulate any session data object for
+  which the browser id is known. By default, enabled for `Manager`.
+
+Access contents information
+  allows a role to obtain data about session data. By default, enabled for
+  `Manager` and `Anonymous`.
+
+Permissions related to transient object containers:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Add Transient Object Container
+  allows a role to add transient objects containers. By default, enabled for
+  `Manager`.
+
+Change Transient Object Container
+  allows a role to make changes to a transient object container.
+
+Access Transient Objects
+  allows a role to obtain and otherwise manipulate the transient object related
+  to the current browser id.
+
+Concepts and Caveats
+====================
+
+Security Considerations
++++++++++++++++++++++++
+
+Sessions are insecure by their very nature. If an attacker gets a hold of
+someone's browser id, and if they can construct a cookie or use form elements
+or URL elements to pose as that user from their own browser, they will have
+access to all information in that user's session. Sessions are not a
+replacement for authentication for this reason.
+
+Ideally, you'd like to make certain that nobody but the user its intended for
+gets a hold of his browser id. To take steps in this direction, and if you're
+truly concerned about security, you will ensure that you use cookies to
+maintain browser id information, and you will secure the link between your
+users and your site using SSL. In this configuration, it is more difficult to
+"steal" browser id information as the browser id will not be evident in the URL
+and it will be very difficult for attackers to "tap" the encrypted link between
+the browser and the Zope site.
+
+There are significant additional risks to user privacy in employing sessions in
+your application, especially if you use URL-based or formvar-based browser ids.
+Commonly, a browser id is embedded into a form/querystring or a URL in order to
+service users who don't have cookies turned on.
+
+For example, this kind of bug was present until recently in a lot of webmail
+applications: if you sent a mail to someone that included a link to a site
+whose logs you could read, and the user clicked on the link in his webmail
+page, the full URL of the page, including the authentication (stored as session
+information in the URL) would be sent as a HTTP REFERER to your site.
+
+Nowadays all serious webmail applications either choose to store at least some
+of the authentication information outside of the URL (in a cookie for
+instance), or process all the user-originated URLs included in the mail to make
+them go through a redirection that sanitizes the HTTP REFERER.
+
+The moral of the story is: if you're going to use sessions to store sensitive
+information, and you link to external sites within your own site, you're best
+off using *only* cookie-based browser ids.
+
+Browser Id (Non-)Expiration
++++++++++++++++++++++++++++
+
+A browser id will last as long as the browser id cookie persists on the client,
+or for as long as someone uses a bookmarked URL with a browser id encoded into
+it.
+
+The same id will be obtained by a browser id manager on every visit by that
+client to a site - potentially indefinitely depending on which conveyance
+mechanisms you use and your configuration for cookie persistence.
+
+The transient object container implements a policy for data object expiration.
+If asked for a session data object related to a particular browser id which has
+been expired by a session data container, a session data manager will a return
+a new session data object.
+
+Session Data Object Expiration Considerations
++++++++++++++++++++++++++++++++++++++++++++++
+
+Session data objects expire after the period between their last access and
+"now" exceeds the timeout value provided to the session data container which
+hold them. No special action need be taken to expire session data objects.
+
+However, because Zope has no scheduling facility, the sessioning machinery
+depends on the continual exercising of itself to expire session data objects.
+If the sessioning machinery is not exercised continually, it's possible that
+session data objects will stick around longer than the time specified by their
+data container timeout value. For example:
+
+- User A exercises application machinery that generates a session data object.
+  It is inserted into a session data container which advertises a 20-minute
+  timeout.
+
+- User A "leaves" the site.
+
+- 40 minutes go by with no visitors to the site.
+
+- User B visits 60 minutes after User A first generated his session data
+  object, and exercises app code which hands out session data objects. - *User
+  A's session is expired at this point, 40 minutes "late".*
+
+As shown, the time between a session's onAdd and onDelete is not by any means
+*guaranteed* to be anywhere close to the amount of time represented by the
+timeout value of its session data container. The timeout value of the data
+container should only be considered a "target" value.
+
+Additionally, even when continually exercised, the sessioning machinery has a
+built in error potential of roughly 20% with respect to expiration of session
+data objects to reduce resource requirements. This means, for example, if a
+transient object container timeout is set to 20 minutes, data objects added to
+it may expire anywhere between 16 and 24 minutes after they are last accessed.
+
+Sessioning and Transactions
++++++++++++++++++++++++++++
+
+Sessions interact with Zope's transaction system. If a transaction is aborted,
+the changes made to session data objects during the transaction will be rolled
+back.
+
+Mutable Data Stored Within Session Data Objects
++++++++++++++++++++++++++++++++++++++++++++++++
+
+If you mutate an object stored as a value within a session data object, you'll
+need to notify the sessioning machinery that the object has changed by calling
+`set` or `__setitem__` on the session data object with the new object value.
+For example::
+
+  session = self.REQUEST.SESSION
+  foo = {}
+  foo['before'] = 1
+  session.set('foo', foo)
+
+  # mutate the dictionary
+
+  foo['after'] = 1
+
+  # performing session.get('foo') 10 minutes from now will likely
+  # return a dict with only 'before' within!
+
+You'll need to treat mutable objects immutably, instead. Here's an example that
+makes the intent of the last example work by doing so::
+
+  session = self.REQUEST.SESSION
+  foo = {}
+  foo['before'] = 1
+  session.set('foo', foo)
+
+  # mutate the dictionary
+  foo['after'] = 1
+
+  # tickle the persistence machinery
+  session.set('foo', foo)
+
+An easy-to-remember rule for manipulating data objects in session storage:
+always explicitly place an object back into session storage whenever you change
+it. For further reference, see the "Persistent Components" chapter of the Zope
+Developer's Guide at http://www.zope.org/Documentation/ZDG.
+
+session.invalidate() and stale references to the session object
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+This Python Script illustrates an issue with using the invalidate method of a
+session object::
+
+  request = container.REQUEST
+  session = request.SESSION
+  session.set('foo','bar')
+  session.invalidate() 
+  # ............................................
+  # we expect that invalidate() flushes the session 
+  # ............................................
+  print 'after invalidate()',session.get('foo') # 'bar' still prints!
+
+  # ............................................
+  # Even this isn't enough
+  # ............................................
+  session = request.SESSION
+  print 'after invalidate()', session.get('foo') # 'bar' still prints!
+
+  # ............................................
+  # Here's the work-around
+  # ............................................
+  session = context.session_data_manager.getSessionData()
+  print 'after getSessionData', session.get('foo') # 'bar' is GONE which is good
+  return printed
+
+In short, after using the `invalidate` method of a session object, the next
+reference to the session object you obtain should be through "getSessionData"
+rather than `REQUEST.SESSION`.
+
+Session Data Object Keys
+++++++++++++++++++++++++
+
+A session data object has essentially the same restrictions as a Python
+dictionary. Keys within a session data object must be hashable (strings,
+tuples, and other immutable basic Python types; or instances which have a
+__hash__ method). This is a requirement of all Python objects that are to be
+used as keys to a dictionary. For more information, see the associated Python
+documentation at http://www.python.org/doc/current/ref/types.html (Mappings ->
+Dictionaries).
+
+In-Memory Session Data Container RAM Utilization
+++++++++++++++++++++++++++++++++++++++++++++++++
+
+Each session data object which is added to an "internal" (RAM-based) session
+data container will consume at least 2K of RAM.
+
+Mounted Transient Object Container Caveats
+++++++++++++++++++++++++++++++++++++++++++
+
+Mounted TOC's do not acquire parameter's from zope.conf (which is the case for
+the default transient object container). Therefore you set parameters directly
+on the object in ZMI.
+
+Persistent objects which have references to other persistent objects in the
+same database cannot be committed into a mounted database because the ZODB does
+not currently handle cross-database references.
+
+Transient object containers which are sometimes stored in a "mounted" database
+(as is currently the case for the default ::
+
+  /temp_folder/session_data
+
+TOC. If you use a transient object container that is accessed via a "mounted"
+database, you cannot store persistent object instances which have already been
+stored in the "main" database as keys or values in a session data object. If
+you try to do so, it is likely that an ::
+
+  InvalidObjectReference
+
+exception will be raised by the ZODB when the transaction involving the object
+attempts to commit. As a result, the transaction will fail and the session data
+object (and other objects touched in the same transaction) will fail to be
+committed to storage.
+
+If your "main" ZODB database is backed by a nonundoing storage, you can avoid
+this condition by storing session data objects in an transient object container
+instantiated within the "main" ZODB database. If this is not an option, you
+should ensure that objects you store as values or keys in a session data object
+held in a mounted session data container are instantiated "from scratch" (via
+their constructors), as opposed to being "pulled out" of the main ZODB.
+
+Conflict Errors
++++++++++++++++
+
+This session tracking software stores all session state in Zope's ZODB. The
+ZODB uses an optimistic concurrency strategy to maintain transactional
+integrity for simultaneous writes. This means that if two objects in the ZODB
+are changed at the same time by two different connections (site visitors) that
+a "ConflictError" will be raised. Zope retries requests that raise a
+ConflictError at most 3 times. If your site is extremely busy, you may notice
+ConflictErrors in the Zope debug log (or they may be printed to the console
+from which you run Zope). An example of one of these errors is as follows::
+
+  2009-01-16T04:26:58 INFO(0) Z2 CONFLICT Competing writes at, /getData
+  Traceback (innermost last):
+  File /zope/lib/python/ZPublisher/Publish.py, line 175, in publish
+  File /zope/lib/python/Zope/__init__.py, line 235, in commit
+  File /zope/lib/python/ZODB/Transaction.py, line 251, in commit
+  File /zope/lib/python/ZODB/Connection.py, line 268, in commit
+  ConflictError: '\000\000\000\000\000\000\002/'
+
+Errors like this in your debug log (or console if you've not redirected debug
+logging to a file) are normal to an extent. If your site is undergoing heavy
+load, you can expect to see a ConflictError perhaps every 20 to 30 seconds. The
+requests which experience conflict errors will be retried automatically by
+Zope, and the end user should *never* see one. Generally, session data objects
+attempt to provide application-level conflict resolution to reduce the
+limitations imposed by conflict errors NOTE: to take advantage of this feature,
+you must store your transient object container in a storage such as FileStorage
+or TemporaryStorage which supports application-level conflict resolution.

Copied: zope2docs/branches/baijum-reorganize/zope2book/SimpleExamples.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/SimpleExamples.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/SimpleExamples.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/SimpleExamples.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,749 @@
+Creating Basic Zope Applications
+================================
+
+.. todo:
+   
+   - add new screen shots
+
+This chapter will take you, step by step, through building a basic web
+application in Zope.  As we go through the chapter, we will examine some of
+Zope's main concepts at work.  Using Zope *Folder*, *Script (Python)*, and
+*Page Template* objects, we'll create a simple website for an imaginary
+zoo: the "Zope Zoo", of course!
+
+We will develop the website as a Zope "instance-space" application.  A
+discussion of instance space is at the end of this chapter, but for now it
+is enough to know that instance-space applications are the easiest and
+fastest kind to build, because we can do everything in our favorite web
+browser.
+
+Goals for the Zope Zoo Web Site
+-------------------------------
+
+As with any project, we first need to clarify our goals for the Zope Zoo
+application.  The application's primary goal is to create a website for
+the world-renowned Zope Zoo.  Furthermore, we want to make the website
+easy to use and manage.  Here are some things we'll do:
+
+- Enable web users to navigate the site easily, as if they were moving
+  around a real zoo.
+
+- Keep all our shared web layout tools, like a Cascading Style Sheet
+  (CSS), in a single, easy-to-manage location.
+
+- Design the website so that future site-wide changes are quick and easy
+  to implement.
+
+- Take advantage of Zope to create a dynamic website in which web pages
+  build themselves "on the fly" when requested so that they are always up
+  to date.
+
+- Provide a simple file library of various documents that describe the
+  animals.
+
+Beginning with a Folder
+-----------------------
+
+Zope *Folder* objects provide natural containers and organizers for web
+applications.  A good way to start building an application is to create a
+new *Folder* to hold all the objects and subfolders related to the
+application.
+
+Consider, for example, a Zope folder named *Invoices* to hold an
+application for managing invoices through the Web.  The *Invoices* folder
+could contain both the logic objects - or "methods" - which allow you to
+add and edit invoices, as well as the actual data of the invoices.  The
+*Invoices* folder thus becomes a small Zope application.
+
+We begin building our Zope Zoo website application by creating a Zope
+*Folder* object to hold it all together in one place.
+
+Step 1: Create *ZopeZoo* Folder
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you haven't already, start your Zope installation and log into the Zope
+Management Interface (ZMI) using your favorite browser.  (If you are not
+familiar with the ZMI, refer to the `Installing and Starting Zope
+<InstallingZope.html>`_ chapter.)
+
+1. Navigate to Zope's top-level *root* folder.
+
+2. Use the *Add* list to create a new *Folder*.
+
+3. Give the new folder the *Id* 'ZopeZoo'.
+
+4. Check *Create public interface*.
+
+5. Click *Add*.
+
+(For now, we will ignore the optional *Title* fields.)
+
+Designing a Navigable Zoo
+-------------------------
+
+One of our goals is to enable easy user movement around the website.  A key
+to this easy movement is a navigation interface that is consistent among
+the site's pages.  In other words, every web page in the site should
+present a similar set of hyperlinks, in a similar place on the page, on
+which users can rely to guide them through the site.
+
+We also want to make sure the navigation links are always correct,
+regardless of how the structure of the site changes.  The solution is to
+design a meaningful site structure, and then create the Zope methods that
+will dynamically present the current structure to web users in the form of
+navigation links.
+
+First, let's define the site structure.  If the Zope Zoo was real, we might
+model the website's organization on the zoo's physical or logical design.
+For our purposes, we will pretend that the zoo houses three classes of
+animals.  We'll organize the website by adding folders inside our *ZopeZoo*
+folder.
+
+Step 2: Create Site Organization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Enter the *ZopeZoo* folder and create three subfolders with *Ids*:
+   'Reptiles', 'Mammals' and 'Fish'.
+
+2. Inside the *Mammals* folder, add one folder named 'Whales'.
+
+3. Navigate to the *Reptiles* folder and create two folders there:
+   'Lizards' and 'Snakes'.
+
+In Zope's Navigator frame on the left side, you should see an icon for the
+*ZopeZoo* folder.  (If you don't see it, click *Refresh* in the Navigator).
+To view the *ZopeZoo* folder hierarchy - i.e. our nascent web site's
+structure - expand the *ZopeZoo* folder by clicking the little plus sign
+next to the icon.  Similarly expand the zoo subfolders.  You'll see
+something like the figure below.
+
+.. figure:: Figures/zoo1.png
+
+   Zoo folder structure
+
+Now we create the basic presentation objects:  The main template and the
+style sheet *z_zoo.css*.  To get started, we ask a web designer to create a
+HTML mockup and a CSS file that together represent the web page layout
+shared throughout the site.
+
+For the style sheet we create a simple *File* object in Zope.  No need to
+make it dynamic.
+
+Step 3: Create the Style Sheet
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Go to the top level of our zoo website, the *ZopeZoo* folder.
+
+2. Select *File* from the *Add* list.
+
+3. Give the file an *Id* of 'z_zoo.css'.
+
+4. Click *Add*.
+
+5. Select *z_zoo.css* to get its *Edit* view.
+
+6. Copy and paste these style definitions into the *File Data* area::
+
+    body, p, th, td {
+      font-family: Verdana, Arial, Helvetica, sans-serif;
+      font-size: 10pt;
+    }
+    h1 {
+      color: #6699cc;
+      font-family: Verdana, Arial, Helvetica, sans-serif;
+      font-size: 18pt;
+      font-weight: bold;
+    }
+    p {
+      color: #660000;
+    }
+    .status_message{
+      background: #ffffaa;
+      border-style: solid;
+      border-width: thin;
+      font-weight: bold;
+      padding: 4pt;
+    }
+    th {
+      background: #dee7ec;
+      text-align: left;
+    }
+
+At this stage, the HTML page the web designer created for us is valid XHTML
+1.0 Strict and could also live in a static *File* object.  But in the next
+steps we will convert the page into a dynamic template by adding TAL and
+METAL statements, so we need a *Page Template* object.  For now we use the
+*index_html* method already added by selecting *Create public interface* in
+step 1.
+
+Step 4: Create the Main Template
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Select *index_html* to get its *Edit* view.
+
+2. Replace all of the stock template code with this::
+
+    <!DOCTYPE html PUBLIC
+        "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
+    <html>
+    <head>
+
+    <title>PAGE TITLE OR ID</title>
+    <link rel="stylesheet" href="z_zoo.css" type="text/css" />
+
+    </head>
+    <body>
+
+    <div>&gt; <a href="ABSOLUTE_URL">PARENT TITLE OR ID</a> </div>
+
+    <ul>
+      <li><a href="ABSOLUTE_URL">SUB-OBJECT TITLE OR ID</a></li>
+    </ul>
+
+    <h1>PAGE TITLE OR ID</h1>
+
+    <p class="status_message">STATUS MESSAGE</p>
+
+    <p>THIS IS WHERE THE PAGE'S CONTENT GOES.</p>
+
+    </body>
+    </html>
+
+Our web designer marked placeholders for dynamic elements with UPPERCASE
+letters.  Using the *Test* tab of the new template, we can see the static
+HTML page.  Don't blame the web designer for the spartan layout.  It's for
+the sake of an easy example.  If you don't understand the XHTML and CSS
+code you might want to learn more about HTML first.  This chapter shows you
+how to make that code dynamic.
+
+Step 5: Dynamic Title and Headline
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Go to the *Edit* tab of *index_html*.
+
+2. Find these two lines::
+
+    <title>PAGE TITLE OR ID</title>
+    ...
+    <h1>PAGE TITLE OR ID</h1>
+
+3. Change them to look like that::
+
+    <title tal:content="context/title_or_id">PAGE TITLE OR ID</title>
+    ...
+    <h1 tal:content="context/title_or_id">PAGE TITLE OR ID</h1>
+
+The *path expression* 'context/title_or_id' returns the *title* of the
+context object or - if that doesn't exist - its *id*.  We work in the
+context of the *ZopeZoo* folder, which has no title.  So clicking again on
+the *Test* tab you'll see that title and headline are replaced by the id
+*ZopeZoo*.  (You might want to open the *Test* tab in a new window to see
+the title of the browser window.)  After completing the next step you'll be
+able to navigate to subfolders and see title and headline change depending
+on the context.
+
+Step 6: Generate Subfolder Menu Dynamically
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Find the example menu item::
+
+    <ul>
+      <li><a href="ABSOLUTE_URL">SUB-OBJECT TITLE OR ID</a></li>
+    </ul>
+
+2. Extend it like this::
+
+    <ul tal:condition="python: context.objectValues(['Folder'])">
+      <li tal:repeat="item python: context.objectValues(['Folder'])">
+        <a href="ABSOLUTE_URL"
+           tal:attributes="href item/absolute_url"
+           tal:content="item/title_or_id">SUB-OBJECT TITLE OR ID</a></li>
+    </ul>
+
+The *Python expression* 'context.objectValues(['Folder'])' returns all the
+subfolders in our context.  The 'tal:condition' statement checks if any
+subfolders exist.  If not, the complete 'ul' element is removed.  That
+means we have reached a *leaf* of the navigation tree and don't need a
+subfolder menu.
+ 
+Otherwise, the same expression in the 'tal:repeat' statement of the 'li'
+element will return a list of subfolders.  The 'li' element will be
+repeated for each *item* of this list.  In step 3 we created three
+subfolders in the *ZopeZoo* folder, so using again the *Test* tab we will
+see three list items, each with the correct id and link URL.  For now there
+are no links back, so use the back button of your browser if you can't wait
+exploring the site.
+
+Step 7: Generate Breadcrumbs Dynamically
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Look for this line::
+
+    <div>&gt; <a href="ABSOLUTE_URL">PARENT TITLE OR ID</a> </div>
+
+2. Replace it by::
+
+    <div><tal:loop tal:repeat="item python: request.PARENTS[-2::-1]">&gt;
+      <a href="ABSOLUTE_URL"
+         tal:attributes="href item/absolute_url"
+         tal:content="item/title_or_id">PARENT TITLE OR
+                                        ID</a> </tal:loop></div>
+
+Using a trail of bread crumbs for navigation is quite an old idea, you
+might remember Hansel and Gretel tried that to find their way home.  In our
+days, breadcrumbs are used for site navigation and show the path back to
+the root (or home) of the site.
+
+The folder that contains the current object is also called its *parent*.
+As long as we have not reached the root object, each folder has again a
+*parent* folder.  'request.PARENTS' is a list of all these parents from the
+current object down to the root object of the Zope application.
+'request.PARENTS[-2::-1]' returns a copy of that list in reverse order,
+starting with the second last element.  We don't need the last value
+because 'ZopeZoo' is located in the second level of our Zope application
+and we just want to navigate within the zoo.
+
+We use again a 'tal:repeat' statement to display the list.  Because we
+don't want to repeat the 'div' element, we add a dummy TAL element that
+doesn't show up in the rendered HTML page.  Now our site navigation is
+complete and you can explore the sections of the zoo.
+
+Step 8: Dynamic Status Bar
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Go to this line::
+
+    <p class="status_message">STATUS MESSAGE</p>
+
+2. Extend it by two tal attributes::
+
+    <p class="status_message"
+       tal:condition="options/status_message | nothing"
+       tal:content="options/status_message">STATUS MESSAGE</p>
+
+We need the status bar later in this chapter.  For now all we need is to
+make it invisible.  'options/status_message' will later be used for some
+messages.  But most pages don't have that variable at all and this path
+expression would raise an error.  'options/status_message | nothing'
+catches that error and falls back to the special  value *nothing*.  This is
+a common pattern to test if a value exists **and** is true.
+
+Step 9: Improve Style Sheet Link
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Find this line in the HTML head::
+
+    <link rel="stylesheet" href="z_zoo.css" type="text/css" />
+
+2. Replace it by::
+
+    <link rel="stylesheet" href="z_zoo.css" type="text/css"
+          tal:attributes="href context/z_zoo.css/absolute_url" />
+
+While the relative URI of the *href* attribute works thanks to acquisition,
+this isn't a good solution.  Using the *index_html* method for different
+folders, the browser can't know that all the *z_zoo.css* files are in fact
+one and the same.  Besides the CSS file the basic layout often contains a
+logo and other images, so making sure they are requested only once makes
+your site faster and you waste less bandwidth.  The *path expression*
+'context/z_zoo.css/absolute_url' returns the absolute url of the CSS file.
+Using it in the *href* attribute we have a unique URI independent of the
+current context.
+
+Step 10: Factor out Basic Look and Feel
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Rename *index_html* to 'z_zoo.pt'.
+
+2. Wrap a 'metal:define-macro' statement around the whole page and add
+   two 'metal:define-slot' statements for headline and content.  After
+   all these changes our main template - now called *z_zoo.pt* - looks
+   like this::
+
+    <metal:macro metal:define-macro="page"><!DOCTYPE html PUBLIC
+        "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
+    <html>
+    <head>
+
+    <title tal:content="context/title_or_id">PAGE TITLE OR ID</title>
+    <link rel="stylesheet" href="z_zoo.css" type="text/css"
+          tal:attributes="href context/z_zoo.css/absolute_url" />
+
+    </head>
+    <body>
+
+    <div><tal:loop tal:repeat="item python: request.PARENTS[-2::-1]">&gt;
+      <a href="ABSOLUTE_URL"
+         tal:attributes="href item/absolute_url"
+         tal:content="item/title_or_id">PARENT TITLE OR
+                                        ID</a> </tal:loop></div>
+
+    <ul tal:condition="python: context.objectValues(['Folder'])">
+      <li tal:repeat="item python: context.objectValues(['Folder'])">
+        <a href="ABSOLUTE_URL"
+           tal:attributes="href item/absolute_url"
+           tal:content="item/title_or_id">SUB-OBJECT TITLE OR ID</a></li>
+    </ul>
+
+    <metal:slot metal:define-slot="headline">
+
+      <h1 tal:content="context/title_or_id">PAGE TITLE OR ID</h1>
+
+    </metal:slot>
+
+    <p class="status_message"
+       tal:condition="options/status_message | nothing"
+       tal:content="options/status_message">STATUS MESSAGE</p>
+
+    <metal:slot metal:define-slot="content">
+
+      <p>THIS IS WHERE THE PAGE'S CONTENT GOES.</p>
+
+    </metal:slot>
+
+    </body>
+    </html>
+    </metal:macro>
+
+3. Add again a new *Page Template* with the *id* 'index_html'.
+
+4. Replace the example code of *index_html* with these two lines::
+
+    <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
+    </metal:macro>
+
+Transforming our main template into an external macro and including it
+again using the 'metal:use-macro' statement doesn't change the resulting
+HTML page in any way.  But in the next step we can add code we only want to
+use in *index_html* without changing the main template.
+
+The 'metal:define-macro' statement in *z_zoo.pt* marks the complete
+template as reuseable macro, giving it the *id* *page*.  The expression
+'context/z_zoo.pt/macros/page' in *index_html* points to that macro.
+
+For later use we also added two 'metal:define-slot' statements within the
+macro.  That allows to override *headline* and *body* while reusing the
+rest of the macro.
+
+Step 11: Add Special Front Page Code
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Go to the *Edit* tab of the new *index_html*.
+
+2. Replace it by this code::
+
+    <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
+    <metal:slot metal:fill-slot="headline">
+
+      <h1>Welcome to the Zope Zoo</h1>
+
+    </metal:slot>
+    <metal:slot metal:fill-slot="content">
+
+      <p>Here you will find all kinds of cool animals. You are in the
+        <b tal:content="context/title_or_id">TITLE OR ID</b> section.</p>
+
+    </metal:slot>
+    </metal:macro>
+
+The *index_html* should serve as the welcome screen for zoo visitors.  In
+order to do so, we override the default slots.  Take a look at how your
+site appears by clicking on the *View* tab of the *ZopeZoo* folder.
+
+You can use the navigation links to travel through the various sections of
+the Zoo.  Use this navigation interface to find the reptiles section.  Zope
+builds this page to display a folder by looking for the default folder view
+method, *index_html*.  It walks up the zoo site folder by folder until it
+finds the *index_html* method in the *ZopeZoo* folder.  It then calls this
+method on the *Reptiles* folder.
+
+Modifying a Subsection of the Site
+----------------------------------
+
+What if you want the reptile page to display something besides the welcome
+message?  You can replace the *index_html* method in the reptile section
+with a more appropriate display method and still take advantage of the main
+template including navigation.
+
+Step 12: Create *index_html* for the Reptile House
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Go to the *Reptile* folder.
+
+2. Add a new *Page Template* named 'index_html'.
+
+3. Give it some content more appropriate to reptiles::
+
+    <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
+    <metal:slot metal:fill-slot="headline">
+
+      <h1>The Reptile House</h1>
+
+    </metal:slot>
+    <metal:slot metal:fill-slot="content">
+
+      <p>Welcome to the Reptile House.</p>
+
+      <p>We are open from 6pm to midnight Monday through Friday.</p>
+
+    </metal:slot>
+    </metal:macro>
+
+Now take a look at the reptile page by going to the *Reptile* folder and
+clicking the *View* tab.
+
+Since the *index_html* method in the *Reptile* folder uses the same macro
+as the main *index_html*, the reptile page still includes your navigation
+system.
+
+Click on the *Snakes* link on the reptile page to see what the Snakes
+section looks like.  The snakes page looks like the *Reptiles* page because
+the *Snakes* folder acquires its *index_html* display method from the
+*Reptiles* folder instead of from the *ZopeZoo* folder.
+
+Creating a File Library
+-----------------------
+
+File libraries are common on websites since many sites distribute files of
+some sort.  The old fashioned way to create a file library is to upload
+your files, then create a web page that contains links to those files.
+With Zope you can dynamically create links to files.  When you upload,
+change or delete files, the file library's links can change automatically.
+
+Step 13: Creating Library Folder and some Files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Add a new *Folder* to *ZopeZoo* with *Id* 'Files' and *Title* 'File
+   Library'.
+
+2. Within that folder, add two *File* objects called 'DogGrooming' and
+   'HomeScienceExperiments'.
+
+We don't need any content within the files to test the library.  Feel
+free to add some more files and upload some content.
+
+Step 14: Adding *index_html* Script and Template
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Within the *Files* folder, add this new *Script (Python)* with the
+   *Id* 'index_html'::
+
+    ## Script (Python) "index_html"
+    ##parameters=
+    ##
+    library_items = []
+    items = context.objectValues(['File'])
+    for item in items:
+        library_items.append(
+                { 'title': item.title_or_id(),
+                  'url': item.absolute_url(),
+                  'modified': item.bobobase_modification_time().aCommon()
+                  } )
+
+    options = { 'library_items': tuple(library_items) }
+
+    return options
+
+2. Also add a new *Page Template* named 'index_html.pt' with this
+   content::
+
+    <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
+    <metal:slot metal:fill-slot="content">
+
+      <table>
+        <tr>
+          <th width="300">File</th>
+          <th>Last Modified</th>
+        </tr>
+        <tr>
+          <td><a href="URL">TITLE</a></td>
+          <td>MON DD, YYYY H:MM AM</td>
+        </tr>
+      </table>
+
+    </metal:slot>
+    </metal:macro>
+
+This time the logic for our 'index_html' method will be more complex, so we
+should separate logic from presentation.  We start with two unconnected
+objects:  A *Script (Python)* to generate the results and a *Page Template*
+to present them as HTML page.
+
+The script loops over 'context.objectValues(['File'])', a list of all
+*File* objects in our *Files* folder, and appends for each file the needed
+values to the library_items list.  Again the dynamic values are UPPERCASE
+in our mockup, so what we need are the file *title*, the *url* and the last
+*modified* date in a format like this: Mar 1, 1997 1:45 pm.  Most Zope
+objects have the *bobobase_modification_time* method that returns a
+*DateTime* object.  Looking at the API of *DateTime*, you'll find that the
+*aCommon* method returns the format we want.
+
+Later we will have more return values, so we store them in the *options*
+dictionary.  Using the *Test* tab of the script you will see the returned
+dictionary contains all the dynamic content needed by our template.
+
+The template uses again the *page* macro of *z_zoo.pt*.  Unlike before
+there is only one 'metal:fill-slot' statement because we don't want to
+override the *headline* slot.  Go to the *Test* tab of the template to see
+how our file library will look like.
+
+Step 15: Bringing Things Together
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Replace the last line of the *index_html* script by this one::
+
+    return getattr(context, 'index_html.pt')(**options)
+
+2. Look for this example table row in *index_html.pt*::
+
+      <tr>
+        <td><a href="URL">TITLE</a></td>
+        <td>MON DD, YYYY H:MM AM</td>
+      </tr>
+
+3. Replace it by that code::
+
+      <tr tal:repeat="item options/library_items">
+        <td><a href="URL"
+               tal:attributes="href item/url"
+               tal:content="item/title">TITLE</a></td>
+        <td tal:content="item/modified">MON DD, YYYY H:MM AM</td>
+      </tr>
+
+Now our script calls the *index_html.pt* after doing all the computing and
+passes the resulting *options* dictionary to the template, which creates
+the HTML presentation of *options*.  The *Test* tab of the template no
+longer works because it now depends on the script.  Go to the *Test* tab of
+the script to see the result: The file library!
+
+If you add another file, Zope will dynamically adjust the file library
+page.  You may also want to try changing the titles of the files, uploading
+new files, or deleting some of the files.
+
+Step 16: Making the Library Sortable
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Find the table headers in *index_html.pt*::
+
+        <th width="300">File</th>
+        <th>Last Modified</th>
+
+2. Replace them with these dynamic table headers::
+
+        <th width="300"><a href="SORT_TITLE_URL"
+               tal:omit-tag="not: options/sort_title_url"
+               tal:attributes="href options/sort_title_url"
+               >File</a></th>
+        <th><a href="SORT_MODIFIED_URL"
+               tal:omit-tag="not: options/sort_modified_url"
+               tal:attributes="href options/sort_modified_url"
+               >Last Modified</a></th>
+
+3. Extend *index_html* to make it look like this::
+
+    ## Script (Python) "index_html"
+    ##parameters=sort='title'
+    ##
+    library_items = []
+    items = context.objectValues(['File'])
+    if sort == 'title':
+        sort_on = ( ('title_or_id', 'cmp', 'asc'), )
+        sort_title_url = ''
+        sort_modified_url = '%s?sort=modified' % context.absolute_url()
+    else:
+        sort_on = ( ('bobobase_modification_time', 'cmp', 'desc'), )
+        sort_title_url = '%s?sort=title' % context.absolute_url()
+        sort_modified_url = ''
+    items = sequence.sort(items, sort_on)
+    for item in items:
+        library_items.append(
+                { 'title': item.title_or_id(),
+                  'url': item.absolute_url(),
+                  'modified': item.bobobase_modification_time().aCommon()
+                  } )
+
+    options = { 'sort_title_url': sort_title_url,
+                'sort_modified_url': sort_modified_url,
+                'library_items': tuple(library_items) }
+
+    return getattr(context, 'index_html.pt')(**options)
+
+The changes in the template are quite simple.  If an url is provided, the
+column header becomes a link.  If not, the 'not:' expression of the
+'tal:omit-tag' statement is true and the 'a' tag is omitted.  The script
+will always provide an url for the column that isn't currently sorted.
+
+Basically we have to extend the logic, so most changes are in the script.
+First of all we define an optional parameter *sort*.  By default it is
+'title', so if no value is passed in we sort by title.  Sort criteria and
+urls depend on the sort parameter.  We use the sort function of the built
+in *sequence* module to apply the sort criteria to the *items* list.
+
+Now view the file library and click on the *File* and *Last Modified* links
+to sort the files.  If there is a *sort* variable and if it has a value of
+*modified* then the files are sorted by modification time.  Otherwise the
+files are sorted by *title*.
+
+Building "Instance-Space" Applications
+--------------------------------------
+
+In Zope, there are a few ways to develop a web application.  The simplest
+and fastest way, and the one we've been concentrating on thus far in this
+book, is to build an application in *instance space*.  To understand the
+term "instance space", we need to once again put on our "object orientation
+hats".
+
+When you create Zope objects by selecting them from the Zope "Add" list,
+you are creating *instances* of a *class* defined by someone else (see the
+`Object Orientation <ObjectOrientation.html>`_ chapter if you need to brush
+up on these terms).  For example, when you add a Script (Python) object to
+your Zope database, you are creating an instance of the Script (Python)
+class.  The Script (Python) class was written by a Zope Corporation
+engineer.  When you select "Script (Python)" from the Add list, and you
+fill in the form to give an id and title and whatnot, and click the submit
+button on the form, Zope creates an *instance* of that class in the Folder
+of your choosing.  Instances such as these are inserted into your Zope
+database and they live there until you delete them.
+
+In the Zope application server, most object instances serve to perform
+presentation duties, logic duties, or content duties.  You can "glue" these
+instances together to create basic Zope applications.  Since these objects
+are really instances of a class, the term "instance space" is commonly used
+to describe the Zope root folder and all of its subfolders.  "Building an
+application in instance space" is defined as the act of creating Zope
+object instances in this space and modifying them to act a certain way when
+they are executed.
+
+Instance-space applications are typically created from common Zope objects.
+Script (Python) objects, Folders, Page Templates, and other Zope services can
+be glued together to build simple applications.
+
+Instance-Space Applications vs. Python packages
+-----------------------------------------------
+
+In contrast to building applications in instance space, you may also build
+applications in Zope by building them as Python packages.  Building an
+application as a package differs from creating applications in instance
+space inasmuch as the act of creating a package typically is more familiar to
+developers and does not constrain them in any way.
+
+Building a package also typically allows you to more easily distribute an
+application to other people, and allows you to build objects that may more
+closely resemble your "problem space".
+
+Building a package is typically more complicated than building an
+"instance-space" application, so we get started here by describing how to
+build instance-space applications.  When you find that it becomes difficult
+to maintain, extend, or distribute an instance-space application you've
+written, it's probably time to reconsider rewriting it as a package.
+
+The Next Step
+-------------
+
+This chapter shows how simple web applications can be made.  Zope has many
+more features in addition to these, but these simple examples should get
+you started on create well managed, complex websites.
+
+In the next chapter, we'll see how the Zope security system lets Zope work
+with many different users at the same time and allows them to collaborate
+together on the same projects.

Copied: zope2docs/branches/baijum-reorganize/zope2book/UsingZope.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/UsingZope.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/UsingZope.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/UsingZope.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,429 @@
+Using the Zope Management Interface
+===================================
+
+Introduction
+------------
+
+When you log in to Zope, you are presented with the Zope Management
+Interface (ZMI).  The ZMI is a management and configuration environment that
+allows you to control Zope, manipulate Zope objects, and configure web
+applications.
+
+The Zope Management Interface represents a view into the Zope *object
+hierarchy*.  Almost every link or button in the ZMI represents an action
+that is taken against an *object*.  When you build web applications with
+Zope, you typically spend some of your time creating and managing objects.
+
+Don't be frightened if you don't understand the word "object" just yet.
+For the purposes of this chapter, the definition of an "object" is *any
+discrete item that is manageable through the ZMI*.  In fact, for the
+purposes of this chapter, you can safely replace the word "object" with the
+word "thing" with no ill effects.  If you do find something confusing,
+however, you may want to review the `Object
+Orientation <ObjectOrientation.html>`_ chapter for more detail on objects.
+
+How the Zope Management Interface Relates to Objects
+----------------------------------------------------
+
+Unlike web server applications like Apache or Microsoft IIS, Zope does not
+"serve up" HTML files that it finds on your server's hard drive.
+Similarly, the objects that Zope creates are not stored in ".html" files on
+your server.  There is no file hierarchy on your server's computer that
+contains all of your Zope objects.
+
+Instead, the objects that Zope creates are stored in a database called the
+"Zope Object DataBase", or the *ZODB*.  In default configurations, the ZODB
+creates a file named "Data.fs" in which Zope stores its objects.  The ZMI
+is the primary way by which you interact with Zope objects stored in this
+database.  Note that there are other methods of interacting with objects
+stored in the ZODB, including FTP and WebDAV, which are detailed in the
+chapter in this book entitled `Managing Zope Using External
+Tools <ExternalTools.stx>`_, but the ZMI is the primary management
+tool.
+
+ZMI Frames
+----------
+
+The ZMI uses three browser frames:
+
+- The left frame is called the *Navigator Frame*, which can be used to
+  expand or collapse a view into the Zope object hierarchy, much like you
+  would expand and collapse a view of files using a file tree widget like
+  the one in Windows Explorer.
+
+- The right frame is called the *Workspace Frame*, which displays a
+  particular view of the object you're currently managing.    
+
+- The top frame is called the *Status Frame*, which displays your user name
+  (when logged in), as well as a drop-down list that performs various
+  actions.
+
+The Navigator Frame
+~~~~~~~~~~~~~~~~~~~
+
+In the left-hand, or *Navigator*, frame, you have a view into the *root
+folder* and all of its subfolders.  The *root folder* is in the upper-left
+corner of the tree. The root folder is the "topmost" container of Zope
+objects: almost everything meaningful in your Zope instance lives inside
+the root folder.
+
+.. figure:: Figures/navigator.jpg
+  
+   The Navigator Frame
+
+Some of the folders in the Navigator are displayed with "plus mark" icons
+to their left.  These icons let you expand the folders to see the
+sub-folders inside them.
+
+When you click on an object icon or name in the Navigator, the *Workspace*
+frame will refresh with a view of that object.
+
+The Workspace Frame
+~~~~~~~~~~~~~~~~~~~
+
+The right-hand frame of the management interface shows the object you are
+currently managing.  When you first log into Zope, the root folder is
+displayed as the current object.  The workspace gives you information about
+the current object and lets you manage it.
+
+.. figure:: Figures/workspace.jpg
+
+   The Workspace Frame
+
+A series of tabs is displayed across the top of the screen. The tab that is
+currently active is highlighted in a lighter color.  Each tab takes you to
+a different *view* of the current object, and each view lets you perform a
+different management function on that object.
+
+When you first log into Zope, you are looking at the *Contents* view of the
+root folder object.
+
+At the top of the workspace, just below the tabs, is a description of the
+current object's type and URL. On the left is an icon representing the
+current object's type, and to the right of that is the object's URL.
+
+At the top of the page, 'Folder at /' tells you that the current object is
+a folder and that its path is "/".  Note that this path is the object's
+place relative to Zope's "root" folder. The root folder's path is expressed
+as "/" , and since you are looking at the root when you first log in, the
+path displayed at the the top of the workspace is simply "/".
+
+Zope object paths are typically mirrored in the URLs that are used to
+access a Zope object.  For instance, if the main URL of your Zope site was
+http://mysite.example.com:8080, then the URL of the root folder would be
+http://mysite.example.com:8080/ and the URL of 'Folder at /myFolder' would
+be 'http://mysite.example.com:8080/myFolder'.
+
+As you explore different Zope objects, you'll find that the links displayed
+at the top of the workspace frame can be used to navigate between objects'
+management views.  For example, if you are managing a folder at
+*/Zoo/Reptiles/Snakes*, you can return to the folder at */Zoo* by clicking
+on the word *Zoo* in the folder's URL.
+
+The Status Frame
+~~~~~~~~~~~~~~~~
+
+The "status frame" at the top of the management interface displays your
+current login name, along with a pull-down box that lets you select:
+
+- *Preferences*: By selecting this menu item, you can set default
+  preferences for your Zope management interface experience.  You can
+  choose to turn off the status frame.  You can also choose whether you
+  want the management interface to try to use style sheets.  Additionally,
+  you can change the default height and width of text-area boxes displayed
+  in the ZMI.  This information is associated with your browser via a
+  cookie.  It is not associated in any way with your Zope user account.
+
+- *Logout*: Selecting this menu item will log you out of Zope.
+  Due to the way that the HTTP "basic authentication" protocol works, this
+  may not behave properly with all browsers.  If you experience problems
+  logging out using this method, try closing and reopening your browser to
+  log out.
+
+.. figure:: Figures/statusframe.jpg
+ 
+   The Status Frame
+
+Creating Objects
+----------------
+
+The Zope Management Interface allows you to create new objects in your Zope
+instance.  To add a new object, select an entry from the pull-down menu in
+the Workspace labeled "Select type to add...".  This pull-down menu is
+called the *add list*.
+
+The first kind of object you'll want to add in order to "try out" Zope is a
+"Folder".  To create a Zope Folder object, navigate to the root folder and
+select *Folder* from the add list.  At this point, you'll be taken to an
+add form that collects information about the new folder, as shown in the
+figure below.
+
+.. figure:: Figures/addfolder.jpg
+
+   Folder add form
+
+Type "zoo" in the *Id* field, and "Zope Zoo" in the *Title* field.  Then
+click the *Add* button.
+
+Zope will create a new Folder object in the current folder named *zoo*. You
+can verify this by noting that there is now a new folder named *zoo* inside
+the root folder.
+
+Click on *zoo* to "enter" it. The Workspace frame will switch to the
+contents view of *zoo* (which is currently an "empty" folder, as it has no
+sub-objects or contents).  Note that the URL of the *zoo* folder is based
+on the folder's *id*.
+
+You can create more folders inside your new folder if you wish. For
+example, create a folder inside the *zoo* folder with an id of *arctic*.
+Enter the *zoo* folder and choose *Folder* from the pull-down menu. Then
+type in "arctic" for the folder id, and "Arctic Exhibit" for the title. Now
+click the *Add* button.
+
+When you use Zope, you create new objects by following these
+steps:
+
+1. Enter the folder where you want to add a new object.
+
+2. Choose the type of object you want to add from the add list.
+
+3. Fill out the resulting add form and submit it. As a result, Zope will
+   create a new object in the folder.
+
+Notice that every Zope object has an *id* that you need to specify in the
+add form when you create the object. The id is how Zope names objects.
+Objects also use their ids as a part of their *URL*.  The URL of any given
+Zope object is typically a URL consisting of the folders in which the
+object lives plus its name.  For example, we created a folder named "zoo"
+in the root folder.  If our site were called "mysite.example.com", the new
+folder's URL would be "http://mysite.example.com/zoo".
+
+Moving and Renaming Objects
+---------------------------
+
+Most computer systems let you move files around in directories with cut,
+copy, and paste actions. The ZMI uses a similar system that lets you move
+objects around in folders by cutting or copying them, and then pasting them
+to a new location.
+
+.. Note:
+   Zope move and rename options require that you have cookies enabled in
+   your browser.
+
+To experiment with copy and paste, create a new Folder object in the root
+folder with an id of *bears*.  Then select *bears* by checking the check
+box just to the left of the folder. Then click the *Cut* button. Cut
+selects the selected objects from the folder and places them on Zope's
+"clipboard".  The object will *not*, however, disappear from its location
+until it is pasted somewhere else.
+
+Now enter the *zoo* folder by clicking on it. Click the *Paste* button to
+paste the cut object into the *zoo* folder. You should see the *bears*
+folder appear in its new location. You can verify that the folder has been
+moved by going to the root folder and confirming that *bears* is no longer
+visible there.
+
+Copy works similarly to cut, in that, when you paste copied objects, the
+original objects are not removed.  Select the object(s) you want to copy
+and click the *Copy* button. Then navigate to another folder and click the
+*Paste* button.
+
+You can cut and copy folders that contain other objects and move many
+objects at one time with a single cut and paste.  For example, go to the
+root folder, and copy the *zoo* folder. Now paste it into the root folder.
+You will now have two folders inside the root folder: *zoo* and
+*copy_of_zoo*. If you paste an object into the same folder where you copied
+it, Zope will change the id of the pasted object. This is a necessary step,
+as you cannot have two objects with the same id in the same folder.
+
+To rename the *copy_of_zoo* folder, select the folder by checking the check
+box to the left of the folder. Then click the *Rename* button.  This will
+take you to the rename form.
+
+.. figure:: Figures/renamezoo.jpg
+
+   Renaming an Object
+
+Type in the new id value "zoo2" and click *OK*. Zope ids can consist of
+letters, numbers, spaces, dashes, underscores, and periods, and they are
+case-sensitive. Here are some legal Zope ids: *index.html*, *42*,
+*Lucky13*, and *Snake-Pit*.
+
+Now your root folder contains *zoo* and *zoo2* folders. Each of these
+folders contains a *bears* folder. This is because when we made a copy of
+the *zoo* folder, we also copied the *bears* folder that it contained.
+Copying an object also copies all of the objects it contains.
+
+If you want to delete an object, select it and then click the *Delete*
+button. Unlike cut objects, deleted objects are not placed on the clipboard
+and cannot be pasted. In the next section, we'll see how we can retrieve
+deleted objects using Undo.
+
+Zope will not let you cut, delete, or rename a few particular objects in
+the root folder. These objects include *Control_Panel*,
+*browser_id_manager*, and *temp_folder*.  These objects are necessary for
+Zope's operation.  It is possible to delete other root objects, such as
+*index_html*, *session_data_manager* and *standard_error_message*,
+but it is not recommended to do so unless you have a very good reason.
+
+Transactions and Undoing Mistakes
+---------------------------------
+
+All objects you create in Zope are stored in Zope's "object database".
+Unlike other web application servers, Zope doesn't store its objects in
+files on a filesystem.  Instead, all Zope objects are stored by default in
+a single special file on the filesystem named 'Data.fs'.  This file is
+stored in the 'var' directory of your Zope instance.  Using an object
+database rather than storing objects on the file system allows operations
+to Zope objects to be *transactional*.
+
+A transactional operation is one in which all changes to a set of objects
+are committed as a single "batch".  In Zope, a single web request initiates
+a transaction.  When the web request is finished, Zope commits the
+transaction unless an error occurs during the processing of the request.
+If there is an error, Zope refrains from committing the transaction. Each
+transaction describes all of the changes that happen in the course of
+performing a web request.
+
+Most actions in Zope that causes a transaction can be undone via the *Undo*
+tab.  You can recover from mistakes by undoing the transaction that
+represents the mistake.  This includes undo actions themselves, which can
+also be undone to restore an object to its state before the undo action.
+
+Select the *zoo* folder that we created earlier and click *Delete*. The
+folder disappears. You can get it back by undoing the delete action.
+
+Click the *Undo* tab, as shown in the figure below.
+
+.. figure:: Figures/delzoo.jpg
+
+   The Undo view
+
+Transactions are named after the Zope action, or "method", that initiated
+them.  In this case, the initiating method was one named
+``/manage_delObjects``, which is the name of the Zope action that deletes
+Zope objects.
+
+Select the first transaction labeled */manage_delObjects*, and click the
+*Undo* button at the bottom of the form.  Doing so instructs Zope to undo
+the last transaction. You can verify that the task has been completed by
+visiting the root folder to confirm that the *zoo* folder has returned.  If
+you use the "Back" button to revisit the root folder, you may need to
+refresh your browser to see the proper results.  To see the effect in the
+*Navigator* pane, click the "Refresh" link within the pane.
+
+You may "undo an undo" action, or "redo" the action, and you can undo and
+redo actions as many times as you like.  When you perform a "redo", Zope
+inserts a transaction into the undo log describing the redo action.
+
+The Undo tab is available on most Zope objects.  When viewing the Undo tab
+of a particular object, the list of undoable transactions is filtered down
+to the transactions that have recently affected the current object and its
+sub-objects.
+
+Undo Details and Gotchas
+------------------------
+
+You cannot undo a transaction upon which a later transaction depends.  For
+example, if you paste an object into a folder, and then delete an object in
+the same folder, pasting the first object cannot be undone, as both
+transactions affect the contents of a single object: the folder. The
+solution is to undo both transactions. You can undo more than one
+transaction at a time by selecting multiple transactions on the *Undo* tab
+and then clicking *Undo*.  
+
+Only changes to objects stored in Zope's object database can be undone.  If
+you have integrated data into a relational database server, such as Oracle
+or MySQL (as discussed in the chapter entitled "Relational Database
+Connectivity"), changes to data stored there cannot be undone.
+
+Reviewing Change History
+------------------------
+
+The Undo tab will provide you with enough information to know that a change
+has occurred.  However, it will not tell you much about the effect of the
+transaction on the objects that were changed during the transaction.
+
+Using Object Properties
+-----------------------
+
+*Properties* are ways of associating information with many objects in Zope,
+including folders.  For example, many Zope content objects have a content
+type property, and others contain metadata about the object, such as its
+author, title, or status.
+
+Properties can provide more complex data than strings, such as numbers,
+lists, and other data structures.  All properties are managed via the
+*Properties* view.  Click on the *Properties* tab of the "root" object, and
+you will be taken to the properties management view, as seen in the figure
+below.
+
+.. figure:: Figures/rootproperties.jpg
+
+   The Properties Management View
+
+A property consists of a name, a value, and a type.  A property's type
+defines what kind of value or values it can have.
+
+In the figure above, you can see that the folder has a single string
+property *title*, which has the value 'Zope'.  You may change any
+predefined property by changing its value in the Value box, and then
+clicking *Save Changes*.  You may add additional properties to an object by
+entering a name, value, and type into the bottom-most field in the
+Properties view.
+
+Zope supports a number of property types and each type is suited to a
+specific task.  This list gives a brief overview of the kinds of properties
+you can create from the management interface:
+
+string
+  A string is a sequence of characters of arbitrary length.
+  Strings are the most basic and useful type of property in Zope.
+
+int
+  An int property is an integer, which can be any positive or
+  negative number that is not a fraction.  An int is guaranteed to be
+  at least 32 bits long.
+
+long
+  A long is an integer that has no range limitation.
+
+float
+  A float holds a floating point, or decimal number.
+  Monetary values, for example, often use floats.
+
+lines
+  A lines property is a sequence of strings.
+
+tokens
+  A tokens property is a list of words separated by spaces.
+
+text
+  A text property is just like a string property, except that
+  Zope normalizes the line ending characters (different browsers use
+  different line ending conventions).
+
+selection
+  A selection property is special, in that it is used to render
+  an HTML single selection input widget.
+
+multiple selection
+  A multiple selection property is special, in that it
+  is used to render an HTML multiple selection form input widget.
+
+Properties are very useful tools for tagging your Zope objects with bits of
+metadata.  Properties are supported by most Zope objects and are often
+referenced by your application logic for purposes of data display.
+
+Logging Out
+-----------
+
+You may choose *Logout* from the Status Frame drop-down box to attempt to
+log out of Zope.  Doing so will cause your browser to "pop up" an
+authentication dialog.  Due to the way most web browsers work, you may
+actually need to click on the "OK" button with an *incorrect* user name and
+password in the authentication dialog in order to effectively log out of
+the ZMI.  If you do not do so, you may find even after selecting "Logout"
+that you are still logged in.  This is an intrinsic limitation of the HTTP
+Basic Authentication protocol, which Zope's stock user folder employs.
+Alternately, you may close and reopen your browser to log out of Zope.

Copied: zope2docs/branches/baijum-reorganize/zope2book/VirtualHosting.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/VirtualHosting.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/VirtualHosting.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/VirtualHosting.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,503 @@
+Virtual Hosting Services
+========================
+
+Zope comes with one object that help you do virtual hosting:
+*Virtual Host Monster*. Virtual hosting is a way to
+serve many websites with one Zope server.
+
+Virtual Host Monster
+--------------------
+
+Zope objects need to generate their own URLs from time to time.
+For instance, when a Zope object has its "absolute_url" method
+called, it needs to return a URL which is appropriate for
+itself.  This URL typically contains a hostname, a port, and a
+path.  In a "default" Zope installation, this hostname, port,
+and path is typically what you want.  But when it comes time to
+serve multiple websites out of a single Zope instance, each with
+their own "top-level" domain name, or when it comes time to
+integrate a Zope Folder within an existing website using Apache
+or another webserver, the URLs that Zope objects generate need
+to change to suit your configuration.
+
+A Virtual Host Monster's only job is to change the URLs which
+your Zope objects generate.  This allows you to customize the
+URLs that are displayed within your Zope application, allowing
+an object to have a different URL when accessed in a different
+way.  This is most typically useful, for example, when you wish
+to "publish" the contents of a single Zope Folder
+(e.g. '/FooFolder') as a URL that does not actually contain this
+Folder's name (e.g as the hostname 'www.foofolder.com').
+
+The Virtual Host Monster performs this job by intercepting and
+deciphering information passed to Zope within special path
+elements encoded in the URLs of requests which come in to Zope.
+If these special path elements are absent in the URLs of
+requests to the Zope server, the Virtual Host Monster does
+nothing.  If they are present, however, the Virtual Host Monster
+deciphers the information passed in via these path elements and
+causes your Zope objects to generate a URL that is different
+from their "default" URL.
+
+The Zope values which are effected by the presence of a Virtual
+Host Monster include REQUEST variables starting with URL or BASE
+(such as URL1, BASE2, URLPATH0), and the absolute_url() methods
+of objects.
+
+Virtual Host Monster configuration can be complicated, because
+it requires that you *rewrite* URLs "on the way in" to Zope.  In
+order for the special path elements to be introduced into the
+URL of the request sent to Zope, a front-end URL "rewriting"
+tool needs to be employed.  Virtual Host Monster comes with a
+simple rewriting tool in the form of its *Mappings* view, or
+alternately you can use Apache or another webserver to rewrite
+URLs of requests destined to Zope for you.
+
+Adding a Virtual Host Monster to your Zope
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+VirtualHostMonster is one of the add menu items supplied by the
+stock Zope Product, 'SiteAccess'.  You can add one to any folder
+by selecting its entry from the add menu and supplying an ID for
+it (the ID you choose doesn't matter, except that it must not
+duplicate the ID of another object in that folder).
+
+Where to Put a Virtual Host Monster And What To Name It
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A single Virtual Host Monster in your Zope root can handle all
+of your virtual hosting needs. It doesn't matter what 'id' you
+give it, as long as nothing else in your site has the same
+'id'.
+
+Configuring the VirtualHostMonster
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The default mode for configuring the VirtualHostMonster is not
+to do any configuration at all!  Rather, the external webserver
+modifies the request URL to signal what the *real* public URL for
+the request is (see "Apache Rewrite Rules" below).
+
+If you *do* choose to change the settings of your VHM, the easiest
+method to do so is to use the VHM's ZMI interface (as explained in
+the "Virtual Host Monster *Mappings* Tab" and "Inside-Out Virtual
+Hosting" sections below.
+
+It is possible to modify the VHM settings from the command line
+via Zope debugger;  no documentation for the low-level API
+exists, however, except "the source",
+'Products.SiteAccess.VirtualHostMonster.py,
+which makes it an inadvisable choice for anyone but an experienced
+Zope developer.
+
+Special VHM Path Elements 'VirtualHostBase' and 'VirtualHostRoot'
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A Virtual Host Monster doesn't do anything unless it sees one
+of the following special path elements in a URL:
+
+'VirtualHostBase'
+  if a VirtualHostMonster "sees" this name in the incoming URL, it causes
+   Zope objects to generate URLs with a potentially different protocol, a
+   potentially different hostname, and a potentially different port number.
+
+'VirtualHostRoot'
+  if a VirtualHostMonster "sees" this name in the incoming URL, it causes
+   Zope objects to generate URLs which have a potentially different "path
+   root"
+
+'VirtualHostBase'
+%%%%%%%%%%%%%%%%%
+
+The 'VirtualHostBase' declaration is typically found at the
+beginning of an incoming URL.  A Virtual Host Monster will
+intercept two path elements following this name and will use
+them to compose a new protocol, hostname, and port number.
+
+The two path elements which must follow a 'VirtualHostBase'
+declaration are 'protocol' and 'hostname:portnumber'.  They
+must be separated by a single slash.  The colon and
+portnumber parts of the second element are optional, and if
+they don't exist, the Virtual Host Monster will not change
+the port number of Zope-generated URLs.
+
+Examples:
+
+- If a VHM is installed in the root folder, and a request comes in to
+  your Zope with the URL:
+
+   'http://zopeserver:8080/VirtualHostBase/http/www.buystuff.com'
+
+  URLs generated by Zope objects will start with
+  'http://buystuff.com:8080'.
+
+- If a VHM is installed in the root folder, and a request comes in to
+  your Zope with the URL:
+
+   'http://zopeserver:8080/VirtualHostBase/http/www.buystuff.com:80'
+
+  URLs generated by Zope objects will start with 'http://buystuff.com'
+  (port 80 is the default port number so it is left out).
+
+- If a VHM is installed in the root folder, and a request comes in to
+  your Zope with the URL:
+
+   'http://zopeserver:8080/VirtualHostBase/https/www.buystuff.com:443'
+
+  URLs generated by Zope objects will start with 'https://buystuff.com/'.
+  (port 443 is the default https port number, so it is left off.
+
+One thing to note when reading the examples above is that if
+your Zope is running on a port number like 8080, and you
+want generated URLs to not include this port number and
+instead be served on the standard HTTP port (80), you must
+specifically include the default port 80 within the
+VirtualHostBase declaration, e.g.
+'/VirtualHostBase/http/www.buystuff.com:80'.  If you don't
+specify the ':80', your Zope's HTTP port number will be used
+(which is likely not what you want).
+
+'VirtualHostRoot'
+%%%%%%%%%%%%%%%%%
+
+The 'VirtualHostRoot' declaration is typically found near
+the end of an incoming URL.  A Virtual Host Monster will
+gather up all path elements which *precede* and *follow* the
+'VirtualHostRoot' name, traverse the Zope object hierarchy
+with these elements, and publish the object it finds with
+the path rewritten to the path element(s) which *follow*
+the 'VirtualHostRoot' name.
+
+This is easier to understand by example.  For a URL
+'/a/b/c/VirtualHostRoot/d', the Virtual Host Monster will
+traverse "a/b/c/d" and then generate a URL with path /d.
+
+Examples:
+
+- If a VHM is installed in the root folder, and a request comes in to
+  your Zope with the URL:
+
+   'http://zopeserver:8080/Folder/VirtualHostRoot/
+
+  The object 'Folder' will be traversed to and published,
+  URLs generated by Zope will start with
+  'http://zopeserver:8080/', and when they are visited, they
+  will be considered relative to 'Folder'.
+
+- If a VHM is installed in the root folder, and a request comes in to
+  your Zope with the URL:
+
+   'http://zopeserver:8080/HomeFolder/VirtualHostRoot/Chris
+
+  The object '/Folder/Chris' will be traversed to and
+  published, URLs generated by Zope will start with
+  'http://zopeserver:8080/Chris', and when they are visited,
+  they will be considered relative to '/HomeFolder/Chris'.
+
+Using 'VirtualHostRoot' and 'VirtualHostBase' Together
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The most common sort of virtual hosting setup is one in which
+you create a Folder in your Zope root for each domain that you
+want to serve. For instance the site http://www.buystuff.com
+is served from a Folder in the Zope root named /buystuff while
+the site http://www.mycause.org is served from a Folder in the
+Zope root named /mycause.  In order to do this, you need to
+generate URLs that have both 'VirtualHostBase' and
+'VirtualHostRoot' in them.
+
+To access /mycause as http://www.mycause.org/, you would cause
+Zope to be visited via the following URL::
+
+  /VirtualHostBase/http/www.mycause.org:80/mycause/VirtualHostRoot/
+
+In the same Zope instance, to access /buystuff as
+http://www.buystuff.com/, you would cause Zope to be visited
+via the following URL::
+
+  /VirtualHostBase/http/www.buystuff.com:80/buystuff/VirtualHostRoot/
+
+Testing a Virtual Host Monster
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Set up a Zope on your local machine that listens on HTTP port
+8080 for incoming requests.
+
+Visit the root folder, and select *Virtual Host Monster* from
+the Add list.  Fill in the 'id' on the add form as 'VHM' and
+click 'Add.'
+
+Create a Folder in your Zope root named 'vhm_test'.  Within the
+newly-created 'vhm_test' folder, create a DTML Method named
+'index_html' and enter the following into its body::
+
+   <html>
+   <body>
+   <table border="1">
+     <tr>
+       <td>Absolute URL</td>
+       <td><dtml-var absolute_url></td>
+     </tr>
+     <tr>
+       <td>URL0</td>
+       <td><dtml-var URL0></td>
+     </tr>
+     <tr>
+       <td>URL1</td>
+       <td><dtml-var URL1></td>
+     </tr>
+   </table>
+   </body>
+   </html>
+
+View the DTML Method by clicking on its View tab, and you will
+see something like the following::
+
+  Absolute URL   http://localhost:8080/vhm_test 
+  URL0           http://localhost:8080/vhm_test/index_html
+  URL1           http://localhost:8080/vhm_test 
+
+Now visit the URL 'http://localhost:8080/vhm_test'.  You will be
+presented with something that looks almost exactly the same.
+
+Now visit the URL
+'http://localhost:8080/VirtualHostBase/http/zope.com:80/vhm_test'.
+You will be presented with something that looks much like this::
+
+  Absolute URL   http://zope.com/vhm_test 
+  URL0           http://zope.com/vhm_test/index_html
+  URL1           http://zope.com/vhm_test
+
+Note that the URLs that Zope is generating have changed.
+Instead of using 'localhost:8080' for the hostname and path,
+we've instructed Zope, through the use of a VirtualHostBase
+directive to use 'zope.com' as the hostname.  No port is shown
+because we've told Zope that we want to generate URLs with a
+port number of 80, which is the default http port.
+
+Now visit the URL
+'http://localhost:8080/VirtualHostBase/http/zope.com:80/vhm_test/VirtualHostRoot/'.
+You will be presented with something that looks much like this::
+
+  Absolute URL   http://zope.com
+  URL0           http://zope.com/index_html
+  URL1           http://zope.com
+
+Note that we're now publishing the 'vhm_test' folder as if it
+were the root folder of a domain named 'zope.com'.  We did this
+by appending a VirtualHostRoot directive to the incoming URL,
+which essentially says "traverse to the vhm_root folder as if it
+were the root of the site."
+
+Arranging for Incoming URLs to be Rewritten
+-------------------------------------------
+
+At this point, you're probably wondering just how in the world
+any of this helps you.  You're certainly not going to ask
+people to use their browser to visit a URL like
+'http://yourserver.com//VirtualHostBase/http/zope.com/vhm_test/VirtualHostRoot/'
+just so your Zope-generated URLs will be "right".  That would
+defeat the purpose of virtual hosting entirely.  The answer is:
+don't ask humans to do it, ask your computer to do it.  There
+are two common (but mutually exclusive) ways to accomplish
+this: via the VirtualHostMonster *Mappings* tab and via Apache
+"rewrite rules" (or your webserver's facility to do the same
+thing if you don't use Apache).  Be warned: use either one of
+these facilities or the other but not both or very strange
+things may start to happen.  We give examples of using both
+facilities below.
+
+Virtual Host Monster *Mappings* Tab
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Use the Virtual Host Monster's *Mappings* tab to cause your
+URLs to be rewritten if:
+
+- You run a "bare" Zope without a front-end webserver like
+  Apache.
+
+- You have one or more folders in your Zope that you'd like
+  to publish as "http://some.hostname.com/" instead of
+  "http://hostname.com/a/folder".
+
+The lines entered into the *Mappings* tab are in the form::
+
+  www.example.com /path/to/be/rewritten/to
+
+You can also match multiple subdomains by putting "\*." in front
+of the host name in the mapping rule.  For example::
+
+  *.example.com /folder 
+  
+This example  will match "my.example.com",
+"zoom.example.com", etc. If an exact match exists, it is
+used instead of a wildcard match.
+
+The best way to explain how to use the *Mappings* tab is by
+more specific example.  Assuming you've added a Virtual Host 
+Monster object in your root folder on a Zope running on 'localhost'
+on port 8080, create an alias in your local system's 'hosts'
+file (in /etc/hosts on UNIX and in
+c:\WINNT\system32\drivers\etc\hosts on Windows) that looks
+like this::
+
+  127.0.0.1 www.example.com
+
+This causes your local machine to contact itself when a
+hostname of 'wwww.example.com' is encountered.  For the sake
+of this example, we're going to want to contact Zope via the
+hostname 'www.example.com' through a browser (also on your
+local host) and this makes it possible.
+
+Then visit the VHM in the root folder and click on its
+*Mappings* tab.  On a line by itself enter the following::
+
+  www.example.com:8080/vhm_test
+
+This will cause the 'vhm_test' folder to be published when
+we visit 'http://www.example.com:8080'.  Visit
+'http://www.example.com:8080'.  You will see::
+
+  Absolute URL   http://www.example.com:8080
+  URL0           http://www.example.com:8080/index_html
+  URL1           http://www.example.com:8080
+
+In the "real world" this means that you are "publishing" the
+'vhm_test' folder as http://'www.example.com:8080'.
+
+Note that it is not possible to rewrite the port part
+(by default, '8080') of the URL this way. To change the
+port Zope is listening on, you will have to configure
+Zope's start parameter or use Apache rewriting.
+
+Apache Rewrite Rules
+~~~~~~~~~~~~~~~~~~~~
+
+If you use Apache in front of Zope, instead of using the
+*Mappings* tab, you should use Apache's rewrite rule
+functionality to rewrite URLs in to Zope.  The way this
+works is straightforward: Apache listens on its "normal"
+port, typically port 80.  At the same time, Zope's web
+server (on the same host or on another host) listens on a
+different port (typically 8080).  Apache accepts requests on
+its listening port.  A virtual host declaration in Apache's 
+configuration tells Apache to apply the contained
+directives to the specified virtual host.
+
+Using Apache's rewrite rule functionality requires that the
+'mod_rewrite' and 'mod_proxy' Apache modules be enabled.
+This can for instance be done by configuring Apache with the
+'--enable-modules="rewrite proxy"' flag during compile time or
+by loading the corresponding shared modules.
+
+If you are using the new Apache 2 series, you will also have
+to include the 'mod_proxy_http' module. See the "Apache
+mod_rewrite documentation",
+http://httpd.apache.org/docs/trunk/mod/mod_rewrite.html
+for details.
+
+You can check whether you have the required modules installed
+in Apache by examinint 'LoadModule' section of httpd.conf
+
+After you've got Apache configured with mod_rewrite
+and mod_proxy (and, depending on your Apache version,
+mod_proxy_http), you can start configuring Apache's
+config file and Zope for the following example.
+Assuming you've added a Virtual Host Monster object in
+your root folder on a Zope running on 'localhost' on
+port 8080, create an alias in your local system's
+'hosts' file (in /etc/hosts on UNIX and in
+c:\WINNT\system32\drivers\etc\hosts on Windows) that
+looks like this::
+
+  127.0.0.1 www.example.com
+
+This causes your local machine to contact itself when a
+hostname of 'wwww.example.com' is encountered.  For the sake
+of this example, we're going to want to contact Zope via the
+hostname 'www.example.com' through a browser (also on your
+local host) and this makes it possible.
+
+Note:  On MacOS X Server, the 'Server Admin.app' program
+simplifies adding virtual host definitions to your Apache.
+This application can make and maintain virtual host , access
+log, etc. 
+
+Now, assuming you've got Apache running on port 80 and Zope
+running on port 8080 on your local machine, and assuming
+that you want to serve the folder named 'vhm_test' in Zope
+as 'www.example.com' and, add the following to your Apache's
+'httpd.conf' file and restart your Apache process::
+
+  NameVirtualHost *:80
+  <VirtualHost *:80>
+  ServerName www.example.com
+  RewriteEngine On
+  RewriteRule ^/(.*) http://127.0.0.1:8080/VirtualHostBase/http/www.example.com:80/vhm_test/VirtualHostRoot/$1 [L,P]
+  </VirtualHost>
+
+If you want to proxy SSL to Zope, you need a similar directive
+for port 443::
+
+   NameVirtualHost *:443
+   <VirtualHost *:443>
+   ServerName www.example.com
+   SSLProxyEngine on
+   RewriteEngine On
+   RewriteRule ^/(.*) http://127.0.0.1:8080/VirtualHostBase/https/www.example.com:443/vhm_test/VirtualHostRoot/$1 [L,P]
+   </VirtualHost>
+
+Note: the long lines in the RewriteRule directive above
+*must* remain on a single line, in order for Apache's
+configuration parser to accept it.
+
+
+When you visit 'http://www.example.com' in your browser, you
+will see::
+
+  Absolute URL   http://www.example.com
+  URL0           http://www.example.com/index_html
+  URL1           http://www.example.com
+
+This page is being served by Apache, but the results are
+coming from Zope.  Requests come in to Apache with "normal"
+URLs (e.g. 'http://www.example.com').  The VirtualHost
+stanza in Apache's httpd.conf causes the request URL to be
+rewritten (e.g. to
+'http://127.0.0.1:8080/VirtualHostBase/http/www.example.com:80/vhm_test/VirtualHostRoot/').
+Apache then calls the rewritten URL, and returns the result.
+
+See the "Apache Documentation",
+http://httpd.apache.org/docs/2.0/misc/rewriteguide.html
+for more information on the subject of rewrite rules.
+
+Virtual Hosting Considerations for Content classes
+--------------------------------------------------
+
+Be sure that content objects catalog themselves using as their
+unique ID a "site-relative" path, rather than their full physical
+path;  otherwise, the object will be findable when using the site
+without virtual hosting, but not with, or vice versa.
+
+"Inside-Out" Virtual Hosting
+----------------------------
+
+Another use for virtual hosting is to make Zope appear to be
+part of a site controlled by another server. For example, Zope
+might only serve the contents of
+'http://www.mycause.org/dynamic_stuff', while Apache or
+another webserver serves files via
+'http://www.mycause.org/'. To accomplish this, you want to add
+"dynamic_stuff" to the start of all Zope-generated URLs.
+
+If you insert VirtualHostRoot, followed by one or more path
+elements that start with '_vh_', then these elements will be
+ignored during traversal and then added (without the '_vh_')
+to the start of generated URLs. For instance, a request for
+"/a/VirtualHostRoot/_vh_z/" will traverse "a" and then
+generate URLs that start with /z.
+
+In our example, you would have the main server send requests
+for http://www.mycause.org/dynamic_stuff/anything to Zope,
+rewritten as /VirtualHostRoot/_vh_dynamic_stuff/anything.
+

Copied: zope2docs/branches/baijum-reorganize/zope2book/ZEO.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/ZEO.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/ZEO.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/ZEO.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,596 @@
+Scalability and ZEO
+###################
+
+When a web application receives more requests than it can handle over a short
+period of time, it can become unresponsive. In the worst case, too many
+concurrent requests to a web application can cause the software which services
+the application to crash. This can be a problem for any kind of web-based app,
+not just those which are served by Zope.
+
+The obvious solution to this problem is to use more than one server. When one
+server becomes overloaded, the others can then hopefully continue to
+successfully serve requests. By adding additional servers to this kind of
+configuration, you can "scale" your web application as necessary to meet
+demand.
+
+Using multiple servers has obvious benefits, but it also poses serious
+challenges. For example, if you have five servers, then you must ensure that
+all five server installations are populated with the same information. This is
+not a very hard task if you have only a few static web pages, but for larger
+applications with large bodies of rapidly changing information, manually
+synchronizing the data which drives five separate server installations is
+almost impossible, even with the "out of the box" features that Zope provides.
+
+A "stock" Zope installation uses the Zope Object Database as its content store,
+using a "storage" which is named a "FileStorage". This storage type (there are
+others) keeps all of your Zope data in a single file on your computer's hard
+drive, typically named `Data.fs`. This configuration works well until you need
+to add an additional Zope server to your site to handle increased traffic to
+your web application. Two Zope servers cannot share this file. The file is
+"locked" by one Zope server and no other Zope server can access the file. Thus,
+in a "stock" Zope configuration, it is impossible to add Zope servers which
+read from the same database in order to "scale" your web application to meet
+demand.
+
+To solve this problem, Zope Corporation has created another kind of "storage",
+which operates using a client/server architecture, allowing many Zopes to share
+the same database information. This product is known as `Zope Enterprise
+Objects` or ZEO. ZEO is built into Zope, no additional software install is
+required.
+
+This chapter gives you a brief overview on installing ZEO, but there are many
+other options we don't cover. For more in-depth information, see the
+documentation that comes with the ZEO package, and also take a look at the
+`ZODB and ZEO discussion area <http://www.zope.org/Wikis/ZODB/FrontPage>`_.
+
+What is ZEO?
+============
+
+ZEO is a system that allows you to share a Zope Object Database between more
+than one Zope process. By using ZEO, you may run multiple instances of Zope on
+a single computer or on multiple computers. Thus, you may spread requests to
+your web application between Zope servers. You may add more computers as the
+number of requests grows, allowing your web application to scale. Furthermore,
+if one Zope server fails or crashes, other servers can still service requests
+while you fix the broken one. ZEO takes care of making sure each Zope
+installation uses consistent information from the same Zope Object Database.
+
+ZEO uses a client/server architecture. The Zope processes (shown on multiple
+computers in the diagram below) are the *ZEO Clients*. All of the clients
+connect to one, central *ZEO Storage Server*, as shown in the image below.
+
+`Simple ZEO illustration <img:20-1:Figures/11-1.png>`_
+
+The terminology may be a bit confusing. Typically, you may think of Zope as a
+server, not a client. But when using ZEO, your Zope processes act as both
+servers (for web requests) and clients (for data from the ZEO server).
+
+ZEO clients and servers communicate using standard Internet protocols, so they
+can be in the same room or in different countries. ZEO, in fact, could
+distribute a Zope site to disparate geographic locations, given good network
+connectivity between the ZEO clients and the ZEO server. In this chapter we'll
+explore some interesting ways you can distribute your ZEO clients.
+
+When you should use ZEO
+=======================
+
+Using a ZEO-based installation is advantageous for almost all users. Here are
+some of the reasons:
+
+- Zope is a high-performance system, and one Zope can handle millions of hits
+  per day, but there are upper bounds on the capacity of a single Zope server.
+  ZEO allows you to scale your site by adding more hardware on which you may
+  place extra Zope servers to handle excess demand.
+
+- Your site is critical and requires 24/7 uptime. Using ZEO can help you add
+  redundancy to your server configuration.
+
+- You want to distribute your site to disparate geographic locations in order
+  to increase response time to remote sites. ZEO allows you to place Zope
+  servers which use the same ZODB in separate geographic locations.
+
+- You want to "debug" an application which is currently served by a single Zope
+  server from another Zope process. ZEO enables the developer to attach to a
+  ZODB database while still continuing to serve requests from another ZEO
+  client.
+
+Installing, configuring, and maintaining a ZEO-enabled Zope requires some
+system administration knowledge. Most Zope users will not need ZEO, or may not
+have the expertise necessary to maintain a distributed server system like ZEO.
+ZEO is fun, and can be very useful, but before jumping head-first and
+installing ZEO in your system you should weigh the extra administrative burden
+ZEO creates against the simplicity of running just a simple, stand-alone Zope.
+
+Installing and Running ZEO
+==========================
+
+ZEO is part of Zope, all batteries are included. However, there are some
+prerequisites before you will be successfully able to use ZEO:
+
+- All of the Zope servers in a ZEO-enabled configuration must run the same
+  version of Zope and ZEO. The easiest way to meet this prerequisite is to make
+  sure all of your computers use the same Zope version.
+
+- All of your ZEO clients must have the same third party Products installed and
+  they must be the same version. This is necessary, or your third-party objects
+  may behave abnormally or not work at all.
+
+- If your Zope system requires access to external resources, like mail servers
+  or relational databases, ensure that all of your ZEO clients have access to
+  those resources.
+
+- Slow or intermittent network connections between clients and server degrade
+  the performance of your ZEO clients. Your ZEO clients should have a good
+  connection to their server.
+
+Installing ZEO is very easy. After you have gone through the steps necessary to
+build the Zope software it takes nothing more than running two scripts and
+tweaking the default configuration laid down in the ZEO client's `zope.conf`
+configuration file.
+
+First, you need to create a place where the ZEO server will live. It also
+contains the database file, so make sure you have enough space to cover your
+expected database size and at least double that so you can pack the ZODB::
+
+  $ python /path/to/Zope/bin/mkzeoinstance.py /path/to/zeostorage
+
+Make sure you use the same python interpreter that was used to build your Zope
+software. `/path/to/zeostorage` represents the location where you want the ZEO
+server to be. While the script runs you will see output telling you what it is
+doing.
+
+Once you have built the ZEO server's home this way you will notice that its
+layout is very similar to a Zope instance home. It has a configuration file
+named `zeo.conf` inside its etc-subdirectory which you should look at to get a
+notion of what can be configured, and you will need it to look up where the
+server will listen for ZEO requests when you configure your ZEO clients.
+
+The ZEO storage home also contains prefabricated start/stop scripts that work
+the same way as the Zope `zopectl` script, for ZEO it is called `zeoctl`.
+
+You should now have ZEO properly installed. Try it out by first starting the
+server. In a terminal window or DOS box type::
+
+  $ /path/to/zeostorage/bin/zeoctl start
+
+You can follow its log file by simply typing::
+
+  $ /path/to/zeostorage/bin/zeoctl logtail
+
+or by looking at the log file directly. Its location is configurable using the
+previously mentioned zeo.conf configuration file.
+
+After having set up the ZEO storage server that way you will want at least one
+ZEO client. You can use an existing Zope server (provided it meets the
+prerequisites mentioned earlier) or build a new instance home the same way you
+would if you set up a new Zope server without ZEO::
+
+  $ python /path/to/Zope/bin/mkzopeinstance
+
+Now visit the instance home you created and look for the `zope.conf`
+configuration file in its etc-directory. In order to use ZEO the client must be
+told to access the ZODB not from the file system but talk to a ZEO server
+instead. Look for the::
+
+  zodb_db main
+
+directive at the bottom. Underneath the default configuration you will notice
+an example ZEO client configuration. Comment out the complete zodb_db main
+stanza containing the
+
+  `filestorage`
+
+directive and uncomment the example zodb_db main configuration that contains
+the::
+
+  zeoclient
+
+directive. If you have not tweaked your zeo.conf file all you need to do at
+this moment is to ensure that the `server` argument in the `zeoclient`
+directive shows the same value as the `address` argument in the `zeo` directive
+inside your ZEO server's zeo.conf-file.
+
+Now you are ready to test the ZEO client. Fire it up by running::
+
+  $ /path/to/zeoclient/bin/zopectl start
+
+and check the log file manually or by running::
+
+  $ /path/to/zeoclient/bin/zopectl logtail
+
+Now visit the Zope Managment Interface (ZMI) of your ZEO client in a web
+browser and go to the *Control Panel*. Click on *Database Managment*. Here, you
+see that Zope is connected to a *ZEO Storage* and that its state is
+*connected*.
+
+Running ZEO on one computer is a great way to familiarize yourself with ZEO and
+how it works. Running a single ZEO client does not however, improve the speed
+of your site, and in fact, it may slow it down just a little. To really get the
+speed benefits that ZEO provides, you need to run multiple ZEO clients. This
+can easily be achieved by creating more ZEO client instances as described
+above. The instances can be on the same server machine or distributed over
+several machines.
+
+How to Distribute Load
+======================
+
+Imagine you have a ZEO server named *zooServer* and three ZEO clients named
+*zeoclient1*, *zeoclient2*, and *zeoclient3*. The three ZEO clients are
+connected to the ZEO server and each client is verified to work properly.
+
+Now you have three computers that serve content to your users. The next problem
+is how to actually spread the incoming web requests evenly among the three ZEO
+clients. Your users only know about *www.zopezoo.org*, not *zeoclient1*,
+*zeoclient2* or *zeoclient3*. It would be a hassle to tell only some users to
+use *zeoclient1*, and others to use *zeoclient3*, and it wouldn't be very good
+use of your computing resources. You want to automate, or at least make very
+easy, the process of evenly distributing requests to your various ZEO clients.
+
+There are a number of solutions to this problem, some easy, some advanced, and
+some expensive. The next section goes over the more common ways of spreading
+web requests around various computers using different kinds of technology, some
+of them based on freely-available or commercial software, and some of them
+based on special hardware.
+
+User Chooses a Mirror
++++++++++++++++++++++
+
+The easiest way to distribute requests across many web servers is to pick from
+a list of *mirrored sites*, each of which is a ZEO client. Using this method
+requires no extra software or hardware, it just requires the maintenance of a
+list of mirror servers. By presenting your users with a menu of mirrors, they
+can use to choose which server to use.
+
+Note that this method of distributing requests is passive (you have no active
+control over which clients are used) and voluntary (your users need to make a
+voluntary choice to use another ZEO client). If your users do not use a mirror,
+then the requests will go to your ZEO client that serves *www.zopezoo.org*.
+
+If you do not have any administrative control over your mirrors, then this can
+be a pretty easy solution. If your mirrors go off-line, your users can always
+choose to come back to the master site which you *do* have administrative
+control over and choose a different mirror.
+
+On a global level, this method improves performance. Your users can choose to
+use a server that is geographically closer to them, which probably results in
+faster access. For example, if your main server was in Portland, Oregon on the
+west coast of the USA and you had users in London, England, they could choose
+your London mirror and their request would not have to go half-way across the
+world and back.
+
+To use this method, create a property in your root folder of type *lines* named
+"mirror". On each line of this property, put the URL to your various ZEO
+clients, as shown in the figure below.
+
+`Figure of property with URLs to mirrors <img:20-2:Figures/11-2.png>`_
+
+Now, add some simple TAL code to your site to display a list of your mirrors::
+
+  <h2>Please choose from the following mirrors:
+  <ul>
+    <li tal:repeat="mirror here/mirrors">
+      <a href=""
+         tal:attributes="href mirror"
+         tal:content="mirror">
+          my.mirror.site
+      </a>
+    </li>
+  </ul>
+
+Or, in a Script (Python):::
+
+  ## Script (Python) "generate_mirror"
+  ##bind container=container
+  ##bind context=context
+  ##bind namespace=
+  ##bind script=script
+  ##bind subpath=traverse_subpath
+  ##parameters=a, b
+  ##title=
+  ##
+  print "<h2>Please choose from the following mirrors: <ul>"
+  for mirror in container.mirrors:
+      print "<li><a href="%s">%s</a>" % (mirror, mirror)
+  return printed
+
+This TAL code (and Script (Python) equivalent) displays a list of all mirrors
+your users can choose from. When using this model, it is good to name your
+computers in ways that assist your users in their choice of mirror. For
+example, if you spread the load geographically, then choose names of countries
+for your computer names.
+
+Alternately, if you do not want users voluntarily choosing a mirror, you can
+have the *index_html* method of your www.zopezoo.org site issue HTTP redirects.
+For example, use the following code in your *www.zopezoo.org* site's
+*index_html* method::
+
+  <tal:block define="mirror python: modules.random.choice(here.mirrors);
+  dummy python: request.RESPONSE.redirect(mirror)" />
+
+This code will redirect any visitors to *www.zopezoo.org* to a random mirror
+server.
+
+Using Round-robin DNS to Distribute Load
+++++++++++++++++++++++++++++++++++++++++
+
+The *Domain Name System*, or DNS, is the Internet mechanism that translates
+computer names (like "www.zope.org") into numeric addresses. This mechanism can
+map one name to many addresses.
+
+The simplest method for load-balancing is to use round-robin DNS, as
+illustrated in the figure below.
+
+`Load balancing with round-robin DNS. <img:20-3:Figures/11-3.png>`_
+
+When *www.zopezoo.org* gets resolved, DNS answers with the address of either
+*zeoclient1*, *zeoclient2*, or *zeoclient3* - but in a rotated order every
+time. For example, one user may resolve *www.zopezoo.org* and get the address
+for *zeoclient1*, and another user may resolve *www.zopezoo.org* and get the
+address for *zeoclient2*. This way your users are spread over the various ZEO
+clients.
+
+This not a perfect load balancing scheme, because DNS information gets cached
+by the other nameservers on the Internet. Once a user has resolved
+*www.zopezoo.org* to a particular ZEO client, all subsequent requests for that
+user also go to the same ZEO client. The final result is generally acceptable,
+because the total sum of the requests are really spread over your various ZEO
+clients.
+
+One potential problem with this solution is that it can take hours or days for
+name servers to refresh their cached copy of what they think the address of
+*www.zopezoo.org* is. If you are not responsible for the maintenance of your
+ZEO clients and one fails, then 1/Nth of your users (where N is the number of
+ZEO clients) will not be able to reach your site until their name server cache
+refreshes.
+
+Configuring your DNS server to do round-robin name resolution is an advanced
+technique that is not covered in this book. A good reference on how to do this
+can be found in the `Apache Documentation
+<http://www.engelschall.com/pw/apache/rewriteguide/#ToC29>`_.
+
+Distributing the load with round-robin DNS is useful, and cheap, but not 100%
+effective. DNS servers can have strange caching policies, and you are relying
+on a particular quirk in the way DNS works to distribute the load. The next
+section describes a more complex, but much more powerful way of distributing
+load called *Layer 4 Switching*.
+
+Using Layer 4 Switching to Distribute Load
+++++++++++++++++++++++++++++++++++++++++++
+
+Layer 4 switching lets one computer transparently hand requests to a farm of
+computers. This is an advanced technique that is largely beyond the scope of
+this book, but it is worth pointing out several products that do Layer 4
+switching for you.
+
+Layer 4 switching involves a *switch* that, according to your preferences,
+chooses from a group of ZEO clients whenever a request comes in, as shown in
+the figure below.
+
+`Illustration of Layer 4 switching <img:20-4:Figures/11-4.png>`_
+
+There are hardware and software Layer 4 switches. There are a number of
+software solutions, but one in general that stands out is the *Linux Virtual
+Server* (LVS). This is an extension to the free Linux operating system that
+lets you turn a Linux computer into a Layer 4 switch. More information on the
+LVS can be found on `its website <http://www.linuxvirtualserver.org>`_.
+
+There are also a number of hardware solutions that claim higher performance
+than software based solutions like LVS. Cisco Systems has a hardware router
+called LocalDirector that works as a Layer 4 switch, and Alteon also makes a
+popular Layer 4 switch.
+
+Other software-based solutions
+++++++++++++++++++++++++++++++
+
+If you are looking for a simple load balancer and proxy software to put in
+front of your ZEO clients you can take a look at the `Pound load balancer
+<http://www.apsis.ch/pound/>`_ which can be set up quickly and offers many
+convenient features.
+
+Many administrators will want to cache content and load balance at the same
+time. The `Squid cache server <http://www.squid-cache.org/>`_ is an excellent
+choice. Toby Dickenson has written up a `HowTo
+<http://www.zope.org/Members/htrd/howto/squid>`_ describing a configuration in
+which Squid caches and balances the load among several ZEO clients.
+
+Dealing with the Storage Server as A Single Point of Failure
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Without ZEO, a single Zope system is a single point of failure. ZEO allows you
+to spread that point of failure around to many different computers. If one of
+your ZEO clients fails, other clients can answer requests on the failed clients
+behalf.
+
+However, in a typical ZEO setup there is still a single point of failure: the
+ZEO server itself. Without using commercial software, this single point of
+failure cannot be removed.
+
+One popular method is to accept the single point of failure risk and mitigate
+that risk as much as possible by using very high-end, reliable equipment for
+your ZEO server, frequently backing up your data, and using inexpensive,
+off-the-shelf hardware for your ZEO clients. By investing the bulk of your
+infrastructure budget on making your ZEO server rock solid (redundant power
+supplies, RAID, and other fail-safe methods) you can be pretty well assured
+that your ZEO server will remain up, even if a handful of your inexpensive ZEO
+clients fail.
+
+Some applications, however, require absolute one-hundred-percent uptime. There
+is still a chance, with the solution described above, that your ZEO server will
+fail. If this happens, you want a backup ZEO server to jump in and take over
+for the failed server right away.
+
+Like Layer 4 switching, there are a number of products, software and hardware,
+that may help you to create a backup storage server. One popular software
+solution for linux is called `fake <http://vergenet.net/linux/fake/>`_. Fake is
+a Linux-based utility that can make a backup computer take over for a failed
+primary computer by "faking out" network addresses. When used in conjunction
+with monitoring utilities like `mon <http://www.kernel.org/software/mon/>`_ or
+`heartbeat <http://www.linux-ha.org/>`_, fake can guarantee almost 100% up-time
+of your ZEO server and Layer 4 switches. Using `fake` in this way is beyond the
+scope of this book.
+
+ZEO also has a commercial "multiple-server" configuration which provides for
+redundancy at the storage level. Zope Corporation sells a commercial product
+named `Zope Replication Services <http://www.zope.com/Products/ZRS.html>`_ that
+provides redundancy in storage server services. It allows a "secondary" storage
+server to take over for a "primary" server when the primary fails.
+
+ZEO Server Details
+++++++++++++++++++
+
+The final piece of the puzzle is where the ZEO server stores its information.
+If your primary ZEO server fails, how can your backup ZEO server ensure it has
+the most recent information that was contained in the primary server?
+
+Before explaining the details of how the ZEO server works, it is worth
+understanding some details about how Zope *storages* work in general.
+
+Zope does not save any of its object or information directly to disk. Instead,
+Zope uses a *storage* component that takes care of all the details of where
+objects should be saved.
+
+This is a very flexible model, because Zope no longer needs to be concerned
+about opening files, or reading and writing from databases, or sending data
+across a network (in the case of ZEO). Each particular storage takes care of
+that task on Zope's behalf.
+
+For example, a plain, stand-alone Zope system can be illustrated in the figure
+below.
+
+`Zope connected to a filestorage <img:20-5:Figures/11-5.png>`_
+
+You can see there is one Zope application which plugs into a *FileStorage*.
+This storage, as its name implies, saves all of its information to a file on
+the computer's filesystem.
+
+When using ZEO, you simple replace the FileStorage with a *ClientStorage*, as
+illustrated in the figure below.
+
+`Zope with a Client Storage and Storage server <img:20-6:Figures/11-6.png>`_
+
+Instead of saving objects to a file, a ClientStorage sends objects over a
+network connection to a *Storage Server*. As you can see in the illustration,
+the Storage Server uses a FileStorage to save that information to a file on the
+ZEO server's filesystem. In a "stock" ZEO setup, this storage file is in the
+same place as it would be were you not running ZEO (within your Zope
+directory's `var` directory named `Data.fs`).
+
+Ongoing Maintenance
+===================
+
+A ZEO server does not need much in terms of care and feeding. You need to make
+sure the ZODB does not grow too large and pack it once in a while, and you
+should rotate the server logs.
+
+Packing
++++++++
+
+FileStorage, the most common ZODB database format, works by appending changes
+at the file end. That means it will grow with time. To avoid running out of
+space it can be *packed*, a process that will remove old object revisions and
+shrink the ZODB. Zope comes with a handy utility script to do this task, and
+you can run it in an automated fashion like out of `cron` . Look for a script
+named `zeopack.py` underneath ZODBTools in the utilities directory of your Zope
+installation.
+
+Given a setup where the ZEO server is listening on port 8001 on localhost, you
+pack it this way::
+
+  $ python /path/to/Zope/utilities/ZODBTools/zeopack.py -h localhost -p 8001
+
+Make sure you use the same version of Python that is used to run the ZEO
+server.
+
+Log Rotation
+++++++++++++
+
+ZEO by default keeps a single event log. It is located in the *log*
+subdirectory of your ZEO server's home and can be configured using the
+`zeo.conf` configuration file. Depending on the level of logging specified and
+server traffic the file can grow quite quickly.
+
+The `zeoctl` script in your ZEO storage home has a facility to effect the
+closing and reopening of the log file. All you need to do is move the old log
+aside and tell the server to start a new one::
+
+  $ cd /path/to/zeostorage
+  $ mv logs/zeo.log logs/zeo.log.1
+  $ bin/zeoctl logreopen
+
+These steps can be automated via `cron`, at on Windows or the handy `logrotate`
+facility on Linux. Here is an example logrotate script that can be dropped into
+'/etc/logrotate.d'::
+
+  # Rotate ZEO logs weekly
+  /path/to/zeostorage/log/zeo.log {
+      weekly
+      rotate 5
+      compress
+      notifempty
+      missingok
+      postrotate
+      /path/to/zeostorage/bin/zeoctl logreopen
+      endscript
+  }
+
+
+ZEO Caveats
+===========
+
+For the most part, running ZEO is exactly like running Zope by itself, but
+there are a few issues to keep in mind.
+
+First, it takes longer for information to be written to the Zope object
+database. This does not slow down your ability to use Zope (because Zope does
+not block you during this write operation) but it does increase your chances of
+getting a *ConflictError*. Conflict errors happen when two ZEO clients try to
+write to the same object at the same time. One of the ZEO clients wins the
+conflict and continues on normally. The other ZEO client loses the conflict and
+has to try again.
+
+Conflict errors should be as infrequent as possible because they could slow
+down your system. While it's normal to have a *few* conflict errors (due to the
+concurrent nature of Zope) it is abnormal to have *many* conflict errors. The
+pathological case is when more than one ZEO client tries to write to the same
+object over and over again very quickly. In this case, there will be lots of
+conflict errors, and therefore lots of retries. If a ZEO client tries to write
+to the database three times and gets three conflict errors in a row, then the
+request is aborted and the data is not written.
+
+Because ZEO takes longer to write this information, the chances of getting a
+ConflictError are higher than if you are not running ZEO. Because of this, ZEO
+is more *write sensitive* than running Zope without ZEO. You may have to keep
+this in mind when you are designing your network or application. As a rule of
+thumb, more and more frequent writes to the database increase your chances of
+getting a ConflictError. However, faster and more reliable network connections
+and computers lower your chances of getting a ConflictError. By taking these
+two factors into account, conflict errors can be mostly avoided.
+
+ZEO servers do not have any in-memory cache for frequently or recently accessed
+items. Every request for an object from a ZEO client will cause a read from
+disk. While some of that read activity is served by operating system level disk
+caches or hardware caches built into the drive itself it can still make the
+server quite busy if multiple ZEO clients are in use. It is good practice to
+ensure that a busy ZEO server has a fast disk.
+
+To maximize serving speed for ZEO clients (which necessitates minimizing trips
+to the ZEO server for retrieving content) it is advisable to keep a large ZEO
+client cache. This cache keeps frequently accessed objects in memory on the ZEO
+client. The cache size is set inside the `zeoclient` stanza in the `zodb_db
+main` section of your ZEO client's `zope.conf` file. Using the key `cache-size`
+you can specify an integer value for the number of bytes used as the ZEO cache.
+By default this is set to a value of 20000000, which equates about 20 MB. Zope
+allows you to use a simpler format such as *256MB* for the cache-size key.
+
+Conclusion
+==========
+
+In this chapter we looked at ZEO, and how ZEO can substantially increase the
+capacity of your website. In addition to running ZEO on one computer to get
+familiarized, we looked at running ZEO on many computers, and various
+techniques for spreading the load of your visitors among those many computers.
+
+ZEO is not a "magic bullet" solution, and like other system designed to work
+with many computers, it adds another level of complexity to your website. This
+complexity pays off however when you need to serve up lots of dynamic content
+to your audience.

Copied: zope2docs/branches/baijum-reorganize/zope2book/ZPT.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/ZPT.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/ZPT.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/ZPT.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,913 @@
+Using Zope Page Templates
+=========================
+
+*Page Templates* are a web page generation tool.  They help programmers and
+designers collaborate in producing dynamic web pages for Zope web
+applications.  Designers can use them to maintain pages without having to
+abandon their tools, while preserving the work required to embed those pages
+in an application.
+
+In this chapter, you'll learn the basic features of *Page Templates*,
+including how you can use them in your website to create dynamic web pages
+easily.  The next chapter walks you through a "hands on" example showing how
+to build a Zope web application using scripts and *Page Templates*.  In the
+chapter entitled `Advanced Page Templates <AdvZPT.html>`_, you'll learn about
+advanced *Page Template* features.
+
+The goal of *Page Templates* is to allow designers and programmers to work
+together easily.  A designer can use a WYSIWYG HTML editor to create a
+template, then a programmer can edit it to make it part of an application.
+If required, the designer can load the template *back* into his editor and
+make further changes to its structure and appearance.  By taking reasonable
+steps to preserve the changes made by the programmer, the designer will not
+disrupt the application.
+
+*Page Templates* aim at this goal by adopting three principles:
+
+1. Play nicely with editing tools.
+
+2. What you see is very similar to what you get.
+
+3. Keep code out of templates, except for structural logic.
+
+A Page Template is like a model of the pages that it will generate.  In
+particular, it is parseable by most HTML tools.
+
+HTML Page Templates
+-------------------
+
+*Page Templates* can operate in two modes: *HTML Mode* and *XML Mode*.
+Later in this chapter we will show you how to use the *XML Mode*, but in
+most cases we want to use the *HTML Mode* which is also the default mode.
+For the *HTML Mode* the *Content-Type* has to be set to 'text/html'.
+
+HTML isn't XML-conform and can't be extended by a template language.  So
+while rendered HTML *Page Templates* should return valid HTML, their
+source code isn't valid HTML or XML.  But the *Template Attribute
+Language* (*TAL*) does a good job in hiding itself in HTML tags, so most
+HTML tools will be able to parse the source of HTML *Page Templates* and
+just ignore the *TAL* attributes.
+
+As you might already know, XHTML is a XML-conform reformulation of HTML
+and widely used in our days.  Nevertheless, generating HTML and XHTML
+with *Page Templates* works exactly the same way.  While the *HTML Mode*
+doesn't enforce well-formed XML, it's absolutely fine to use this mode
+also for XHTML.
+
+How Page Templates Work
+~~~~~~~~~~~~~~~~~~~~~~~
+
+*Page Templates* use the *Template Attribute Language* (*TAL*).  *TAL*
+consists of special tag attributes.  For example, a dynamic page
+headline might look like this::
+
+  <h1 tal:content="context/title">Sample Page Title</h1>
+
+The 'tal:content' attribute is a *TAL* statement.  Since it has an XML
+namespace (the 'tal:' part) most editing tools will not complain that
+they don't understand it, and will not remove it.  It will not change
+the structure or appearance of the template when loaded into a WYSIWYG
+editor or a web browser.  The name *content* indicates that it will set
+the text contained by the 'h1' tag, and the value 'context/title' is an
+expression providing the text to insert into the tag.  Given the text
+specified by 'context/title' resolves to "Susan Jones Home Page", the
+generated HTML snippet looks like this::
+
+  <h1>Susan Jones Home Page</h1>
+
+All *TAL* statements consist of tag attributes whose name starts with
+'tal:' and all *TAL* statements have values associated with them.  The
+value of a *TAL* statement is shown inside quotes.  See Appendix C,
+`Zope Page Templates Reference <AppendixC.html>`_, for more information
+on *TAL*.
+
+To the HTML designer using a WYSIWYG tool, the dynamic headline example
+is perfectly parseable HTML, and shows up in their editor looking like a
+headline should look like.  In other words, *Page Templates* play nicely
+with editing tools.
+
+This example also demonstrates the principle that "What you see is very
+similar to what you get".  When you view the template in an editor, the
+headline text will act as a placeholder for the dynamic headline text.
+The template provides an example of how generated documents will look.
+
+When this template is saved in Zope and viewed by a user, Zope turns the
+dummy content into dynamic content, replacing "Sample Page Title" with
+whatever 'context/title' resolves to.  In this case, 'context/title'
+resolves to the title of the object to which the template is applied.
+This substitution is done dynamically, when the template is viewed.
+
+There are template statements for replacing entire tags, their contents,
+or just some of their attributes.  You can repeat a tag several times or
+omit it entirely.  You can join parts of several templates together, and
+specify simple error handling.  All of these capabilities are used to
+generate document structures.  Despite these capabilities, you **can't**
+create subroutines or classes, perform complex flow control, or easily
+express complex algorithms using a *Page Template*.  For these tasks,
+you should use Python-based Scripts or application components.
+
+The *Page Template* language is deliberately not as powerful and
+general-purpose as it could be.  It is meant to be used inside of a
+framework (such as Zope) in which other objects handle business logic
+and tasks unrelated to page layout.
+
+For instance, template language would be useful for rendering an invoice
+page, generating one row for each line item, and inserting the
+description, quantity, price, and so on into the text for each row.  It
+would not be used to create the invoice record in a database or to
+interact with a credit card processing facility.
+
+Creating a Page Template
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Use your web browser to log into the Zope Management Interface as a manager.
+Create a *Folder* to work in named 'template_test' in the root of your Zope.
+Visit this folder and choose *Page Template* from Zope's add list. Type
+'simple_page' in the add form's *Id* field, then push the *Add and Edit*
+button.
+
+You should now see the main editing page for the new *Page Template*.
+The title is blank and the default template text is in the editing area.
+
+Now let's create a simple dynamic page.  Type the words 'a Simple Page'
+in the *Title* field.  Then, edit the template text to look like this::
+
+  <html>
+    <body>
+      <p>
+        This is <b tal:content="template/title">the Title</b>.
+      </p>
+    </body>
+  </html>
+
+Now push the *Save Changes* button.  Zope should show a message
+confirming that your changes have been saved.
+
+If you get an error message, check to make sure you typed the example
+correctly and save it again.
+
+Click on the *Test* tab.  You should see a page with "This is **a Simple
+Page**." at the top.  Notice that the title is bold.  This is because
+the 'tal:content' statement just replaces the content of the *bold* tag.
+
+Back up, then click on the *Browse HTML source* link under the
+*Content-Type* field.  This will show you the *unrendered* source of the
+template.  You should see, "This is **the Title**." The bold text acts
+as a placeholder for the dynamic title text.  Back up again, so that you
+are ready to edit the example further.
+
+You can find two options on the *Edit* tab we will not touch for now:
+The *Content-Type* field allows you to specify the content type of
+your page.  Changing that value switches the *Page Template* into *XML
+Mode*, discussed later in this chapter.  The *Expand macros with
+editing* control is explained in the "Macros" section of this chapter.
+
+*TALES* Expressions
+~~~~~~~~~~~~~~~~~~~
+
+The expression "template/title" in your simple Page Template is a *path
+expression*.  This is the most common type of expression.  There are
+several other types of expressions defined by the *TAL Expression
+Syntax* (*TALES*) specification.  For more information on TALES see
+Appendix C, `Zope Page Templates Reference`_.
+
+Path Expressions
+%%%%%%%%%%%%%%%%
+
+The 'template/title' *path expression* fetches the *title* attribute
+of the template.  Here are some other common path expressions:
+
+- 'context/objectValues': A list of the sub-objects of the folder on
+  which the template is called.
+
+- 'request/URL': The URL of the current web request.
+
+- 'user/getUserName': The authenticated user's login name.
+
+From the last chapter you should already be familiar with the context
+variable that is also available in *Python-based Scripts* and the
+attribute 'objectValues' that specifies an API method.  The other two
+examples are just to show you the pattern.  You will learn more about
+them later in the book.
+
+To see what these examples return, just copy the following lines into
+a *Page Template* and select the *Test* tab.  You'll notice that
+'context/objectValues' returns a list that needs further treatment to
+be useful.  We'll come back to that later in this chapter::
+
+  <p tal:content="context/objectValues"></p>
+  <p tal:content="request/URL"></p>
+  <p tal:content="user/getUserName"></p>
+
+Every *path expression* starts with a variable name.  The available
+variable names refer either to objects like *context*, *request* or
+*user* that are bound to every *Page Template* by default or variables
+defined within the *Page Template* using TAL.  Note that *here* is an
+old alias of *context* and still used in many places.
+
+The small set of built-in variables such as *request* and *user* is
+described in the chapter entitled `Advanced Page Templates`_.
+You will also learn how to define your own variables in that chapter.
+
+If the variable itself returns the value you want, you are done.
+Otherwise, you add a slash ('/') and the name of a sub-object or
+attribute.  You may need to work your way through several
+sub-objects to get to the value you're looking for.
+
+Python Expressions
+%%%%%%%%%%%%%%%%%%
+
+A good rule of thumb is that if you need Python to express your logic,
+you better factor out the code into a script.  But Zope is a good tool
+for prototyping and sometimes it would be overkill to write a script
+for one line of code.  And looking at existing products you will see
+quite often 'Python expressions', so it's better to know them.
+
+Recall the first example of this chapter::
+
+  <h1 tal:content="context/title">Sample Page Title</h1>
+
+Let's try to rewrite it using a *Python expression*::
+
+  <h1 tal:content="python: context.title">Sample Page Title</h1>
+
+While *path expressions* are the default, we need a prefix to indicate other
+expression types. This expression with the prefix 'python:' does (at least
+here) the same as the *path expression* above. *Path expressions* try different
+ways to access 'title', so in general they are more flexible, but less
+explicit.
+
+There are some simple things you can't do with *path expressions*.
+The most common are comparing values like in::
+
+  "python: variable1 == variable2"
+
+... or passing arguments to methods, e.g.::
+
+  "python: context.objectValues(['Folder'])"
+
+*TAL* Attributes
+~~~~~~~~~~~~~~~~
+
+*Page Templates* are example pages or snippets.  *TAL* statements define
+how to convert them dynamically.  Depending on the used *TAL* attribute
+they substitute example content or attributes by dynamic values, or
+remove or repeat example elements depending on dynamic values.
+
+Inserting Text
+%%%%%%%%%%%%%%
+
+  In your "simple_page" template, you used the 'tal:content' statement
+  on a *bold* tag.  When you tested it, Zope replaced the content of the
+  HTML *bold* element with the title of the template.
+
+  This is easy as long as we want to replace the complete content of an
+  HTML element.  But what if we want to replace only some words within
+  an element?
+
+  In order to place dynamic text inside of other text, you typically use
+  'tal:replace' on an additional 'span' tag.  For example, add the
+  following lines to your example::
+
+    <p>The URL is
+      <span tal:replace="request/URL">
+        http://www.example.com</span>.</p>
+
+  The 'span' tag is structural, not visual, so this looks like "The URL
+  is http://www.example.com." when you view the source in an editor or
+  browser.  When you view the rendered version, however, it may look
+  something like::
+
+    The URL is http://localhost:8080/template_test/simple_page.
+
+  If you look at the source code of the rendered version, the *span*
+  tags are removed.
+
+  To see the difference between 'tal:replace' and 'tal:content', create
+  a page template and include the following in the body::
+
+    <b tal:content="template/title"></b>
+    <b tal:content="request/URL"></b>
+    <b tal:content="user/getUserName"></b>
+    <b tal:replace="template/title"></b>
+    <b tal:replace="request/URL"></b>
+    <b tal:replace="user/getUserName"></b>
+
+  There are two other ways to add elements that are only needed for
+  *TAL* attributes and that are removed again in the rendered version::
+
+    <p>The URL is
+      <span tal:content="request/URL" tal:omit-tag="">
+        http://www.example.com</span>.</p>
+
+  ... which is more useful in other situations and will be discussed
+  there and::
+
+    <p>The URL is
+      <tal:span tal:content="request/URL">
+        http://www.example.com</tal:span>.</p>
+
+  While you can get really far by using HTML elements and 'tal:replace'
+  or 'tal:omit-tag', some people prefer to use *TAL* elements if the
+  elements are only used to add *TAL* attributes.  *TAL* is an attribute
+  language and doesn't define any elements like 'tal:span', but it uses
+  a complete XML namespace and allows to use any element name you like.
+  They are silently removed while the *Page Template* is rendered.
+
+  This is useful for using speaking names like 'tal:loop', 'tal:case' or
+  'tal:span' and to insert additional elements where HTML doesn't allow
+  elements like 'span' or 'div'.  And if her browser or editor also
+  ignores these tags, the designer will have less trouble with *TAL*
+  elements than with additional HTML elements.
+
+Repeating Structures
+%%%%%%%%%%%%%%%%%%%%
+
+Let's start with a simple three-liner::
+
+  <p tal:repeat="number python: range(4)" tal:content="number">
+    999
+  </p>
+
+'number' is our *repeat variable* and 'range(4)' is a *Python
+expression* that returns the list '[0, 1, 2, 3]'.  If this code is
+rendered, the 'repeat' statement repeats the *paragraph* element for
+each value of the sequence, replacing the variable 'number' by the
+current sequence value.  So the rendered page will not show the
+example number '999', but 4 *paragraph* elements containing the
+numbers of our list.
+
+In most cases we want to iterate over more complex sequences.  Our
+next example shows how to use a sequence of (references to) objects.
+The 'simple_page' template could be improved by adding an item list,
+in the form of a list of the objects that are in the same *Folder* as
+the template.  You will make a table that has a row for each object,
+and columns for the id, meta-type and title.  Add these lines to the
+bottom of your example template::
+
+  <table border="1" width="100%">
+    <tr>
+      <th>Id</th>
+      <th>Meta-Type</th>
+      <th>Title</th>
+    </tr>
+    <tr tal:repeat="item context/objectValues">
+      <td tal:content="item/getId">Id</td>
+      <td tal:content="item/meta_type">Meta-Type</td>
+      <td tal:content="item/title">Title</td>
+    </tr>
+  </table>
+
+The 'tal:repeat' statement on the table row means "repeat this row for
+each item in my context's list of object values".  The *repeat*
+statement puts the objects from the list into the *item* variable one
+at a time (this is called the *repeat variable*), and makes a copy of
+the row using that variable.  The value of 'item/getId' in each row is
+the Id of the object for that row, and likewise with 'item/meta_type'
+and 'item/title'.
+
+You can use any name you like for the repeat variable ("item" is only
+an example), as long as it starts with a letter and contains only
+letters, numbers, and underscores ('_').  The repeat variable is only
+defined in the repeat tag.  If you try to use it above or below the
+*tr* tag you will get an error.
+
+You can also use the repeat variable name to get information about the
+current repetition.  See `Advanced Page Templates`_.
+
+Now view the page and notice how it lists all the objects in the same
+folder as the template.  Try adding or deleting objects from the
+folder and notice how the page reflects these changes.
+
+Conditional Elements
+%%%%%%%%%%%%%%%%%%%%
+
+Using Page Templates you can dynamically query your environment and
+selectively insert text depending on conditions.  For example, you
+could display special information in response to a cookie::
+
+  <p tal:condition="request/cookies/verbose | nothing">
+    Here's the extra information you requested.
+  </p>
+
+This paragraph will be included in the output only if there is a
+'verbose' cookie set.  The expression, 'request/cookies/verbose |
+nothing' is true only when there is a cookie named 'verbose' set.
+You'll learn more about this kind of expression in the chapter
+entitled `Advanced Page Templates`_.
+
+Using the 'tal:condition' statement you can check all kinds of
+conditions.  A 'tal:condition' statement leaves the tag and its
+contents in place if its expression has a true value, but removes them
+if the value is false.  Zope considers the number zero, a  blank
+string, an empty list, and the built-in variable 'nothing' to be false
+values.  Nearly every other value is true, including non-zero numbers,
+and strings with anything in them (even spaces!).
+
+Another common use of conditions is to test a sequence to see if it is
+empty before looping over it.  For example in the last section you saw
+how to draw a table by iterating over a collection of objects.  Here's
+how to add a check to the page so that if the list of objects is empty
+no table is drawn.
+
+To allow you to see the effect, we first have to modify that example
+a bit, showing only *Folder* objects in the context folder.  Because
+we can't specify parameters using *path expressions* like
+'context/objectValues', we first convert it into the *Python
+expression* 'context.objectValues()' and then add the argument that
+tells the 'objectValues' method to return only sub-folders::
+
+  <tr tal:repeat="item python: context.objectValues(['Folder'])">
+
+If you did not add any sub-folders to the *template_test* folder so
+far, you will notice that using the *Test* tab the table header is
+still shown even if we have no table body.  To avoid this we add a
+'tal:condition' statement in the table tag.  The complete table now
+looks like this::
+
+  <table tal:condition="python: context.objectValues(['Folder'])"
+         border="1" width="100%">
+    <tr>
+      <th>Id</th>
+      <th>Meta-Type</th>
+      <th>Title</th>
+    </tr>
+    <tr tal:repeat="item python: context.objectValues(['Folder'])">
+      <td tal:content="item/getId">Id</td>
+      <td tal:content="item/meta_type">Meta-Type</td>
+      <td tal:content="item/title">Title</td>
+    </tr>
+  </table>
+
+If the list of sub-folders is an empty list, the condition is false
+and the entire table is omitted.  You can verify this by using the
+*Test* tab again.
+
+Go and add three Folders named '1', '2', and '3' to the
+*template_test* folder in which your *simple_page* template lives.
+Revisit the *simple_page* template and view the rendered output via
+the *Test* tab.  You will see a table that looks much like the below::
+
+  Id          Meta-Type          Title
+  1           Folder
+  2           Folder
+  3           Folder
+
+Changing Attributes
+%%%%%%%%%%%%%%%%%%%
+
+Most, if not all, of the objects listed by your template have an
+*icon* attribute that contains the path to the icon for that kind of
+object.  In order to show this icon in the meta-type column, you will
+need to insert this path into the 'src' attribute of an 'img' tag.
+Edit the table cell in the meta-type column of the above example to
+look like this::
+
+  <td><img src="file_icon.gif"
+           tal:attributes="src item/icon" />
+    <span tal:replace="item/meta_type">Meta-Type</span></td>
+
+The 'tal:attributes' statement replaces the 'src' attribute of the
+'img' tag with the value of 'item/icon'.  The 'src` attribute in the
+template (whose value is "file_icon.gif") acts as a placeholder.
+
+Notice that we've replaced the 'tal:content' attribute on the table
+cell with a 'tal:replace' statement on a 'span' tag.  This change
+allows you to have both an image and text in the table cell.
+
+XML Page Templates
+------------------
+
+Creating XML with *Page Templates* is almost exactly like creating HTML.
+You switch to *XML Mode* by setting the *content-type* field to
+'text/xml' or whatever the content-type for your XML should be.
+
+In *XML Mode* no "loose" markup is allowed.  Zope assumes that your
+template is well-formed XML.  Zope also requires an explicit TAL and METAL
+XML namespace declarations in order to emit XML.  For example, if you wish
+to emit XHTML, you might put your namespace declarations on the 'html'
+tag::
+
+  <html xmlns:tal="http://xml.zope.org/namespaces/tal"
+    xmlns:metal="http://xml.zope.org/namespaces/metal">
+
+To browse the source of an XML template you go to 'source.xml' rather than
+'source.html'.
+
+Debugging and Testing
+
+Zope helps you find and correct problems in your *Page Templates*.  Zope
+notices problems at two different times: when you're editing a *Page
+Template*, and when you're viewing a *Page Template*.  Zope catches
+different types of problems when you're editing and than when you're
+viewing a *Page Template*.
+
+You may have already seen the trouble-shooting comments that Zope inserts
+into your Page Templates when it runs into problems.  These comments tell
+you about problems that Zope finds while you're editing your templates.
+The sorts of problems that Zope finds when you're editing are mostly
+errors in your *TAL* statements.  For example::
+
+  <!-- Page Template Diagnostics
+   Compilation failed
+   TAL.TALDefs.TALError: bad TAL attribute: 'contents', at line 10, column 1
+  -->
+
+This diagnostic message lets you know that you mistakenly used
+'tal:contents' rather than 'tal:content' on line 10 of your template.
+Other diagnostic messages will tell you about problems with your template
+expressions and macros.
+
+When you're using the Zope management interface to edit *Page Templates*
+it's easy to spot these diagnostic messages, because they are shown in the
+"Errors" header of the management interface page when you save the *Page
+Template*.
+
+If you don't notice the diagnostic message and try to render a template
+with problems you'll see a message like this::
+
+  Error Type: PTRuntimeError
+  Error Value: Page Template hello.html has errors.
+
+That's your signal to reload the template and check out the diagnostic
+message.
+
+In addition to diagnostic messages when editing, you'll occasionally get
+regular Zope errors when viewing a Page Template.  These problems are
+usually due to problems in your template expressions.  For example, you
+might get an error if an expression can't locate a variable::
+
+  Error Type: KeyError
+  Error Value: 'unicorn'
+
+This error message tells you that it cannot find the *unicorn* variable.
+To help you figure out what went wrong, Zope includes information about
+the environment in the traceback.  This information will be available in
+your *error_log* (in your Zope root folder).  The traceback will include
+information about the place where the error occurred and the environment::
+
+  URL: /sandbox/demo
+  Line 1, Column 14
+  Expression: standard:'context/unicorn'
+  Names:
+    {'container': <Folder instance at 019AC4D0>,
+     'context': <Application instance at 01736F78>,
+     'default': <Products.PageTemplates.TALES.Default instance at 0x012F9D00>,
+     ...
+     'root': <Application instance at 01736F78>,
+     'template': <ZopePageTemplate at /sandbox/demo>,
+     'traverse_subpath': [],
+     'user': admin}
+
+This information is a bit cryptic, but with a little detective work it can
+help you figure out what went wrong.  In this case, it tells us that the
+'context' variable is an "Application instance".  This means that it is
+the top-level Zope folder (notice how 'root' variable is the same
+"Application instance").  Perhaps the problem is that you wanted to apply
+the template to a folder that had a *unicorn* property, but the root on
+which you called the template hasn't such a property.
+
+Macros
+------
+
+So far, you've seen how *Page Templates* can be used to add dynamic
+behavior to individual web pages.  Another feature of page templates is
+the ability to reuse look and feel elements across many pages.
+
+For example, with *Page Templates*, you can have a site that has a
+standard look and feel.  No matter what the "content" of a page, it will
+have a standard header, side-bar, footer, and/or other page elements.
+This is a very common requirement for websites.
+
+You can reuse presentation elements across pages with *macros*.  Macros
+define a section of a page that can be reused in other pages.  A macro can
+be an entire page, or just a chunk of a page such as a header or footer.
+After you define one or more macros in one *Page Template*, you can use
+them in other *Page Templates*.
+
+Using Macros
+~~~~~~~~~~~~
+
+You can define macros with tag attributes similar to *TAL* statements.
+Macro tag attributes are called *Macro Expansion Tag Attribute Language*
+(*METAL*) statements.  Here's an example macro definition::
+
+  <p metal:define-macro="copyright">
+    Copyright 2009, <em>Foo, Bar, and Associates</em> Inc.
+  </p>
+
+This 'metal:define-macro' statement defines a macro named "copyright".
+The macro consists of the 'p' element (including all contained elements,
+ending with the closing 'p' tag).
+
+Macros defined in a Page Template are stored in the template's *macros*
+attribute.  You can use macros from other *Page Templates* by referring
+to them through the *macros* attribute of the *Page Template* in which
+they are defined.  For example, suppose the *copyright* macro is in a
+*Page Template* called "master_page".  Here's how to use the *copyright*
+macro from another *Page Template*::
+
+  <hr />
+  <b metal:use-macro="container/master_page/macros/copyright">
+    Macro goes here
+  </b>
+
+In this *Page Template*, the 'b' element will be completely replaced by
+the macro when Zope renders the page::
+
+  <hr />
+  <p>
+    Copyright 2009, <em>Foo, Bar, and Associates</em> Inc.
+  </p>
+
+If you change the macro (for example, if the copyright holder changes)
+then all *Page Templates* that use the macro will automatically reflect
+the change.
+
+Notice how the macro is identified by a *path expression* using the
+'metal:use-macro' statement.  The 'metal:use-macro' statement replaces
+the statement element with the named macro.
+
+Macro Details
+~~~~~~~~~~~~~
+
+The 'metal:define-macro' and 'metal:use-macro' statements are pretty
+simple.  However there are a few subtleties to using them which are
+worth mentioning.
+
+A macro's name must be unique within the Page Template in which it is
+defined.  You can define more than one macro in a template, but they all
+need to have different names.
+
+Normally you'll refer to a macro in a 'metal:use-macro' statement with a
+path expression.  However, you can use any expression type you wish so
+long as it returns a macro.  For example::
+
+  <p metal:use-macro="python:context.getMacro()">
+    Replaced with a dynamically determined macro,
+    which is located by the getMacro script.
+  </p>
+
+In this case the path expression returns a macro defined dynamically by
+the 'getMacro' script.  Using *Python expressions* to locate macros lets
+you dynamically vary which macro your template uses.  An example
+of the body of a "getMacro" Script (Python) is as follows::
+
+  return container.ptMacros.macros['amacroname']
+
+You can use the 'default' variable with the 'metal:use-macro'
+statement::
+
+  <p metal:use-macro="default">
+    This content remains - no macro is used
+  </p>
+
+The result is the same as using *default* with 'tal:content' and
+'tal:replace'.  The "default" content in the tag doesn't change when it
+is rendered.  This can be handy if you need to conditionally use a macro
+or fall back on the default content if it doesn't exist.
+
+If you try to use the 'nothing' variable with 'metal:use-macro' you will
+get an error, since 'nothing' is not a macro.  If you want to use
+'nothing' to conditionally include a macro, you should instead enclose
+the 'metal:use-macro' statement with a 'tal:condition' statement.
+
+Zope handles macros first when rendering your templates.  Then Zope
+evaluates TAL expressions.  For example, consider this macro::
+
+  <p metal:define-macro="title"
+     tal:content="template/title">
+    template's title
+  </p>
+
+When you use this macro it will insert the title of the template in
+which the macro is used, *not* the title of the template in which the
+macro is defined.  In other words, when you use a macro, it's like
+copying the text of a macro into your template and then rendering your
+template.
+
+If you check the *Expand macros when editing* option on the *Page
+Template* *Edit* view, then any macros that you use will be expanded in
+your template's source.
+
+Using Slots
+~~~~~~~~~~~
+
+Macros are much more useful if you can override parts of them when you
+use them.  You can do this by defining *slots* in the macro that you can
+fill in when you use the template.  For example, consider a side bar
+macro::
+
+  <div metal:define-macro="sidebar">
+    Links
+    <ul>
+      <li><a href="/">Home</a></li>
+      <li><a href="/products">Products</a></li>
+      <li><a href="/support">Support</a></li>
+      <li><a href="/contact">Contact Us</a></li>
+    </ul>
+  </div>
+
+This macro is fine, but suppose you'd like to include some additional
+information in the sidebar on some pages.  One way to accomplish this is
+with slots::
+
+  <div metal:define-macro="sidebar">
+    Links
+    <ul>
+      <li><a href="/">Home</a></li>
+      <li><a href="/products">Products</a></li>
+      <li><a href="/support">Support</a></li>
+      <li><a href="/contact">Contact Us</a></li>
+    </ul>
+    <span metal:define-slot="additional_info"></span>
+  </div>
+
+When you use this macro you can choose to fill the slot like so::
+
+  <p metal:use-macro="container/master.html/macros/sidebar">
+    <b metal:fill-slot="additional_info">
+      Make sure to check out our <a href="/specials">specials</a>.
+    </b>
+  </p>
+
+When you render this template the side bar will include the extra
+information that you provided in the slot::
+
+  <div>
+    Links
+    <ul>
+      <li><a href="/">Home</a></li>
+      <li><a href="/products">Products</a></li>
+      <li><a href="/support">Support</a></li>
+      <li><a href="/contact">Contact Us</a></li>
+    </ul>
+    <b>
+      Make sure to check out our <a href="/specials">specials</a>.
+    </b>
+  </div>
+
+Notice how the 'span' element that defines the slot is replaced with the
+'b' element that fills the slot.
+
+Customizing Default Presentation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A common use of slot is to provide default presentation which you can
+customize.  In the slot example in the last section, the slot definition
+was just an empty 'span' element.  However, you can provide default
+presentation in a slot definition.  For example, consider this revised
+sidebar macro::
+
+  <div metal:define-macro="sidebar">
+    <div metal:define-slot="links">
+    Links
+    <ul>
+      <li><a href="/">Home</a></li>
+      <li><a href="/products">Products</a></li>
+      <li><a href="/support">Support</a></li>
+      <li><a href="/contact">Contact Us</a></li>
+    </ul>
+    </div>
+    <span metal:define-slot="additional_info"></span>
+  </div>
+
+Now the sidebar is fully customizable.  You can fill the 'links' slot to
+redefine the sidebar links.  However, if you choose not to fill the
+'links' slot then you'll get the default links, which appear inside the
+slot.
+
+You can even take this technique further by defining slots inside of
+slots.  This allows you to override default presentation with a fine
+degree of precision.  Here's a sidebar macro that defines slots within
+slots::
+
+  <div metal:define-macro="sidebar">
+    <div metal:define-slot="links">
+    Links
+    <ul>
+      <li><a href="/">Home</a></li>
+      <li><a href="/products">Products</a></li>
+      <li><a href="/support">Support</a></li>
+      <li><a href="/contact">Contact Us</a></li>
+      <span metal:define-slot="additional_links"></span>
+    </ul>
+    </div>
+    <span metal:define-slot="additional_info"></span>
+  </div>
+
+If you wish to customize the sidebar links you can either fill the
+'links' slot to completely override the links, or you can fill the
+'additional_links' slot to insert some extra links after the default
+links.  You can nest slots as deeply as you wish.
+
+Combining METAL and TAL
+~~~~~~~~~~~~~~~~~~~~~~~
+
+You can use both *METAL* and *TAL* statements on the same elements.  For
+example::
+
+  <ul metal:define-macro="links"
+      tal:repeat="link context/getLinks">
+    <li>
+      <a href="link url"
+         tal:attributes="href link/url"
+         tal:content="link/name">link name</a>
+    </li>
+  </ul>
+
+In this case, 'getLinks' is an (imaginary) Script that assembles a list
+of link objects, possibly using a Catalog query.
+
+Since METAL statements are evaluated before *TAL* statements, there are
+no conflicts.  This example is also interesting since it customizes a
+macro without using slots.  The macro calls the 'getLinks' Script to
+determine the links.  You can thus customize your site's links by
+redefining the 'getLinks' Script at different locations within your
+site.
+
+It's not always easy to figure out the best way to customize look and
+feel in different parts of your site.  In general you should use slots
+to override presentation elements, and you should use Scripts to provide
+content dynamically.  In the case of the links example, it's arguable
+whether links are content or presentation.  Scripts probably provide a
+more flexible solution, especially if your site includes link content
+objects.
+
+Whole Page Macros
+~~~~~~~~~~~~~~~~~
+
+Rather than using macros for chunks of presentation shared between
+pages, you can use macros to define entire pages.  Slots make this
+possible.  Here's an example macro that defines an entire page::
+
+  <html metal:define-macro="page">
+    <head>
+      <title tal:content="context/title">The title</title>
+    </head>
+
+    <body>
+      <h1 metal:define-slot="headline"
+          tal:content="context/title">title</h1>
+
+      <p metal:define-slot="body">
+        This is the body.
+      </p>
+
+      <span metal:define-slot="footer">
+        <p>Copyright 2009 Fluffy Enterprises</p>
+      </span>
+
+    </body>
+  </html>
+
+This macro defines a page with three slots, 'headline', 'body', and
+'footer'.  Notice how the 'headline' slot includes a *TAL* statement to
+dynamically determine the headline content.
+
+You can then use this macro in templates for different types of content,
+or different parts of your site.  For example here's how a template for
+news items might use this macro::
+
+  <html metal:use-macro="container/master.html/macros/page">
+
+    <h1 metal:fill-slot="headline">
+      Press Release:
+      <span tal:replace="context/getHeadline">Headline</span>
+    </h1>
+
+    <p metal:fill-slot="body"
+       tal:content="context/getBody">
+      News item body goes here
+    </p>
+
+  </html>
+
+This template redefines the 'headline' slot to include the words "Press
+Release" and call the 'getHeadline' method on the current object.  It
+also redefines the 'body' slot to call the 'getBody' method on the
+current object.
+
+The powerful thing about this approach is that you can now change the
+'page' macro and the press release template will be automatically
+updated.  For example you could put the body of the page in a table and
+add a sidebar on the left and the press release template would
+automatically use these new presentation elements.
+
+Using Templates with Content
+----------------------------
+
+In general Zope supports content, presentation and logic components.
+*Page Templates* are presentation components and they can be used to
+display content components.
+
+Zope ships with several content components: ZSQL Methods, Files, and Images.
+You can use Files for textual content since you can edit the contents of Files
+if the file is less than 64K and contains text. However, the File object is
+fairly basic and may not provide all of the features or metadata that you need.
+
+Zope's `Content Management Framework <http://cmf.zope.org>`_ (CMF) solves
+this problem by providing an assortment of rich content components.  The
+CMF is Zope's content management add on.  It introduces all kinds of
+enhancements including workflow, skins and content objects.  The CMF makes
+a lot of use of *Page Templates*.

Copied: zope2docs/branches/baijum-reorganize/zope2book/ZopeArchitecture.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/ZopeArchitecture.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/ZopeArchitecture.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/ZopeArchitecture.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,301 @@
+##############################
+Zope Concepts and Architecture
+##############################
+
+Fundamental Zope Concepts
+=========================
+
+The Zope framework has several fundamental underlying concepts,
+each of which should be understood in order to make the most of your Zope
+experience.
+
+Zope Is a Framework
+-------------------
+
+Zope relieves the developer of most of the onerous details of
+Web application development, such as data persistence, data
+integrity, and access control, allowing one to focus instead on the
+problem at hand.  It allows you to utilize the services it
+provides to build web applications more quickly than other
+languages or frameworks, and to write web
+application logic in the `Python <http://www.python.org/>`_
+language.  Zope also comes with one solution that allow you 
+to "template" text, XML, and HTML: *Zope Page Templates* (ZPT).
+
+Object Orientation
+------------------
+
+Unlike common, file-based web template systems, such as ASP or
+PHP, Zope is a highly "object-oriented" web development
+platform.  Object orientation is a concept that is shared
+between many different programming languages, including 
+Python.  The concept of
+object orientation may take a little "getting-used-to" if you're
+an old hand at procedural languages used for
+web scripting, such as Perl or PHP.  However, you will easily grasp its 
+main concepts by reading the `Object Orientation <ObjectOrientation.html>`_
+chapter, and by trying the hands-on examples in this book.
+
+Object Publishing
+------------------
+
+The technology that would become Zope was founded on the
+realization that the Web is fundamentally object-oriented. A URL
+to a Web resource is really just a path to an object in a set of
+containers, and the HTTP protocol provides a way to send
+messages to that object and to request a response.
+
+Zope's object structure is hierarchical, which means that a
+typical Zope site is composed of objects that contain other
+objects (which may contain other objects, ad infinitum).  URLs
+map naturally to objects in the hierarchical Zope environment
+based on their names. For example, the URL
+"/Marketing/index.html" could be used to access the Document
+object named "index.html" located in the Folder object named
+"Marketing".
+
+Zope's seminal duty is to *publish* the objects you create.  The
+way it does this is conceptually straightforward:
+
+1. Your web browser sends a request to the Zope server.  The
+   request specifies a URL in the form
+   'protocol://host:port/path?querystring"',
+   e.g., 'http://www.zope.org:8080/Resources?batch_start=100'.
+
+2. Zope separates the URL into its component "host", "port" "path"
+   and "query string" portions ('http://www.zope.org', '8080',
+   '/Resources' and '?batch_start=100', respectively).
+
+3. Zope locates the object in its object database corresponding
+   to the "path" ('/Resources').
+
+4. Zope "executes" the object using the "query string" as a source
+   of parameters that can modify the behavior of the object.  This
+   means that the object may behave differently depending on the
+   values passed in the query string.
+
+5. If the act of executing the object returns a value, the value
+   is sent back to your browser.  Typically a given Zope object
+   returns HTML, file data, or image data.
+
+6. The data is interpreted by the browser and shown to you.
+
+Mapping URLs to objects isn't a new idea.  Web servers like Apache
+and Microsoft's IIS do the same thing: they translate URLs into
+files and directories on a file system.  Zope similarly maps URLs
+to objects in its object database.
+
+A Zope object's URL is based on its *path*, which is composed of the
+'ids' of its containing Folders and the object's 'id', separated
+by slash characters.  For example, if you have a Zope "Folder"
+object in the root folder called *Bob*, then its path would be
+'/Bob'.  If *Bob* is in a sub-folder called *Uncles*, then its URL
+would be '/Uncles/Bob'.
+
+There could also be other Folders in the Uncles folder called
+*Rick*, *Danny*, and *Louis*.  You would access them through the web
+similarly::
+
+  /Uncles/Rick
+  /Uncles/Danny 
+  /Uncles/Louis
+
+The URL of an object is most simply composed of its 'host',
+'port', and 'path'.  For the Zope object with the path '/Bob'
+on the Zope server at ``http://localhost:8080/``, the URL would be
+``http://localhost:8080/Bob``.  Visting a URL of a Zope object
+directly is termed *calling the object through the web*.  This
+causes the object to be evaluated and the result of the
+evaluation to be returned to your web browser.
+
+For a more detailed explanation of how Zope performs object
+publishing, see the `Object Publishing chapter
+<http://www.zope.org/Documentation/Books/ZDG/current/ObjectPublishing.stx>`_
+of the *Zope Developer's Guide*.
+
+Through-The-Web Management
+--------------------------
+
+To create and work with Zope objects, you can use your Web browser to access
+the *Zope management interface* (ZMI). Basic management and application
+configuration tasks can be done completely through the Web using only a
+browser. The ZMI provides a familiar, Windows Explorer-like view of the Zope
+object system.
+
+Any object in the object hierarchy can be configured. Site managers can work
+with their objects by clicking on tabs that represent different "views" of an
+object. These views vary depending on the type of object. For example a
+"Database Connection" Zope object provides views that let you modify its
+connection string or caching parameters. All objects also have a "Security"
+view that allows you to manage their individual access control settings.
+
+Zope had a much larger focus on Through-The-Web activities in its beginning.
+In recent years the Through-The-Web model has been discouraged for any kind of
+development and reduced to configuration tasks.
+
+Security and Safe Delegation
+----------------------------
+
+One of the things that sets Zope apart from other application
+servers, is that it was designed from the start to be tightly
+coupled with not only the Web object model, but also the Web
+development model. Today's successful web applications require
+the participation of many people across an organization with
+different areas of expertise. Zope is specifically designed to
+accommodate this model, allowing site managers to safely
+delegate control to design experts, database experts, and content
+managers.
+
+A successful Web site requires the collaboration of many people
+people in an organization: application developers, SQL experts,
+content managers, and often even the end users of the
+application. On a conventional Web site, maintenance and
+security can quickly become problematic: how much control do you
+give to the content manager? How does giving the content manager
+a user account affect your security? What about that SQL code embedded
+in the ASP files he'll be working on -- code that probably
+exposes your database login?
+
+Objects in Zope provide a robust set of possible
+permissions, richer than that of a conventional file-based system. Permissions
+vary by object type, based on the capabilities of that
+object, which enables the implementation of fine-grained access
+control. For example, you can set access control so that content
+managers can use "SQL Method" objects without being able to change them or
+even view their source. You can also set restrictions so that a
+user can only create certain kinds of objects, for instance,
+"Folders" and "Page Templates," but not "SQL Methods" or other
+objects.
+
+Zope provides the capability to manage users through the web via
+*User Folders*, which are special folders that contain user
+information. Several Zope add-ons are available that provide
+extended types of User Folders that get their user data from
+external sources, such as relational databases or LDAP
+directories.  The ability to add new User Folders can be
+delegated to users within a sub-folder, essentially allowing you
+to delegate the creation and user management of subsections of
+your website to semi-trusted users, without having to worry about those
+users changing the objects "above" their own folder.
+
+Native Object Persistence and Transactions
+------------------------------------------
+
+By default, Zope objects are stored in a high-performance, transactional
+object database known as the *Zope Object Database* (ZODB). Each
+web request is treated as a separate transaction by the ZODB. 
+If an error occurs in your application during a
+request, any changes made during the request will be
+automatically rolled back. The ZODB also provides
+multi-level undo, allowing a site manager to "undo" changes to
+the site with the click of a button.  The Zope framework makes
+all of the details of persistence and transactions totally
+transparent to the application developer.  Relational databases,
+when used with Zope, can also play in Zope's transactional
+framework.
+
+Acquisition
+-----------
+
+One more prominent aspect of Zope is *acquisition*, whose core concepts are
+simply that:
+
+* Zope objects are contained inside other objects (such as Folders).
+
+* Objects can "acquire" attributes and behavior from their containers.
+
+The concept of acquisition works with all Zope objects and
+provides an extremely powerful way to centralize common
+resources. A commonly-used SQL query or snippet of HTML, for
+example, can be defined in one Folder, and objects in sub-folders
+can use it through acquisition. If the query needs
+to be changed, you can change it in one place without worrying
+about all of the sub-objects that use the same query.
+
+If you are familiar with *Cascading Style Sheets* (CSS), you already
+know how an element in an HTML document can inherit cascading properties
+from its parent or ancestor elements. Containment acquisition
+works in the same fashion: if a document X is contained in folder Y,
+document X can access the attributes of folder Y through acquisition.
+Note that some advanced aspects of acquisition may break
+this analogy; these are discussed in the 
+`Advanced Zope Scripting <ScriptingZope.html>`_ chapter.
+
+Acquisition is explained in further detail in the chapter on
+`Acquisition <Acquisition.html>`_ .
+
+Zope Is Extensible
+------------------
+
+Zope is highly extensible, and component developers can create new
+types of Zope objects by writing new Zope add-on in Python. The Zope
+software provides a number of useful, built-in components to aid
+extension authors in development, including a robust set of framework classes
+that take care of most of the details of implementing new Zope
+objects.
+
+A number of Zope add-ons are available that provide
+features like drop-in web discussion topics, desktop data
+publishing, XML tools, and e-commerce integration. Many of these
+add-ons have been written by highly active members of the
+Zope community, and most are also open source.
+
+Fundamental Zope Components
+===========================
+
+Zope consists of several different components that work together
+to help you build web applications.  Zope's fundamental components
+are shown in the following figure and explained below:
+
+.. image:: Figures/zopearchitecture.png
+
+ZServer
+-------
+
+Zope comes with a built-in web server that serves content to you and your
+users.  This web server also serves Zope content via FTP, WebDAV, and
+XML-RPC (a remote procedure call facility).
+
+Web Server
+----------
+
+Of course, you may already have an existing web server, such as Apache or
+Microsoft IIS, and you may not want to use Zope's web server.  Zope works
+with these servers also, and any other web server that supports the
+Common Gateway Interface (CGI).  In production environments, it can be
+advantageous to run a server like Apache or Squid "in front of" Zope in
+order to help sanitize incoming requests, augment its capabilities (e.g.,
+terminate HTTPS connections), and cache Zope-provided content.
+
+Zope Core
+---------
+
+This is the engine that coordinates Zope activity, driving its management
+interface and object database.
+
+Object Database
+---------------
+
+When you work with Zope, you are usually working with objects that are
+stored in the ZODB.
+
+Relational database
+-------------------
+
+You don't have to store your information in Zope's object database if you
+don't want to.  Zope also works with other relational databases,
+including *Oracle*, *PostgreSQL*, *Sybase*, and *MySQL*.
+
+File System
+-----------
+
+Zope can, of course, work with documents and other files stored on your
+server's file system.
+
+Products
+--------
+
+Zope also allows site managers to add new, pre-built object types to Zope
+by installing add-ons on the Zope server file system. These are referred to
+as Products or Add-ons. Technically they are normal Python packages.
+

Copied: zope2docs/branches/baijum-reorganize/zope2book/ZopeServices.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/ZopeServices.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/ZopeServices.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/ZopeServices.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,380 @@
+Zope Services
+=============
+
+Some Zope objects are *service* objects.  *Service* objects provide
+various kinds of support to your "domain-specific" content, logic,
+and presentation objects.  They help solve fundamental problems that
+many others have experienced when writing applications in Zope.
+
+Access Rule Services
+--------------------
+
+*Access Rules* make it possible to cause an action to happen any
+time a user "traverses" a Folder in your Zope site.  When a user's
+browser submits a request for a URL to Zope which has a Folder's
+name in it, the Folder is "looked up" by Zope during object
+publishing.  That action (the lookup) is called *traversal*.
+Access Rules are arbitrary bits of code which effect the
+environment in some way during Folder traversal.  They are easiest
+to explain by way of an example.
+
+.. note:::
+
+   The Access Service section needs an explanation of how to suppress
+   an access rule. For the baffled among us, you can set an environmental
+   variable 'SUPPRESS_ACCESSRULE' ( I add a line in my 'start' script to
+   do this ) or include '_SUPPRESS_ACCESSRULE' to the URL at a point AFTER
+   the folder/container in question.
+   SITEROOT works the same way, just replace ACCESSRULE with SITEROOT in
+   the above explanation.
+
+In your Zope site, create a Folder named "accessrule_test".
+Inside the accessrule_test folder, create a Script (Python) object
+named 'access_rule' with two parameters: 'container' and
+'request'.  Give the 'access_rule' Script (Python) the following
+body::
+
+  useragent = request.get('HTTP_USER_AGENT', '')
+  if useragent.find('Windows') != -1:
+      request.set('OS', 'Windows')
+  elif useragent.find('Linux') != -1:
+      request.set('OS', 'Linux')
+  else:
+      request.set('OS', 'Non-Windows, Non-Linux')
+
+This Script causes the traversal of the accessrule_test folder to
+cause a new variable named 'OS' to be entered into the REQUEST,
+which has a value of 'Windows', 'Linux', or 'Non-Windows,
+Non-Linux' depending on the user's browser.
+
+Save the 'access_rule' script and revisit the accessrule_test
+folder's *Contents* view.  Choose *Set Access Rule* from the add
+list.  In the 'Rule Id' form field, type 'access_rule'.  Then
+click *Set Rule*.  A confirmation screen appears claiming that
+"'access_rule' is now the Access Rule for this object".  Click
+"OK".  Notice that the icon for the 'access_rule' Script (Python)
+has changed, denoting that it is now the access rule for this
+Folder.
+
+Create a page template named 'test' in the accessrule_test folder
+with the following text::
+
+  <html>
+  <body>
+    <pre tal:content="context/REQUEST">request details</pre>
+  </body>
+  </html>
+
+Save the 'test' page template and click its "View" tab.  You will
+see a representation of all the variables that exist in the
+REQUEST.  Note that in the **other** category, there is now a
+variable named "OS" with (depending on your browser platform)
+either 'Windows', 'Linux' or 'Non-Linux, Non-Windows').
+
+Revisit the accessrule_test folder and again select *Set Access
+Rule* from the add list.  Click the *No Access Rule* button.  A
+confirmation screen will be displayed stating that the object now
+has no Access Rule.
+
+Visit the 'test' script you created previously and click its
+*View* tab.  You will notice that there is now no "OS" variable
+listed in the request because we've turned off the Access Rule
+capability for 'access_rule'.
+
+Temporary Storage Services
+--------------------------
+
+Temporary Folders are Zope folders that are used for storing
+objects temporarily.  Temporary Folders acts almost exactly like a
+regular Folder with two significant differences:
+
+1. Everything contained in a Temporary Folder disappears when you
+   restart Zope.  (A Temporary Folder's contents are stored in
+   RAM).
+
+2. You cannot undo actions taken to objects stored a Temporary
+   Folder.
+
+By default there is a Temporary Folder in your root folder named
+*temp_folder*.  You may notice that there is an object entitled,
+"Session Data Container" within *temp_folder*. This is an object
+used by Zope's default sessioning system configuration.  See the
+"Using Sessions" section later in this chapter for more
+information about sessions.
+
+Temporary folders store their contents in RAM rather than in the
+Zope database. This makes them appropriate for storing small
+objects that receive lots of writes, such as session data.
+However, it's a bad idea use temporary folders to store large
+objects because your computer can potentially run out of RAM as
+a result.
+
+Caching Services
+----------------
+
+A *cache* is a temporary place to store information that you
+access frequently.  The reason for using a cache is speed.  Any
+kind of dynamic content, like a a Script (Python),
+must be evaluated each time it is called.  For simple pages or
+quick scripts, this is usually not a problem.  For very complex
+scripts that do a lot of computation or call remote
+servers, accessing that page or script could take more than a
+trivial amount of time.  Scripts can get this
+complex, especially if you use lots of looping (such as the
+Python 'for' loop) or if you call lots of scripts, that
+in turn call lots of scripts, and so on.  Computations that take a
+lot of time are said to be *expensive*.
+
+A cache can add a lot of speed to your site by calling an
+expensive page or script once and storing the result of that call
+so that it can be reused.  The very first person to call that page
+will get the usual "slow" response time, but then once the value
+of the computation is stored in the cache, all subsequent users to
+call that page will see a very quick response time because they
+are getting the *cached copy* of the result and not actually going
+through the same expensive computation the first user went
+through.
+
+To give you an idea of how caches can improve your site speed,
+imagine that you are creating *www.zopezoo.org*, and that the very
+first page of your site is very complex.  Let's suppose this page
+has complex headers, footers, queries several different database
+tables, and calls several special scripts that parse the results
+of the database queries in complex ways.  Every time a user comes
+to *www.zopezoo.org*, Zope must render this very complex page.
+For the purposes of demonstration, let's suppose this complex page
+takes one-half of a second, or 500 milliseconds, to compute.
+
+Given that it takes a half of a second to render this fictional
+complex main page, your machine can only really serve 120 hits per
+minute.  In reality, this number would probably be even lower than
+that, because Zope has to do other things in addition to just
+serving up this main page.  Now, imagine that you set this page up
+to be cached.  Since none of the expensive computation needs to be
+done to show the cached copy of the page, many more users could
+see the main page.  If it takes, for example, 10 milliseconds to
+show a cached page, then this page is being served *50 times
+faster* to your website visitors.  The actual performance of the
+cache and Zope depends a lot on your computer and your
+application, but this example gives you an idea of how caching can
+speed up your website quite a bit.  There are some disadvantages
+to caching however:
+
+Cache lifetime
+  If pages are cached for a long time, they may
+  not reflect the most current information on your site.  If you
+  have information that changes very quickly, caching may hide the
+  new information from your users because the cached copy contains
+  the old information.  How long a result remains cached is called
+  the *cache lifetime* of the information.
+
+Personal information
+  Many web pages may be personalized for
+  one particular user.  Obviously, caching this information and
+  showing it to another user would be bad due to privacy concerns,
+  and because the other user would not be getting information
+  about *them*, they'd be getting it about someone else.  For this
+  reason, caching is often never used for personalized
+  information.
+
+Zope allows you to get around these problems by setting up a *cache
+policy*.  The cache policy allows you to control how content gets
+cached.  Cache policies are controlled by *Cache Manager* objects.
+
+Adding a Cache Manager
+~~~~~~~~~~~~~~~~~~~~~~
+
+Cache managers can be added just like any other Zope object.
+Currently Zope comes with two kinds of cache managers:
+
+HTTP Accelerated Cache Manager
+  An HTTP Accelerated Cache Manager allows you to control an HTTP cache
+  server that is external to Zope, for example,
+  `Squid <http://www.squid-cache.org/>`_.  HTTP Accelerated Cache Managers
+  do not do the caching themselves, but rather set special HTTP headers
+  that tell an external cache server what to cache.  Setting up an external
+  caching server like Squid is beyond the scope of this book, see the Squid
+  site for more details.
+
+(RAM) Cache Manager
+  A RAM Cache Manager is a Zope cache manager that caches the content of
+  objects in your computer memory.  This makes it very fast, but also
+  causes Zope to consume more of your computer's memory.  A RAM Cache
+  Manager does not require any external resources like a Squid server, to
+  work.
+
+For the purposes of this example, create a RAM Cache Manager in
+the root folder called *CacheManager*.  This is going to be the
+cache manager object for your whole site.
+
+Now, you can click on *CacheManager* and see its configuration
+screen.  There are a number of elements on this screen:
+
+Title
+  The title of the cache manager.  This is optional.
+
+REQUEST variables
+  This information is used to store the
+  cached copy of a page.  This is an advanced feature, for now,
+  you can leave this set to just "AUTHENTICATED_USER".
+
+Threshold Entries
+  The number of objects the cache manager
+  will cache at one time.
+
+Cleanup Interval
+  The lifetime of cached results.
+
+For now, leave all of these entries as is, they are good,
+reasonable defaults.  That's all there is to setting up a cache
+manager!
+
+There are a couple more views on a cache manager that you may find
+useful.  The first is the *Statistics* view.  This view shows you
+the number of cache "hits" and "misses" to tell you how effective
+your caching is.
+
+There is also an *Associate* view that allows you to associate a
+specific type or types of Zope objects with a particular cache
+manager.  For example, you may only want your cache manager to
+cache Scripts.  You can change these settings on the
+*Associate* view.
+
+At this point, nothing is cached yet, you have just created a
+cache manager.  The next section explains how you can cache the
+contents of actual documents.
+
+Caching an Object
+~~~~~~~~~~~~~~~~~
+
+Caching any sort of cacheable object is fairly straightforward.
+First, before you can cache an object you must have a cache
+manager like the one you created in the previous section.
+
+To cache a page, create a new page template object in the
+root folder called *Weather*.  This object will contain some
+weather information.  For example, let's say it contains::
+
+  <html>
+  <body>
+
+    <p>Yesterday it rained.</p>
+
+  </body>
+  </html>
+
+Now, click on the *Weather* page template and click on its *Cache*
+view.  This view lets you associate this page with a cache
+manager.  If you pull down the select box at the top of the view,
+you'll see the cache manager you created in the previous section,
+*CacheManager*.  Select this as the cache manager for *Weather*.
+
+Now, whenever anyone visits the *Weather* page, they will get
+the cached copy instead.  For a page as trivial as our
+*Weather* example, this is not much of a benefit.  But imagine for
+a moment that *Weather* contained some database queries.  For
+example::
+
+  <html>
+  <body>
+
+    <p>
+      Yesterday's weather was
+      <tal:yesterday tal:replace="context/yesterdayQuery" />
+    </p>
+
+    <p>
+      The current temperature is
+      <tal:current tal:replace="context/currentTempQuery" />
+    </p>
+
+  </body>
+  </html>
+
+
+Let's suppose that *yesterdayQuery* and *currentTempQuery* are
+SQL Methods that query a database for yesterdays forecast and
+the current temperature, respectively (for more information on
+SQL Methods, see the chapter entitled `Relational Database
+Connectivity <RelationalDatabases.html>`_.)  Let's also suppose that
+the information in the database only changes once every hour.
+
+Now, without caching, the *Weather* document would query the
+database every time it was viewed.  If the *Weather* document was
+viewed hundreds of times in an hour, then all of those hundreds of
+queries would always contain the same information.
+
+If you specify that the page should be cached, however, then
+the page will only make the query when the cache expires.  The
+default cache time is 300 seconds (5 minutes), so setting this
+page up to be cached will save you 91% of your database
+queries by doing them only one twelfth as often.  There is a
+trade-off with this method, there is a chance that the data may be
+five minutes out of date, but this is usually an acceptable
+compromise.
+
+Outbound Mail Services
+----------------------
+
+Zope comes with an object that is used to send outbound e-mail,
+usually in conjunction with a Script (Python).
+
+Mailhosts can be used Python to send an email
+message over the Internet.  They are useful as 'gateways' out to
+the world.  Each mailhost object is associated with one mail
+server, for example, you can associate a mailhost object with
+'yourmail.yourdomain.com', which would be your outbound SMTP mail
+server.  Once you associate a server with a mailhost object, the
+mailhost object will always use that server to send mail.
+
+To create a mailhost object select *MailHost* from the add list.
+You can see that the default id is "MailHost" and the default SMTP
+server and port are "localhost" and "25".  make sure that either
+your localhost machine is running a mail server, or change
+"localhost" to be the name of your outgoing SMTP server.
+
+Now you can use the new MailHost object from a Script.
+
+Error Logging Services
+----------------------
+
+The *Site Error Log* object, typically accessible in the Zope root
+under the name 'error_log', provides debugging and error logging
+information in real-time.  When your site encounters an error, it
+will be logged in the Site Error Log, allowing you to review (and
+hopefully fix!) the error.
+
+Options settable on a Site Error Log instance
+include:
+
+Number of exceptions to keep
+  keep 20 exceptions by default, rotating "old" exceptions out when more
+  than 20 are stored.  Set this to a higher or lower number as you like.
+
+Copy exceptions to the event log
+  If this option is selected, the site error log object will copy the text
+  of exceptions that it receives to the "event log" facility, which is
+  typically controlled by the 'EVENT_LOG_FILE' environment variable.  For
+  more information about this environment variable, see the chapter
+  entitled `Installing and Starting Zope <InstallingZope.html>`_.
+
+Virtual Hosting Services
+------------------------
+
+For detailed information about using virtual hosting services in
+Zope, see the chapter entitled `Virtual Hosting Services
+<VirtualHosting.html>`_.
+
+Searching and Indexing Services
+-------------------------------
+
+For detailed information about using searching and indexing services in Zope to
+index and search a collection of documents, see the chapter entitled
+`Searching and Categorizing Content <SearchingZCatalog.html>`_.
+
+Sessioning Services
+-------------------
+
+For detailed information about using Zope's "sessioning" services
+to "keep state" between HTTP requests for anonymous users, see the
+chapter entitled `Sessions <Sessions.html>`_.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/bootstrap.py
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/bootstrap.py	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/bootstrap.py	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,77 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Bootstrap a buildout-based project
-
-Simply run this script in a directory containing a buildout.cfg.
-The script accepts buildout command-line options, so you can
-use the -c option to specify an alternate configuration file.
-
-$Id: bootstrap.py 90478 2008-08-27 22:44:46Z georgyberdyshev $
-"""
-
-import os, shutil, sys, tempfile, urllib2
-
-tmpeggs = tempfile.mkdtemp()
-
-is_jython = sys.platform.startswith('java')
-
-try:
-    import pkg_resources
-except ImportError:
-    ez = {}
-    exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
-                         ).read() in ez
-    ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
-
-    import pkg_resources
-
-if sys.platform == 'win32':
-    def quote(c):
-        if ' ' in c:
-            return '"%s"' % c # work around spawn lamosity on windows
-        else:
-            return c
-else:
-    def quote (c):
-        return c
-
-cmd = 'from setuptools.command.easy_install import main; main()'
-ws  = pkg_resources.working_set
-
-if is_jython:
-    import subprocess
-    
-    assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd', 
-           quote(tmpeggs), 'zc.buildout'], 
-           env=dict(os.environ,
-               PYTHONPATH=
-               ws.find(pkg_resources.Requirement.parse('setuptools')).location
-               ),
-           ).wait() == 0
-
-else:
-    assert os.spawnle(
-        os.P_WAIT, sys.executable, quote (sys.executable),
-        '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout',
-        dict(os.environ,
-            PYTHONPATH=
-            ws.find(pkg_resources.Requirement.parse('setuptools')).location
-            ),
-        ) == 0
-
-ws.add_entry(tmpeggs)
-ws.require('zc.buildout')
-import zc.buildout.buildout
-zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
-shutil.rmtree(tmpeggs)

Deleted: zope2docs/branches/baijum-reorganize/zope2book/buildout.cfg
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/buildout.cfg	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/buildout.cfg	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,22 +0,0 @@
-[buildout]
-develop =
-parts =
-    stxpy
-
-eggs-directory = ${buildout:directory}/eggs
-versions = versions
-unzip = true
-eggs =
-
-[versions]
-zc.buildout =
-zc.recipe.egg =
-
-[stxpy]
-recipe = zc.recipe.egg
-eggs =
-    Sphinx
-interpreter = stxpy
-scripts =
-    sphinx-build
-    sphinx-quickstart

Copied: zope2docs/branches/baijum-reorganize/zope2book/index.rst (from rev 104981, zope2docs/branches/baijum-reorganize/zope2book/source/index.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/index.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zope2book/index.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -0,0 +1,44 @@
+The Zope2 Book
+==============
+
+Welcome to *The Zope Book*.  This book is designed to introduce you
+to `Zope2`, an open-source web application server.
+
+
+Contents
+--------
+
+.. toctree::
+   :maxdepth: 2
+
+   Preface.rst
+   IntroducingZope.rst
+   ZopeArchitecture.rst
+   InstallingZope.rst
+   ObjectOrientation.rst
+   UsingZope.rst
+   BasicObject.rst
+   Acquisition.rst
+   BasicScripting.rst
+   ZPT.rst
+   SimpleExamples.rst
+   Security.rst
+   AdvZPT.rst
+   ScriptingZope.rst
+   ZopeServices.rst
+   DTML.rst
+   AdvDTML.rst
+   SearchingZCatalog.rst
+   RelationalDatabases.rst
+   VirtualHosting.rst
+   Sessions.rst
+   ZEO.rst
+   ExternalTools.rst
+   MaintainingZope.rst
+   AppendixA.rst
+   AppendixB.rst
+   AppendixC.rst
+   AppendixD.rst
+   AppendixE.rst
+   Contributions.rst
+

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/Acquisition.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/Acquisition.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/Acquisition.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,287 +0,0 @@
-Acquisition
-###########
-
-Acquisition is the technology that allows dynamic behavior to be
-shared between Zope objects via *containment*.
-
-Acquisition's flavor permeates Zope and can be used almost everywhere within
-Zope: in Zope Page Templates, in Script (Python) objects, and even in Zope
-URLs. Because of its ubiquity in Zope, a basic understanding of acquisition is
-important.
-
-Over the years Acquisition has been proven to be a very powerful but often
-too complex technology to use. While it is predictable in simple interactions,
-it gets increasingly complicated to understand its behavior in most
-real-world-sized projects.
-
-In order to understand Zope, you will still need an understanding of
-Acquisition today. Basing your application logic on it is highly
-discouraged, though.
-
-
-Acquisition vs. Inheritance
-===========================
-
-The chapter entitled `Object Orientation <ObjectOrientation.html>`_
-describes a concept called *inheritance*.  Using inheritance, an
-object can *inherit* some of the behaviors of a specific class,
-*overriding* or adding other behaviors as necessary.  Behaviors of
-a class are nearly always defined by its *methods*, although
-attributes can be inherited as well.
-
-In a typical object-oriented language, there are rules that define the way
-a *subclass* inherits behavior from its *superclasses*.  For
-example, in Python (a *multiple-inheritance* language), a class
-may have more than one superclass, and rules are used to determine
-which of a class' superclasses is used to define behavior in any
-given circumstance.
-
-We'll define a few Python classes here to demonstrate.  You don't
-really need to know Python inside and out to understand these
-examples.  Just know that a 'class' statement defines a class, and
-a 'def' statement inside of a class statement defines a method.
-A class statement followed by one or more words inside (parentheses)
-causes that class to *inherit* behavior from the classes named in
-the parentheses (you can play along at home if you like, using the
-Python interpreter).::
-
-  >>> class SuperA:
-  ...     def amethod(self):
-  ...         print "I am the 'amethod' method of the SuperA class"
-  ...     def anothermethod(self):
-  ...         print "I am the 'anothermethod' method of the SuperA class"
-  ...
-  >>> class SuperB:
-  ...     def amethod(self):
-  ...         print "I am the 'amethod' method of the SuperB class"
-  ...     def anothermethod(self):
-  ...         print "I am the 'anothermethod' method of the SuperB class"
-  ...     def athirdmethod(self):
-  ...         print "I am the 'athirdmethod' method of the SuperB class"
-  ...
-  >>> class Sub(SuperA, SuperB):
-  ...     def amethod(self):
-  ...         print "I am the 'amethod' method of the Sub class"
-  ...
-
-If we make an *instance* of the "Sub" class, and attempt to *call*
-one of its methods, there are rules in place to determine whether
-the behavior of the method will be defined by the Sub class
-itself, its SuperA superclass, or its SuperB superclass.  The
-rules are fairly simple: if the Sub class has itself defined the
-named method, that method definition will be used.  Otherwise, the
-*inheritance hierarchy* will be searched for a method definition.
-
-The *inheritance hierarchy* is defined by the class' superclass
-definitions.  The case of the Sub class above has a simple
-inheritance hierarchy: it inherits first from the SuperA
-superclass, then it inherits from the SuperB superclass.  This
-means that if you call a method on an instance of the Sub class,
-and that method is not defined as part of the Sub class'
-definition, it will first search for the method in the SuperA
-class.  If it doesn't find it there, it will search in the
-SuperB class.  Python performs this search of the base classes
-using an order derived from the order of declaration.  Note that for
-complex cases (e.g., where the same method is defined in several
-ancestors of base classes), the lookup order is too complicated to
-explain within the scope of this book.  Please see the online
-Python documentation for the "method resolution order",
-http://www.python.org/download/releases/2.3/mro/
-
-Here is an example of calling methods on an instance of the
-above-defined Sub class::
-
-  >>> instance = Sub()
-  >>> instance.amethod()
-  I am the 'amethod' method of the Sub class
-  >>> instance.anothermethod()
-  I am the 'anothermethod' method of the SuperA class
-  >>> instance.athirdmethod()
-  I am the 'athirdmethod' method of the SuperB class
-
-Note that when we called the 'anothermethod' method on the Sub
-instance, we got the return value of SuperA's method definition
-for that method, even though both SuperA and SuperB defined that
-method.  This is because the inheritance hierarchy specifies that
-the first superclass (SuperA) is searched first.
-
-The point of this example is that instances of objects use their
-*inheritance hierarchy* to determine their behavior.  In non-Zope
-applications, this is the only way that object instances know
-about their set of behaviors.  However, in Zope, objects make use
-of another facility to search for their behaviors: *acquisition*.
-
-Acquisition Is about Containment
-================================
-
-The concept behind acquisition is simple:
-
-- Objects are situated inside other objects, and these objects act as
-  their "containers".  For example, the container of a Page Template
-  named "apage" inside a Folder "afolder" is the
-  "afolder" folder.
-
-- Objects may acquire behavior from their containers.
-
-Inheritance stipulates that an object can learn about its behavior
-from its superclasses via an *inheritance hierarchy*.
-*Acquisition*, on the other hand, stipulates that an object can
-additionally learn about its behavior through its *containment
-hierarchy*.  In Zope, an object's inheritance hierarchy is always
-searched for behavior before its acquisition hierarchy.  If the
-method or attribute is not found in the object's inheritance
-hierarchy, then the acquisition hierarchy is searched.
-
-Say What?
-=========
-
-Let's toss aside the formal explanations.  Acquisition can be
-best explained with a simple example.
-
-Place a Page Template named 'acquisition_test' in your Zope root
-folder.  Give it the following body::
-
-  <html>
-  <body>
-    <p>
-     I am being called from within the
-     <span tal:replace="context/title" />
-     Folder!
-    </p>
-  </body>
-  </html>
-
-Save it, and then use the Page Template "View" tab to see the result
-of the template in your Workspace frame.  You will see
-something not unlike the following::
-
-  I am being called from within the Zope Folder!
-
-The 'title' of the Zope root folder is 'Zope', so this makes
-sense.  Now create a Folder inside your Zope root folder
-named 'AcquisitionTestFolder' and a title of
-"TheAcquisitionTest".  We're going to invoke the
-'acquisition_test' page *in the context of* the
-AcquisitionTestFolder folder.  To do this, assuming your
-Zope is running on your local machine on port 8080, visit
-the URL
-'http://localhost:8080/AcquisitionTestFolder/acquisition_test'.
-You will see something not unlike the following::
-
-  I am being called from within the TheAcquisitionTest Folder!
-
-Note that even though an object named 'acquisition_test' does not
-"live" inside the AcquisitionTestFolder folder, Zope found the
-page and displayed a result anyway!  Not only did Zope display a
-result, instead of inserting the 'title' of the Zope root folder, it
-inserted the 'title' of the AcquisitionTestFolder folder!
-
-This is an example of acquisition in action.  The concept is simple:
-if a named object is not found as an attribute of the object you're
-searching, its containers are searched until the object is found.
-In this way, acquisition can *add behavior* to objects.  In this
-case, we added a behavior to the AcqusitionTestFolder folder that
-it didn't have before (by way of adding an 'acquisition_test' page).
-
-Providing Services
-==================
-
-It can be said that acquisition allows objects to acquire
-*services* by way of containment.  For example, our
-AcquisitionTestFolder folder acquired the services of the
-'acquisition_test' page.
-
-Not only do objects *acquire* services, but they also *provide* them. For
-example, adding a Mail Host object to a Folder named 'AFolder'
-provides other objects in that folder with the ability to send
-mail.  But it also provides objects contained in *subfolders* of
-that folder with the capability to send mail.  If you create
-subfolders of 'AFolder' named 'AnotherFolder' and 'AThirdFolder',
-you can be assured that objects placed in *these* folders will
-also be able to send mail in exactly the same way as objects
-placed in 'AFolder'.
-
-Acquisition "goes both ways": when you create an object in Zope,
-it has the capability to automatically acquire services.
-Additionally, it automatically provides services that other
-objects can acquire. This makes reuse of services very easy, since
-you don't have to do anything special in order to make services available
-to other objects.
-
-Getting Deeper with Multiple Levels
-===================================
-
-If you place a method in the root folder, and create a subfolder
-in the root folder, you can acquire the method's behaviors. So
-what happens if things get more complex?  Perhaps you have a
-method that needs to be acquired from within a couple of
-folders. Is it acquired from its parent, or its parent's parent,
-or what?
-
-The answer is that acquisition works on the entire object
-hierarchy. If, for example, you have a Page Template, "HappySong",
-in the root folder, and also in the root folder you have three
-nested Folders named "Users", "Barney" and "Songs",
-you may call this URL::
-
-  /Users/Barney/Songs/HappySong
-
-The HappySong page is found in the root folder, unless one of the
-other folders "Users", "Barney" or "Songs" happens to also have a
-page named "HappySong", in which case *that* page is used instead.
-The HappySong page is searched for first directly in the "Songs"
-folder.  If it is not found, the acquisition hierarchy is searched
-starting at the first container in the hierarchy: "Barney".  If it
-is not found in "Barney", the "Users" folder is searched.  If it
-is not found in the "Users" folder, the root folder is searched.
-This search is called *searching the acquisition path* or
-alternately *searching the containment hierarchy*.
-
-Acquisition is not limited to searching a containment hierarchy: it
-can also search a *context hierarchy*.  Acquisition by context is
-terribly difficult to explain, and you should avoid it if at all
-possible.
-
-In the example above, for instance, in order to find and publish
-the "HappySong" template at the end of the URL, acquisition searches
-the *containment hierarchy* of the "Songs" folder first.  Because
-"Songs" is contained within "Barney", and "Barney" within "Users",
-the *containment hierarchy* for "Songs" consists of each folder "up"
-from "Users" to the root.
-
-Once the "HappySongs" template is found, there are two hierarchies of
-interest:
-
-- Because "HappySongs" is located directly within the root, its
-  *containment hierarchy* consists of only itself and the root.
-
-- Because "HappySongs" was found by traversing first through the
-  "Users", "Barney", and "Songs" folders, its *context hierarchy*
-  includes those objects.
-
-Acquisition searches the *context hierarchy* only after failing
-to find the named object in the *containment hierarchy*.
-
-As with understanding Python's concept of multiple inheritance, explaining
-the exact strategy used to order that search is not within the scope of this
-book.
-
-Summary
-=======
-
-Acquisition allows behavior to be distributed hierarchically throughout the
-system. When you add a new object to Zope, you don't need to
-specify all of its behavior, only the part of its behavior that is
-unique to that object. For the rest of its behavior, it relies on other
-objects. This means that you can change an object's behavior by
-changing where it is located in the object hierarchy. This is a
-very powerful function that gives your Zope applications
-flexibility.
-
-Acquisition is useful for providing objects with behavior that
-doesn't need to be specified by their own methods or methods found
-in their inheritance hierarchies.  Acquisition is particularly
-useful for sharing information (such as headers and footers)
-between objects in different folders as well.  You will see how
-you can make use of acquisition within different Zope technologies
-in upcoming chapters.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/AdvDTML.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/AdvDTML.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/AdvDTML.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,1440 +0,0 @@
-Advanced DTML
-=============
-
-DTML is the kind of language that appears to "do what you mean."
-That is good when it does what you actually want it to do, but when
-it does something you don't want to do, well, it's no fun at all.
-This chapter tells you how to make DTML do what you *really* mean.
-When you're done reading this chapter you will be able to write DTML
-that will accomplish a number of complex tasks including:
-
-- Inspect and Modify the REQUEST object
-
-- Modify the current namespace
-
-- Call other scripts from within DTML
-
-- Send email with or without MIME attachments
-
-- Handle exceptions within DTML    
-
-A few of caveats before getting started:
-
-- It's a good idea to know something about Python before diving into
-  advanced DTML or any other advanced area of Zope.
-
-- Understand the Zope acquisition model and how it works.
-
-- If you are writing very complex functionality in DTML, consider
-  using a Python Script.  This will ease maintenance, not to mention
-  readability.
-
-- Understand the difference between a DTML Document and a DTML
-  Method before embarking on building a huge site. See the explanation
-  included in this chapter.
-
-It's no lie that DTML has a reputation for complexity.  While it is true
-that DTML is really simple if all you want to do is simple layout,
-using DTML for more advanced tasks requires an understanding of where 
-DTML variables come from.
-
-Here's a very tricky error that almost all newbies encounter.
-Imagine you have a DTML Document called *zooName*.  This
-document contains an HTML form like the following::
-
-  <dtml-var standard_html_header>
-
-    <dtml-if zooName>
-
-      <p><dtml-var zooName></p>
-
-    <dtml-else>
-
-      <form action="<dtml-var URL>" method="GET">
-        <input name="zooName">
-        <input type="submit" value="What is zooName?">
-      </form>
-
-    </dtml-if>  
-
-  <dtml-var standard_html_footer>
-
-This looks simple enough, the idea is, this is an HTML page that calls
-itself.  This is because the HTML action is the *URL* variable, which
-will become the URL of the DTML Document.  
-
-If there is a 'zooName' variable, then the page will print it, if there
-isn't, it shows a form that asks for it.  When you click submit, the data
-you enter will make the "if" evaluate to true, and this code should print
-what was entered in the form.
-
-But unfortunately, this is one of those instances where DTML will not do
-what you mean, because the name of the DTML Document that contains this
-DTML is also named *zooName*, and it doesn't use the variable out of the
-request, it uses itself, which causes it to call itself and call itself, ad
-infinitum, until you get an "excessive recursion" error.  So instead of
-doing what you really meant, you got an error. This is what confuses
-beginners.  In the next couple of sections, we'll show you how to fix this
-example to do what you mean.
-
-How Variables are Looked up
----------------------------
-
-There are actually two ways to fix the DTML error in the
-*zooName* document.  The first is that you can rename the document
-to something like *zopeNameFormOrReply* and always remember this
-special exception and never do it; never knowing why it happens.
-The second is to understand how names are looked up, and to be
-explicit about where you want the name to come from in the
-*namespace*.
-
-The DTML namespace is a collection of objects arranged in a *stack*.  A
-stack is a list of objects that can be manipulated by *pushing* and
-*popping* objects on to and off of the stack. 
-
-When a DTML Document or DTML Method is executed, Zope creates a
-DTML namespace to resolve DTML variable names. It's important to
-understand the workings of the DTML namespace so that you can
-accurately predict how Zope will locate variables. Some of the
-trickiest problems you will run into with DTML can be resolved by
-understanding the DTML namespace.
-
-When Zope looks for names in the DTML namespace stack it first looks at
-the topmost object in the stack.  If the name can't be found
-there, then the next item down is introspected.  Zope will work its way
-down the stack, checking each object in turn until it finds the name
-that it is looking for.
-
-If Zope gets all the way down to the bottom of the stack and
-can't find what it is looking for, then an error is generated.  For
-example, try looking for the non-existent name, *unicorn*::
-
-  <dtml-var unicorn>
-
-As long as there is no variable named *unicorn* viewing this
-DTML will return an error, as shown in the figure below.
-
-.. figure:: ../Figures/7-1.png
-
-   DTML error message indicating that it cannot find a variable
-
-But the DTML stack is not all there is to names because DTML
-doesn't start with an empty stack, before you even begin executing
-DTML in Zope there are already a number of objects pushed on the
-namespace stack.
-
-DTML Namespaces
----------------
-
-DTML namespaces are built dynamically for every request in Zope. When
-you call a DTML Method or DTML Document through the web, the DTML
-namespace starts with the same first two stack elements; the client
-object and the request, as shown in the figure below.
-
-.. figure:: ../Figures/7-2.png
-
-   Initial DTML namespace stack
-
-The client object is the first object on the top of the DTML namespace
-stack when entering a transaction (note:  commands exist to push 
-additional parameters onto the namespace stack during a thread of 
-execution).  What the client object is depends on whether you are
-executing a DTML Method or a DTML Document.  In our example above, this
-means that the client object is named *zooName*.  Which is why it
-breaks.  The form input that we really wanted comes from the web
-request, but the client is looked at first.
-
-The request namespace is always on the bottom of the DTML namespace
-stack, and is therefore the last namespace to be looked in for names.
-This means that we must be explicit in our example about which
-namespace we want.  We can do this with the DTML 'with' tag::
-
-  <dtml-var standard_html_header>
-
-    <dtml-with REQUEST only>
-      <dtml-if zooName>
-        <p><dtml-var zooName></p>
-      <dtml-else>
-        <form action="<dtml-var URL>" method="GET">
-          <input name="zooName">
-          <input type="submit" value="What is zooName?">
-        </form>
-      </dtml-if>
-    </dtml-with>
-
-  <dtml-var standard_html_footer>
-
-Here, the with tag says to look in the 'REQUEST' namespace, and *only*
-the 'REQUEST' namespace, for the name "zooName".
-
-DTML Client Object  
-~~~~~~~~~~~~~~~~~~
-
-The client object in DTML depends on whether or not you are executing a
-DTML Method or a DTML Document.  In the case of a Document, the client
-object is always the document itself, or in other words, a DTML
-Document is its own client object.
-
-A DTML Method however can have different kinds of client objects
-depending on how it is called.  For example, if you had a DTML Method
-that displayed all of the contents of a folder then the client object
-would be the folder that is being displayed.  This client object can
-change depending on which folder the method in question is
-displaying.  For example, consider the following DTML Method named
-*list* in the root folder::
-
-  <dtml-var standard_html_header>
-
-  <ul>
-  <dtml-in objectValues>
-    <li><dtml-var title_or_id></li>
-  </dtml-in>
-  </ul>
-
-  <dtml-var standard_html_footer>
-
-Now, what this method displays depends upon how it is used.  If
-you apply this method to the *Reptiles* folder with the URL
-'http://localhost:8080/Reptiles/list', then you will get
-something that looks like the figure below.
-
-.. figure:: ../Figures/7-3.png
-
-   Applying the *list* method to the *Reptiles* folder
-
-But if you were to apply the method to the *Birds* folder with
-the URL *http://localhost:8080/Birds/list* then you would get
-something different, only two items in the list, *Parrot* and
-*Raptors*.
-
-Same DTML Method, different results. In the first example, the client
-object of the *list* method was the *Reptiles* folder.  In the second
-example, the client object was the *Birds* folder. When Zope looked
-up the *objectValues* variable, in the first case it called the
-*objectValues* method of the *Reptiles* folder, in the second case it
-called the *objectValues* method of the *Birds* folder.
-
-In other words, the client object is where variables such as
-methods, and properties are looked up first.
-
-As you saw in "Dynamic Content with DTML", if Zope
-cannot find a variable in the client object, it searches through
-the object's containers.  Zope uses acquisition to automatically
-inherit variables from the client object's containers.  So when
-Zope walks up the object hierarchy looking for variables it
-always starts at the client object, and works its way up from
-there.
-
-DTML Method vs. DTML Document
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-One of the most potentially confusing choices to make for Zope
-newbies is the choice between a DTML Method and a DTML Document.
-Unfortunately, many Zope newbies develop entire sites using one 
-type of object only to discover that they should have used the 
-other type. In general, keep the following items in mind when 
-deciding upon which type to use:
-
-- **Does the object require properties of its own?** If so,
-    use a DTML Document since DTML Methods have no inherent
-    properties.
-
-- **Does the object need to be called as a "page"?** If so,
-    consider using a DTML Document since it will be easier
-    to control such items as page title by using properties.
-
-- **Does the object need transparency to its context?** If so, 
-    you should probably use a DTML Method since these objects
-    act as though they are directly attached to their calling, 
-    or containing object.
-
-DTML Request Object
-~~~~~~~~~~~~~~~~~~~
-
-The request object is the bottom object on the DTML
-namespace stack.  The request contains all of the information
-specific to the current web request.
-
-Just as the client object uses acquisition to look in a number
-of places for variables, so too the request looks up variables
-in a number of places. When the request looks for a variable it
-consults these sources in order:
-
-1. The CGI environment. The `Common Gateway Interface
-   <http://www.w3.org/CGI/>`_, or CGI interface defines
-   a standard set of environment variables to be used by
-   dynamic web scripts.  These variables are provided by Zope
-   in the REQUEST namespace.
-
-2. Form data. If the current request is a form action, then
-   any form input data that was submitted with the request can
-   be found in the REQUEST object.
-
-3. Cookies. If the client of the current request has any cookies
-   these can be found in the current REQUEST object.
-
-4. Additional variables. The REQUEST namespace provides you
-   with lots of other useful information, such as the URL of
-   the current object and all of its parents.
-
-The request namespace is very useful in Zope since it is the
-primary way that clients (in this case, web browsers)
-communicate with Zope by providing form data, cookies and other
-information about themselves. For more information about the
-request object, see Appendix B.
-
-A very simple and enlightening example is to simply render the REQUEST
-object in a DTML Document or Method::
-
-  <dtml-var standard_html_header>
-
-  <dtml-var REQUEST>
-
-  <dtml-var standard_html_footer>
-
-Try this yourself, you should get something that looks like
-the figure below.
-
-.. figure:: ../Figures/7-4.png
-
-   Displaying the request
-
-Since the request comes after the client object, if there are names
-that exist in both the request and the client object, DTML will
-always find them first in the client object. This can be a
-problem. Next, let's look at some ways to get around this problem by
-controlling more directly how DTML looks up variables.
-
-Rendering Variables
--------------------
-
-When you insert a variable using the *var* tag, Zope first looks
-up the variable using the DTML namespace, it then *renders* it
-and inserts the results. Rendering means turning an object or
-value into a string suitable for inserting into the output. Zope
-renders simple variables by using Python's standard method for
-coercing objects to strings. For complex objects such as DTML
-Methods and SQL Methods, Zope will call the object instead of
-just trying to turn it into a string. This allows you to insert
-DTML Methods into other DTML Methods.
-
-In general Zope renders variables in the way you would
-expect. It's only when you start doing more advanced tricks that
-you become aware of the rendering process. Later in this chapter
-we'll look at some examples of how to control rendering using
-the 'getitem' DTML utility function.
-
-Modifying the DTML Namespace
-----------------------------
-
-Now that you know the DTML namespace is a stack, you may
-be wondering how, or even why, new objects get pushed onto it.
-
-Some DTML tags modify the DTML namespace while they are executing.
-A tag may push some object onto the namespace stack during the
-course of execution.  These tags include the *in* tag, the *with*
-tag, and the *let* tag.
-
-*In* Tag Namespace Modifications
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When the *in* tag iterates over a sequence it pushes the current
-item in the sequence onto the top of the namespace stack::
-
-  <dtml-var getId> <!-- This is the id of the client object -->
-
-  <dtml-in objectValues>
-
-    <dtml-var getId> <!-- this is the id of the current item in the 
-                       objectValues sequence -->
-  </dtml-in>
-
-You've seen this many times throughout the examples in this
-book.  While the *in* tag is iterating over a sequence, each item
-is pushed onto the namespace stack for the duration of the
-contents of the in tag block.  When the block is finished
-executing, the current item in the sequence is popped off the
-DTML namespace stack and the next item in the sequence is pushed
-on.
-
-Additional Notes
-%%%%%%%%%%%%%%%%
-
-To be more accurate, the *in* tag pushes a number of items
-onto the namespace stack.  These include sequence variables,
-grouping variables, and batch variables in addition to the
-object itself.  Some of those variables are:
-
-- sequence-item: The current item within the iteration.
-
-- sequence-start: True if the current item is the first item
-  in the sequence.
-
-- sequence-end: True if the current item is the last item in
-   the sequence.
-
-- sequence-length: The length of the sequence. 
-
-- previous-sequence: True on the first iteration if the
-  current batch is not the first one. Batch size is set with the
-  size attribute.
-
-- next-sequence: True on the last iteration if the current
-  batch is not the last batch.
-
-There are many more variables available when using the *in*
-tag.  See `Appendix A <AppendixA.html>`_ for more detail.
-
-The *With* Tag
-~~~~~~~~~~~~~~
-
-The *with* tag pushes an object that you specify onto 
-the namespace stack for the duration of the with block. This
-allows you to specify where variables should be looked up first.
-When the with block closes, the object is popped off the
-namespace stack.
-
-Consider a folder that contains a bunch of methods and
-properties that you are interested in.  You could access those
-names with Python expressions like this::
-
-  <dtml-var standard_html_header>
-
-  <dtml-var expr="Reptiles.getReptileInfo()">
-  <dtml-var expr="Reptiles.reptileHouseMaintainer">
-
-  <dtml-in expr="Reptiles.getReptiles()">
-    <dtml-var species>
-  </dtml-in>
-
-  <dtml-var standard_html_footer>
-
-Notice that a lot of complexity is added to the code just to get
-things out of the *Reptiles* folder. Using the *with* tag you can
-make this example much easier to read::
-
-  <dtml-var standard_html_header>
-
-  <dtml-with Reptiles>
-
-    <dtml-var getReptileInfo>
-    <dtml-var reptileHouseMaintainer>
-
-    <dtml-in getReptiles>
-      <dtml-var species>
-    </dtml-in>
-
-  </dtml-with>
-
-  <dtml-var standard_html_footer>
-
-Another reason you might want to use the *with* tag is to put the
-request, or some part of the request on top of the namespace
-stack. For example suppose you have a form that includes an input
-named *id*. If you try to process this form by looking up the
-*id* variable like so::
-
-  <dtml-var id>
-
-You will not get your form's id variable, but the client
-object's id. One solution is to push the web request's form on
-to the top of the DTML namespace stack using the *with* tag::
-
-  <dtml-with expr="REQUEST.form">
-    <dtml-var id>
-  </dtml-with>
-
-This will ensure that you get the form's id first. See Appendix
-B for complete API documentation of the request object.
-
-If you submit your form without supplying a value for the *id* input,
-the form on top of the namespace stack will do you no good, since the
-form doesn't contain an *id* variable. You'll still get the client
-object's id since DTML will search the client object after failing to
-find the *id* variable in the form. The *with* tag has an attribute
-that lets you trim the DTML namespace to only include the object you
-pushed onto the namespace stack::
-
-  <dtml-with expr="REQUEST.form" only>
-    <dtml-if id>
-      <dtml-var id>
-    <dtml-else>
-      <p>The form didn't contain an "id" variable.</p>
-    </dtml-if>
-  </dtml-with>
-
-Using the *only* attribute allows you to be sure about where
-your variables are being looked up.
-
-The *Let* Tag
-~~~~~~~~~~~~~
-
-The *let* tag lets you push a new namespace onto the namespace stack.
-This namespace is defined by the tag attributes to the *let* tag::
-
-  <dtml-let person="'Bob'" relation="'uncle'">
-    <p><dtml-var person>'s your <dtml-var relation>.</p>
-  </dtml-let>
-
-This would display::
-
-  <p>Bob's your uncle.</p>
-
-The *let* tag accomplishes much of the same goals as the *with*
-tag. The main advantage of the let tag is that you can use it to
-define multiple variables to be used in a block. The *let* tag
-creates one or more new name-value pairs and pushes a
-namespace object containing those variables and their values on
-to the top of the DTML namespace stack. In general the *with*
-tag is more useful to push existing objects onto the namespace
-stack, while the *let* tag is better suited for defining new
-variables for a block.
-
-When you find yourself writing complex DTML that requires things
-like new variables, there's a good chance that you could do the
-same thing better with Python or Perl. Advanced scripting is
-covered in the chapter entitled `Advanced Zope Scripting
-<ScriptingZope.html>`_ .
-
-The DTML namespace is a complex place, and this complexity evolved
-over a lot of time.  Although it helps to understand where names come
-from, it is much more helpful to always be specific about where you
-are looking for a name.  The 'with' and 'let' tags let you alter
-the namespace in order to obtain references to the objects you
-need.
-
-DTML Namespace Utility Functions 
---------------------------------
-
-Like all things in Zope, the DTML namespace is an object, and it can
-be accessed directly in DTML with the *_* (underscore) object.  The
-*_* namespace is often referred to as "the under namespace".
-
-The under namespace provides you with many useful methods for certain
-programming tasks.  Let's look at a few of them.
-
-Say you wanted to print your name three times.  This can be done
-with the *in* tag, but how do you explicitly tell the *in* tag to
-loop three times?  Just pass it a sequence with three items::
-
-  <dtml-var standard_html_header>
-
-  <ul>
-  <dtml-in expr="_.range(3)">
-    <li><dtml-var sequence-item>: My name is Bob.</li>
-  </dtml-in>
-  </ul>
-
-  <dtml-var standard_html_footer>
-
-The '_.range(3)' Python expression will return a sequence of the
-first three integers, 0, 1, and 2.  The *range* function is a
-*standard Python built-in* and many of Python's built-in functions
-can be accessed through the *_* namespace, including:
-
-'range([start,], stop, [step])'
-  Returns a list of integers
-  from 'start' to 'stop' counting 'step' integers at a
-  time. 'start' defaults to 0 and 'step' defaults to 1.  For example:
-
-'_.range(3,10,2)'
-    gives '[3,5,7,9]'.
-
-'_.len(sequence)'
-  'len' returns the size of *sequence* as an integer.
-
-Many of these names come from the Python language, which contains
-a set of special functions called 'built-ins'.  The Python
-philosophy is to have a small number of built-in names.  The Zope
-philosophy can be thought of as having a large, complex array of
-built-in names.
-
-The under namespace can also be used to explicitly control variable
-look up.  There is a very common usage of this syntax.  As mentioned 
-above the in tag defines a number of special variables, like
-*sequence-item* and *sequence-key* that you can use inside a loop to
-help you display and control it.  What if you wanted to use one of
-these variables inside a Python expression?::
-
-  <dtml-var standard_html_header>
-
-  <h1>The squares of the first three integers:</h1>
-  <ul>
-  <dtml-in expr="_.range(3)">
-    <li>The square of <dtml-var sequence-item> is: 
-      <dtml-var expr="sequence-item * sequence-item">
-    </li>
-  </dtml-in>  
-  </ul>  
-
-  <dtml-var standard_html_footer>
-
-Try this, does it work?  No!  Why not?  The problem lies in this
-var tag::
-
-  <dtml-var expr="sequence-item * sequence-item">
-
-Remember, everything inside a Python expression attribute must be
-a *valid Python expression*.  In DTML, *sequence-item* is the name
-of a variable, but in Python this means "The object *sequence*
-minus the object *item*".  This is not what you want.
-
-What you really want is to look up the variable *sequence-item*.
-One way to solve this problem is to use the *in* tag *prefix*
-attribute. For example::
-
-  <dtml-var standard_html_header>
-
-  <h1>The squares of the first three integers:</h1>
-  <ul>
-  <dtml-in prefix="loop" expr="_.range(3)">
-    <li>The square of <dtml-var loop_item> is: 
-      <dtml-var expr="loop_item * loop_item">
-    </li>
-  </dtml-in>  
-  </ul>  
-
-  <dtml-var standard_html_footer>   
-
-The *prefix* attribute causes *in* tag variables to be renamed
-using the specified prefix and underscores, rather than using
-"sequence" and dashes. So in this example, "sequence-item" becomes
-"loop_item". See Appendix A for more information on the *prefix*
-attribute.
-
-Another way to look up the variable *sequence-item* in a DTML
-expression is to use the *getitem* utility function to explicitly
-look up a variable::
-
-  The square of <dtml-var sequence-item> is:
-  <dtml-var expr="_.getitem('sequence-item') * 
-                  _.getitem('sequence-item')">
-
-The *getitem* function takes the name to look up as its first
-argument. Now, the DTML Method will correctly display the square of the
-first three integers.  The *getitem* method takes an optional second
-argument which specifies whether or not to render the variable. Recall
-that rendering a DTML variable means turning it into a string. By
-default the *getitem* function does not render a variable.
-
-Here's how to insert a rendered variable named *myDoc*::
-
-  <dtml-var expr="_.getitem('myDoc', 1)">
-
-This example is in some ways rather pointless, since it's the
-functional equivalent to::
-
-  <dtml-var myDoc>
-
-However, suppose you had a form in which a user got to select
-which document they wanted to see from a list of choices. Suppose
-the form had an input named *selectedDoc* which contained the name
-of the document. You could then display the rendered document like
-so::
-
-  <dtml-var expr="_.getitem(selectedDoc, 1)">
-
-Notice in the above example that *selectedDoc* is not in
-quotes. We don't want to insert the text *selectedDoc*
-we want to insert the value of the variable named *selectedDoc*. For
-example, the value of *selectedDoc* might be 'chapterOne'. Using this
-method, you can look up an item using a dynamic value instead of 
-static text.
-
-If you are a python programmer and you begin using the more
-complex aspects of DTML, consider doing a lot of your work in
-Python scripts that you call *from* DTML.  This is explained more
-in the chapter entitled `Advanced Zope Scripting`_.
-Using Python sidesteps many of the issues in DTML.
-
-DTML Security
--------------
-
-Zope can be used by many different kinds of users.  For example, the
-Zope site, `Zope.org <http://www.zope.org/>`_, has over 11,000 community
-members at the time of this writing.  Each member can log into Zope,
-add objects and news items, and manage their own personal area.
-
-Because DTML is a scripting language, it is very flexible about
-working with objects and their properties.  If there were no security
-system that constrained DTML then a user could potentially create
-malicious or privacy-invading DTML code.
-
-DTML is restricted by standard Zope security settings. So if you
-don't have permission to access an object by going to its URL you
-also don't have permission to access it via DTML. You can't use
-DTML to trick the Zope security system.
-
-For example, suppose you have a DTML Document named *Diary* which
-is private. Anonymous users can't access your diary via the
-web. If an anonymous user views DTML that tries to access your
-diary they will be denied::
-
-  <dtml-var Diary>
-
-DTML verifies that the current user is authorized to access all
-DTML variables.  If the user does not have authorization, then the
-security system will raise an *Unauthorized* error and the user
-will be asked to present more privileged authentication
-credentials.
-
-In the chapter entitled `Users and Security <Security.html>`_ , you
-read about security rules for executable content. There are ways
-to tailor the roles of a DTML Document or Method to allow it to
-access restricted variables regardless of the viewer's roles.
-
-Safe Scripting Limits
----------------------
-
-DTML will not let you gobble up memory or execute infinite loops
-and recursions.  Because the restrictions on looping and memory
-use are relatively tight, DTML is not the right language for
-complex, expensive programming logic.  For example, you cannot
-create huge lists with the *_.range* utility function. You also
-have no way to access the filesystem directly in DTML.
-
-Keep in mind however that these safety limits are simple and can
-be outsmarted by a determined user.  It's generally not a good
-idea to let anyone you don't trust write DTML code on your site.
-
-Advanced DTML Tags
-------------------
-
-In the rest of this chapter we'll look at the many advanced DTML
-tags. These tags are summarized in Appendix A.  DTML has a set of
-built-in tags, as documented in this book, which can be counted on
-to be present in all Zope installations and perform the most
-common kinds of things. However, it is also possible to add new
-tags to a Zope installation. Instructions for doing this are
-provided at the Zope.org website, along with an interesting set
-of contributed DTML tags.
-
-This section covers what could be referred to as Zope
-*miscellaneous* tags.  These tags don't really fit into any broad
-categories except for one group of tags, the *exception handling*
-DTML tags which are discussed at the end of this chapter.
-
-The *Call* Tag
---------------
-
-The *var* tag can call methods, but it also inserts the return
-value. Using the *call* tag you can call methods without inserting
-their return value into the output.  This is useful if you are
-more interested in the effect of calling a method rather than its
-return value.
-
-For example, when you want to change the value of a property,
-*animalName*, you are more interested in the effect of calling the
-*manage_changeProperties* method than the return value the method
-gives you.  Here's an example::
-
-  <dtml-if expr="REQUEST.has_key('animalName')">
-    <dtml-call expr="manage_changeProperties(animalName=REQUEST['animalName'])">
-    <h1>The property 'animalName' has changed</h1>
-  <dtml-else>
-    <h1>No properties were changed</h1>
-  </dtml-if>
-
-In this example, the page will change a property depending on whether
-a certain name exists.  The result of the *manage_changeProperties*
-method is not important and does not need to be shown to the user.
-
-Another common usage of the *call* tag is calling methods that affect
-client behavior, like the 'RESPONSE.redirect' method.  In this
-example, you make the client redirect to a different page, to
-change the page that gets redirected, change the value for the
-"target" variable defined in the *let* tag::
-
-  <dtml-var standard_html_header>
-
-  <dtml-let target="'http://example.com/new_location.html'">
-
-    <h1>This page has moved, you will now be redirected to the
-    correct location.  If your browser does not redirect, click <a
-    href="<dtml-var target>"><dtml-var target></a>.</h1>
-
-    <dtml-call expr="RESPONSE.redirect(target)">
-
-  </dtml-let>
-
-  <dtml-var standard_html_footer>  
-
-In short, the *call* tag works exactly like the *var* tag with the
-exception that it doesn't insert the results of calling the
-variable.
-
-Another possibility for use of the *call* tag would be to call a
-ZSQL Method or or preprocess the REQUEST.  Two examples of calling
-a ZSQL method::
-
-  <dtml-call "insertLogEntry(REQUEST)">
-
-or::
-
-  <dtml-call "insertLogEntry(logInfo=REQUEST.get('URL0'), severity=1)">
-
-To call a python script that might do any number of things,
-including preprocessing the REQUEST::
-
-  <dtml-call "preprocess(REQUEST)">
-
-The *Comment* Tag
------------------
-
-DTML can be documented with comments using the *comment* tag::
-
-  <dtml-var standard_html_header>
-
-  <dtml-comment>
-
-    This is a DTML comment and will be removed from the DTML code
-    before it is returned to the client.  This is useful for
-    documenting DTML code.  Unlike HTML comments, DTML comments
-    are NEVER sent to the client.
-
-  </dtml-comment>
-
-  <!-- 
-
-    This is an HTML comment, this is NOT DTML and will be treated
-    as HTML and like any other HTML code will get sent to the
-    client.  Although it is customary for an HTML browser to hide
-    these comments from the end user, they still get sent to the
-    client and can be easily seen by 'Viewing the Source' of a
-    document.
-
-  -->
-
-  <dtml-var standard_html_footer>        
-
-The *comment* block is removed from DTML output.
-
-In addition to documenting DTML you can use the *comment* tag to
-temporarily comment out other DTML tags. Later you can remove the
-*comment* tags to re-enable the DTML.
-
-The *Tree* Tag
---------------
-
-The *tree* tag lets you easily build dynamic trees in HTML to
-display hierarchical data.  A *tree* is a graphical representation
-of data that starts with a "root" object that has objects
-underneath it often referred to as "branches".  Branches can have
-their own branches, just like a real tree.  This concept should be
-familiar to anyone who has used a file manager program like
-Microsoft Windows Explorer to navigate a file system.  And, in
-fact, the left hand "navigation" view of the Zope management
-interface is created using the tree tag.
-
-For example here's a tree that represents a collection of folders
-and sub-folders.
-
-.. figure:: ../Figures/7-5.png
-
-   HTML tree generated by the tree tag
-
-Here's the DTML that generated this tree display::
-
-  <dtml-var standard_html_header>
-
-  <dtml-tree>
-
-    <dtml-var getId>
-
-  </dtml-tree>
-
-  <dtml-var standard_html_footer>
-
-The *tree* tag queries objects to find their sub-objects and takes
-care of displaying the results as a tree. The *tree* tag block works
-as a template to display nodes of the tree.
-
-Now, since the basic protocol of the web, HTTP, is stateless, you
-need to somehow remember what state the tree is in every time you
-look at a page.  To do this, Zope stores the state of the tree in
-a *cookie*.  Because this tree state is stored in a cookie, only
-one tree can appear on a web page at a time, otherwise they will
-confusingly use the same cookie.
-
-You can tailor the behavior of the *tree* tag quite a bit with *tree*
-tag attributes and special variables. Here is a sampling of *tree*
-tag attributes.
-
-branches
-  The name of the method used to find sub-objects. This
-  defaults to *tpValues*, which is a method defined by a number of
-  standard Zope objects.
-
-leaves
-  The name of a method used to display objects that do
-  not have sub-object branches.
-
-nowrap
-  Either 0 or 1. If 0, then branch text will wrap to fit in
-  available space, otherwise, text may be truncated. The default
-  value is 0.
-
-sort
-  Sort branches before text insertion is performed. The
-  attribute value is the name of the attribute that items should be
-  sorted on.
-
-assume_children
-  Either 0 or 1. If 1, then all objects are
-  assumed to have sub-objects, and will therefore always have a
-  plus sign in front of them when they are collapsed. Only when an
-  item is expanded will sub-objects be looked for. This could be a
-  good option when the retrieval of sub-objects is a costly
-  process.  The defalt value is 0.
-
-single
-  Either 0 or 1. If 1, then only one branch of the tree can
-  be expanded. Any expanded branches will collapse when a new branch
-  is expanded.  The default value is 0.
-
-skip_unauthorized
-  Either 0 or 1. If 1, then no errors will be
-  raised trying to display sub-objects for which the user does not
-  have sufficient access. The protected sub-objects are not
-  displayed.  The default value is 0.
-
-Suppose you want to use the *tree* tag to create a dynamic site
-map. You don't want every page to show up in the site map. Let's
-say that you put a property on folders and documents that you want
-to show up in the site map.
-
-Let's first define a Script with the id of *publicObjects*
-that returns public objects::
-
-  ## Script (Python) "publicObjects"
-  ##
-  """
-  Returns sub-folders and DTML documents that have a
-  true 'siteMap' property.
-  """
-  results=[]
-  for object in context.objectValues(['Folder', 'DTML Document']):
-      if object.hasProperty('siteMap') and object.siteMap:
-          results.append(object)
-  return results
-
-Now we can create a DTML Method that uses the *tree* tag and our
-Scripts to draw a site map::
-
-  <dtml-var standard_html_header>
-
-  <h1>Site Map</h1>
-
-  <p><a href="&dtml-URL0;?expand_all=1">Expand All</a> |
-     <a href="&dtml-URL0;?collapse_all=1">Collapse All</a>
-  </p>
-
-  <dtml-tree branches="publicObjects" skip_unauthorized="1">
-    <a href="&dtml-absolute_url;"><dtml-var title_or_id></a>
-  </dtml-tree>
-
-  <dtml-var standard_html_footer>
-
-This DTML Method draws a link to all public resources and displays
-them in a tree. Here's what the resulting site map looks like.
-
-.. figure:: ../Figures/7-6.png
-
-   Dynamic site map using the tree tag
-
-For a summary of the *tree* tag arguments and special variables see
-Appendix A.
-
-The *Return* Tag
-----------------
-
-In general DTML creates textual output. You can however, make DTML
-return other values besides text. Using the *return* tag you can
-make a DTML Method return an arbitrary value just like a Python or
-Perl-based Script.
-
-Here's an example::
-
-  <p>This text is ignored.</p>
-
-  <dtml-return expr="42">
-
-This DTML Method returns the number 42.
-
-Another upshot of using the *return* tag is that DTML execution
-will stop after the *return* tag.
-
-If you find yourself using the *return* tag, you almost certainly
-should be using a Script instead. The *return* tag was developed
-before Scripts, and is largely useless now that you can easily
-write scripts in Python and Perl.
-
-The *Sendmail* Tag
-------------------
-
-The *sendmail* tag formats and sends a mail messages. You can use
-the *sendmail* tag to connect to an existing Mail Host, or you can
-manually specify your SMTP host.
-
-Here's an example of how to send an email message with the
-*sendmail* tag::
-
-  <dtml-sendmail>
-  To: <dtml-var recipient>
-  From: <dtml-var sender>
-  Subject: Make Money Fast!!!!
-
-  Take advantage of our exciting offer now! Using our exclusive method
-  you can build unimaginable wealth very quickly. Act now!
-  </dtml-sendmail>
-
-Notice that there is an extra blank line separating the mail
-headers from the body of the message.
-
-A common use of the *sendmail* tag is to send an email message
-generated by a feedback form. The *sendmail* tag can contain any
-DTML tags you wish, so it's easy to tailor your message with form
-data.
-
-The *Mime* Tag
---------------
-
-The *mime* tag allows you to format data using MIME (Multipurpose
-Internet Mail Extensions). MIME is an Internet standard for
-encoding data in email message. Using the *mime* tag you can use
-Zope to send emails with attachments.
-
-Suppose you'd like to upload your resume to Zope and then have Zope
-email this file to a list of potential employers.
-
-Here's the upload form::
-
-  <dtml-var standard_html_header>
-
-  <p>Send you resume to potential employers</p>
-
-  <form method=post action="sendresume" ENCTYPE="multipart/form-data">
-  <p>Resume file: <input type="file" name="resume_file"></p>
-  <p>Send to:</p>
-  <p>
-  <input type="checkbox" name="send_to:list" value="jobs at yahoo.com">
-    Yahoo<br>
-
-  <input type="checkbox" name="send_to:list" value="jobs at microsoft.com">
-    Microsoft<br>
-
-  <input type="checkbox" name="send_to:list" value="jobs at mcdonalds.com">
-    McDonalds</p>
-
-  <input type=submit value="Send Resume">
-  </form>
-
-  <dtml-var standard_html_footer>
-
-Note:  The text *:list* added to the name of the input fields directs 
-Zope to treat the received information as a list type. For example if 
-the first two checkboxes were selected in the above upload form, the 
-REQUEST variable send_to would have the value [jobs at yahoo.com, jobs at microsoft.com]
-
-Create another DTML Method called *sendresume* to process the form
-and send the resume file::
-
-  <dtml-var standard_html_header>
-
-  <dtml-if send_to>
-
-    <dtml-in send_to> 
-
-      <dtml-sendmail smtphost="my.mailserver.com">
-      To: <dtml-var sequence-item>
-      Subject: Resume
-      <dtml-mime type=text/plain encode=7bit>
-
-      Hi, please take a look at my resume.
-
-      <dtml-boundary type=application/octet-stream disposition=attachment 
-      encode=base64><dtml-var expr="resume_file.read()"></dtml-mime>
-      </dtml-sendmail>
-
-    </dtml-in>
-
-    <p>Your resume was sent.</p>
-
-  <dtml-else>
-
-    <p>You didn't select any recipients.</p>
-
-  </dtml-if>
-
-  <dtml-var standard_html_footer>    
-
-This method iterates over the *sendto* variable and sends one
-email for each item.
-
-Notice that there is no blank line between the 'To:' header and
-the starting *mime* tag.  If a blank line is inserted between them
-then the message will not be interpreted as a *multipart* message
-by the receiving mail reader.
-
-Also notice that there is no newline between the *boundary* tag
-and the *var* tag, or the end of the *var* tag and the closing
-*mime* tag.  This is important, if you break the tags up with
-newlines then they will be encoded and included in the MIME part,
-which is probably not what you're after.
-
-As per the MIME spec, *mime* tags may be nested within *mime* tags
-arbitrarily.
-
-The *Unless* Tag
-----------------
-
-The *unless* tag executes a block of code unless the given condition is
-true. The *unless* tag is the opposite of the *if* tag.  The DTML
-code::
-
-  <dtml-if expr="not butter">
-    I can't believe it's not butter.
-  </dtml-if>
-
-is equivalent to::
-
-  <dtml-unless expr="butter">
-    I can't believe it's not butter.
-  </dtml-unless>
-
-What is the purpose of the *unless* tag? It is simply a convenience
-tag. The *unless* tag is more limited than the *if* tag, since it
-cannot contain an *else* or *elif* tag.
-
-Like the *if* tag, calling the *unless* tag by name does existence
-checking, so::
-
-  <dtml-unless the_easter_bunny>
-    The Easter Bunny does not exist or is not true.
-  </dtml-unless>
-
-Checks for the existence of *the_easter_bunny* as well as its
-truth. While this example only checks for the truth of
-*the_easter_bunny*::
-
-  <dtml-unless expr="the_easter_bunny">
-    The Easter Bunny is not true.
-  </dtml-unless>
-
-This example will raise an exception if *the_easter_bunny* does not
-exist.
-
-Anything that can be done by the *unless* tag can be done by the
-*if* tag.  Thus, its use is totally optional and a matter of
-style.
-
-Batch Processing With The *In* Tag
-----------------------------------
-
-Often you want to present a large list of information but only
-show it to the user one screen at a time.  For example, if a
-user queried your database and got 120 results, you will probably
-only want to show them to the user a small batch, say 10 or 20
-results per page.  Breaking up large lists into parts is called
-*batching*. Batching has a number of benefits.
-
-  o The user only needs to download a reasonably sized document
-  rather than a potentially huge document. This makes pages load
-  faster since they are smaller.
-
-  o Because smaller batches of results are being used, often less
-  memory is consumed by Zope.
-
-  o *Next* and *Previous* navigation interfaces makes scanning
-  large batches relatively easy.
-
-The *in* tag provides several variables to facilitate batch
-processing.  Let's look at a complete example that shows how to
-display 100 items in batches of 10 at a time::
-
-  <dtml-var standard_html_header>
-
-    <dtml-in expr="_.range(100)" size=10 start=query_start>
-
-      <dtml-if sequence-start>
-
-        <dtml-if previous-sequence>
-          <a href="<dtml-var URL><dtml-var sequence-query
-             >query_start=<dtml-var previous-sequence-start-number>">
-             (Previous <dtml-var previous-sequence-size> results)
-          </a>
-        </dtml-if>
-
-        <h1>These words are displayed at the top of a batch:</h1>
-        <ul>
-
-      </dtml-if>
-
-        <li>Iteration number: <dtml-var sequence-item></li>
-
-      <dtml-if sequence-end>
-
-        </ul>
-        <h4>These words are displayed at the bottom of a batch.</h4>
-
-        <dtml-if next-sequence>
-           <a href="<dtml-var URL><dtml-var sequence-query
-              >query_start=<dtml-var
-              next-sequence-start-number>">
-           (Next <dtml-var next-sequence-size> results)
-           </a>
-
-        </dtml-if>
-
-      </dtml-if>
-
-    </dtml-in>
-
-  <dtml-var standard_html_footer>
-
-Let's take a look at the DTML to get an idea of what's going
-on. First we have an *in* tag that iterates over 100 numbers that
-are generated by the *range* utility function. The *size*
-attribute tells the *in* tag to display only 10 items at a
-time. The *start* attribute tells the *in* tag which item number
-to display first.
-
-Inside the *in* tag there are two main *if* tags. The first one
-tests special variable 'sequence-start'. This variable is only
-true on the first pass through the in block. So the contents of
-this if tag will only be executed once at the beginning of the
-loop. The second *if* tag tests for the special variable
-'sequence-end'. This variable is only true on the last pass
-through the *in* tag. So the second *if* block will only be
-executed once at the end.  The paragraph between the *if* tags is
-executed each time through the loop.
-
-Inside each *if* tag there is another *if* tag that check for the
-special variables 'previous-sequence' and 'next-sequence'. The
-variables are true when the current batch has previous or further
-batches respectively. In other words 'previous-sequence' is true
-for all batches except the first, and 'next-sequence' is true for
-all batches except the last. So the DTML tests to see if there are
-additional batches available, and if so it draws navigation links.
-
-The batch navigation consists of links back to the document with a
-*query_start* variable set which indicates where the *in* tag should
-start when displaying the batch. To better get a feel for how this
-works, click the previous and next links a few times and watch how
-the URLs for the navigation links change.
-
-Finally some statistics about the previous and next batches are
-displayed using the 'next-sequence-size' and
-'previous-sequence-size' special variables.  All of this ends up
-generating the following HTML code::
-
-  <html>
-  <head><title>Zope</title>
-  </head>
-  <body bgcolor="#FFFFFF">
-
-    <h1>These words are displayed at the top of a batch:</h1>
-    <ul>
-      <li>Iteration number: 0</li>
-      <li>Iteration number: 1</li>
-      <li>Iteration number: 2</li>
-      <li>Iteration number: 3</li>
-      <li>Iteration number: 4</li>
-      <li>Iteration number: 5</li>
-      <li>Iteration number: 6</li>
-      <li>Iteration number: 7</li>
-      <li>Iteration number: 8</li>
-      <li>Iteration number: 9</li>
-    </ul>
-    <h4>These words are displayed at the bottom of a batch.</h4>
-
-       <a href="http://pdx:8090/batch?query_start=11">
-         (Next 10 results)
-       </a>
-
-  </body>
-  </html>
-
-Another example utilizes the commonly accepted navigation scheme
-of presenting the the user page numbers from which to select::
-
-   <dtml-in "_.range(1,101) "size=10 start=start>
-             <dtml-if sequence-start>
-               <p>Pages: 
-               <dtml-call "REQUEST.set('actual_page',1)">
-               <dtml-in previous-batches mapping>   
-                 <a href="<dtml-var URL><dtml-var sequence-query>start=<dtml-var "_['batch-start-index']+1">">
-                 <dtml-var sequence-number></a>&nbsp;
-                 <dtml-call "REQUEST.set('actual_page',_['sequence-number']+1)">     
-               </dtml-in>
-               <b><dtml-var "_['actual_page']"></b>  
-             </dtml-if>
-             <dtml-if sequence-end>
-               <dtml-in next-batches mapping>&nbsp;
-                  <a href="<dtml-var URL><dtml-var sequence-query>start=<dtml-var "_['batch-start-index']+1">">
-                  <dtml-var "_['sequence-number']+_['actual_page']"></a>
-                </dtml-in>
-             </dtml-if>
-    </dtml-in>
-
-    <dtml-in "_.range(1,101) "size=10 start=start>
-              <br><dtml-var sequence-item>
-    </dtml-in>      
-
-This quick and easy method to display pages is a nice navigational tool
-for larger batches.  It does present the drawback of having to utilize
-an additional *dtml-in* tag to iterate through the actual items, however.
-
-Batch processing can be complex. A good way to work with batches
-is to use the Searchable Interface object to create a batching
-search report for you. You can then modify the DTML to fit your
-needs.  This is explained more in the chapter entitled `Searching
-and Categorizing Content <SearchingZCatalog.html>`_.
-
-Other useful examples
----------------------
-
-In this section are several useful examples of dtml code.  While
-many of these are most often better done in Python scripts, there
-are occasions when knowing how to accomplish this in dtml is
-worthwhile.
-
-Forwarding a REQUEST
-~~~~~~~~~~~~~~~~~~~~
-
-We have seen how to redirect the user's browser to another page
-with the help of the *call* directive.  However, there are times
-when a redirection is not necessary and a simple forwarding of a
-REQUEST from one dtml-method to another would suffice.  In this
-example, the dtml-method shown obtains a variable named *type*
-from the REQUEST object.  A lookup table is reference to obtain
-the name of the dtml-method to which the REQUEST should be
-forwarded.  The code below accomplishes this::
-
-  <dtml-let lookup="{'a' : 'form15', 'b' : 'form75', 'c' : 'form88'}">
-        <dtml-return "_[lookup[REQUEST.get('type')]]">
-  </dtml-let>
-
-This code looks up the name of the desired dtml-method in the
-lookup table (contained in the *let* statement) and in turn,
-looks up the name of this dtml-method in the current namespace.
-As long as the dtml-method exists, control will be passed to the
-method directly.  This example could be made more complete with
-the addition of exception handling which was discussed above.
-
-Sorting with the '<dtml-in>' tag
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-There are many times when sorting a result set is necessary.
-The *dtml-in* tag has some very interesting sort capabilities
-for both static and dynamic sorting.  In the example below, a
-ZSQL method is called that returns results from a log table.
-The columns returned are logTime, logType, and userName.  The
-dtml-method or document that contains this code will generate
-links back to itself to re-sort the query based upon certain
-search criteria::
-
-  <dtml-comment>
-
-  The sorting is accomplished by looking up a sort type
-  variable in the REQUEST that is comprised of two parts.  All
-  but the last character indicate the name of the column on
-  which to sort.  The last character of the sort type indicates
-  whether the sort should be ascending or descending.
-
-  </dtml-comment>
-
-  <table>
-    <tr>
-      <td>Time&nbsp;<a href="<dtml-var URL>?st=logTimea">A</a>&nbsp;<a href="<dtml-var URL>?st=logTimed">D</a></td>
-      <td>Type&nbsp;<a href="<dtml-var URL>?st=logTypea">A</a>&nbsp;<a href="<dtml-var URL>?st=logTyped">D</a></td>
-      <td>User&nbsp;<a href="<dtml-var URL>?st=userNamea">A</a>&nbsp;<a href="<dtml-var URL>?st=userNamed">D</a></td>
-    </tr>
-
-    <dtml-comment>The line below sets the default sort</dtml-comment>
-    <dtml-if "REQUEST.get('st')==None"><dtml-call "REQUEST.set('st', 'logTimed')"></dtml-if>
-    <dtml-in getLogData sort_expr="REQUEST.get('st')[0:-1]" reverse_expr="REQUEST.get('st')[-1]=='d'">
-      <tr>
-        <td><dtml-var logTime></td>
-        <td><dtml-var logType></td>
-        <td><dtml-var userName></td>
-      </tr>
-    </dtml-in>
-  </table>
-
-Calling a DTML object from a Python Script
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Although calling a DTML method from a Python script isn't really
-an advanced DTML technique, it deals with DTML, so it's being
-included here.  To call a DTML Method or DTML Document from a
-Python script, the following code is used::
-
-  dtmlMethodName = 'index_html'
-  return context[dtmlMethodName](container, container.REQUEST)
-
-It's as simple as that.  Often this is very useful if you wish
-to forward a request and significant processing is needed to
-determine which dtml object is the target.
-
-Explicit Lookups
-~~~~~~~~~~~~~~~~
-
-Occasionally it is useful to "turn off" acquisition when looking
-up an attribute.  In this example, you have a folder which
-contains sub-folders.  Each sub-folder contains Images.  The
-top-level folder, each subfolder, and each image contain a
-property named *desc*.
-
-If you were to query the Image for its *desc* property it would
-return the *desc* property of it's parent folder if the Image
-did not have the property.  This could cause confusion as the
-Image would appear to have the *desc* property when it really
-belonged to the parent folder.  In most cases, this behavior is
-desired.  However, in this case, the user would like to see
-which images have the *desc* property and which don't.  This is
-accomplished by utilizing *aq_explicit* in the call to the
-object in question.
-
-Given the following structure::
-
- Folder 
-   |
-   |- Folder1 (desc='Folder one')
-   |- Folder2 (desc='Folder two')
-        |- Image1 (desc='Photo one')
-        |- Image2 
-        |- Image3 (desc='Photo three')
-
-when the second image is asked for its *desc* property it will
-return 'Folder two' based on acquisition rules::
-
-  <dtml-var "Image2.desc">
-
-However, utilizing *aq_explicit* will cause Zope to look only
-in the desired location for the property::
-
-  <dtml-var "Image2.aq_explicit.desc">
-
-This will, of course, raise an exception when the *desc*
-property does not exist.  A safer way to do this is::
-
-  <dtml-if "_.hasattr(Image2.aq_explicit, 'desc')">
-    <dtml-var "Image2.aq_explicit.desc">
-  <dtml-else>
-    No desc property.
-  </dtml-if>
-
-As you can see, this can be very useful.
-
-Conclusion
-----------
-
-DTML provides some very powerful functionality for designing web
-applications.  In this chapter, we looked at the more advanced
-DTML tags and some of their options.  A more complete reference
-can be found in Appendix A.
-
-The next chapter teaches you how to become a Page Template
-wizard. While DTML is a powerful tool, Page Templates provide a
-more elegant solution to HTML generation.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/AdvZPT.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/AdvZPT.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/AdvZPT.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,1384 +0,0 @@
-Advanced Page Templates
-=======================
-
-In the chapter entitled `Using Zope Page Templates <ZPT.html>`_ you
-learned the basic features of Page Templates. In this chapter
-you'll learn about advanced techniques including new types of
-expressions.
-
-Advanced TAL
-------------
-
-In this section we'll go over all TAL statements and their various
-options in depth.  This material is covered more concisely in
-`Appendix C: Zope Page Templates Reference <AppendixC.html>`_.
-
-In this chapter, the terms 'tag' and 'element' are used in the
-sense laid out by the `XHTML spec
-<http://www.w3.org/TR/2000/REC-xhtml1-20000126/#defs>`_.
-"&lt;p&gt;" is a *tag*, while the entire block
-"&lt;p&gt;stuff&lt;/p&gt;" from opening tag through the closing
-tag is an *element*.
-
-Advanced Content Insertion
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You've already seen how 'tal:content' and 'tal:replace' work in
-the chapter entitled `Using Zope Page Templates  <ZPT.html>`_. In
-this section you'll learn some advanced tricks for inserting
-content.
-
-Inserting Structure
-%%%%%%%%%%%%%%%%%%%
-
-Normally, the 'tal:replace' and 'tal:content' statements
-convert HTML tags and entities in the text that they insert
-into an "escaped" form that appears in the resulting document
-as plain text rather than HTML markup.
-For instance, the '<' character is "escaped" to '&amp;lt;'.
-If you want to insert text as part of the HTML structure of
-your document, avoiding this conversion , you need to
-precede the expression with the 'structure' keyword.
-
-This feature is useful when you are inserting a fragment of
-HTML or XML that is stored by an object or generated by
-another Zope object.  For instance, you may have news items
-that contain simple HTML markup such as bold and italic text
-when they are rendered, and you want to preserve this when
-inserting them into a "Top News" page.  In this case, you
-might write::
-
-  <p tal:repeat="newsItem context/topNews"
-     tal:content="structure newsItem">
-    A news item with<code>HTML</code> markup.
-  </p>
-
-This will insert the news items' HTML into a series of paragraphs. The built-in
-variable 'context' refers to the folder in which the template is rendered; See
-the "Expressions" section further below in this chapter for more information on
-'context'. In this case, we use 'context' as the starting point for finding the
-Zope object 'topNews', which is presumably a list of news items or a Script
-which fetches such a list.
-
-The 'structure' keyword prevents the text of each newsItem
-value from being escaped.  It doesn't matter whether the text
-actually contains any HTML markup, since 'structure' really
-means "leave this text alone".  This behavior
-is not the default because most of the text that you insert
-into a template will *not* contain HTML, but may contain
-characters that would interfere with the structure of your page.
-
-Dummy Elements
-%%%%%%%%%%%%%%
-
-You can include page elements that are visible in the template
-but not in generated text by using the built-in variable
-'nothing', like this::
-
-  <tr tal:replace="nothing">
-    <td>10213</td><td>Example Item</td><td>$15.34</td>
-  </tr>
-
-This can be useful for filling out parts of the page that will
-be populated with dynamic content.  For instance, a table that
-usually has ten rows will only have one row in the template.
-By adding nine dummy rows, the template's layout will look
-more like the final result.
-
-Default Content
-%%%%%%%%%%%%%%%
-
-You can leave the contents of an element alone by using the
-'default' expression with 'tal:content' or 'tal:replace'. For
-example::
-
-  <p tal:content="default">Spam</p>
-
-This renders to::
-
-  <p>Spam</p>
-
-Most often you will want to selectively include default
-content, rather than always including it. For example::
-
-  <p tal:content="python:context.getFood() or default">Spam</p>
-
-.. note:
-   
-   Python expressions are explained later in the chapter. If the
-   'getFood' method returns a true value then its result will be
-   inserted into the paragraph, otherwise it's Spam for dinner.
-
-Advanced Repetition
-~~~~~~~~~~~~~~~~~~~
-
-You've already seen most of what you can do with the
-'tal:repeat' statement in the chapter entitled `Using Zope Page
-Templates  <ZPT.html>`_. This section covers a few advanced features
-of the 'tal:repeat' statement.
-
-Repeat Variables
-%%%%%%%%%%%%%%%%
-
-One topic that bears more explanation are repeat
-variables. Repeat variables provide information about the
-current repetition. The following attributes are available on
-'repeat' variables:
-
-- *index* - repetition number, starting from zero.
-
-- *number* - repetition number, starting from one.
-
-- *even* - true for even-indexed repetitions (0, 2, 4, ...).
-
-- *odd* - true for odd-indexed repetitions (1, 3, 5, ...).
-
-- *start* - true for the starting repetition (index 0).
-
-- *end* - true for the ending, or final, repetition.
-
-- *length* - length of the sequence, which will be the total number
-  of repetitions.
-
-You can access the contents of a repeat variable using path
-expressions or Python expressions.  In path expressions, you
-write a three-part path consisting of the name 'repeat', the
-statement variable's name, and the name of the information you
-want, for example, 'repeat/item/start'.  In Python expressions,
-you use normal dictionary notation to get the repeat variable,
-then attribute access to get the information, for example,
-'python:repeat['item'].start'.  The reason that you can't
-simply write 'repeat/start' is that 'tal:repeat' statements
-can be nested, so you need to be able to specify which one you
-want information about.
-
-Repetition Tips
-%%%%%%%%%%%%%%%
-
-Here are a couple practical tips that you may find
-useful. Sometimes you'd like to repeat part of your template,
-but there is no naturally enclosing element.  In this case,
-you must add an enclosing element, but you want to prevent
-it from appearing in the rendered page. You can do this with
-the 'tal:omit-tag' statement::
-
-  <div tal:repeat="section context/getSections"
-       tal:omit-tag="">
-    <h4 tal:content="section/title">Title</h4>
-    <p tal:content="section/text">quotation</p>
-  </div>
-
-This is not just a matter of saving a few characters in the
-rendered output.  Including the 'div' tags in the output could
-affect the page layout, especially if it has stylesheets. We
-use the tal 'omit-tag' statement to disinclude the 'div' tag
-(and its pair closing tag) while leaving its contents
-unmolested.  The 'tal:omit-tag' statement is described in more
-detail later in this chapter.
-
-While it's been mentioned before, it's worth saying again: you
-can nest 'tal:repeat' statements inside each other. Each
-'tal:repeat' statement must have a different repeat variable
-name. Here's an example that shows a math times-table::
-
-  <table border="1">
-    <tr tal:repeat="x python:range(1, 13)">
-      <td tal:repeat="y python:range(1, 13)"
-          tal:content="python:'%d x %d = %d' % (x, y, x*y)">
-          X x Y = Z
-      </td>
-    </tr>
-  </table>
-
-This example uses Python expressions, which are covered later in this chapter.
-
-One useful feature that isn't supplied by 'tal:repeat' is sorting. If you want
-to sort a list you can either write your own sorting script (which is quite
-easy in Python) or you can use the 'sequence.sort' utility function. Here's an
-example of how to sort a list of objects by title::
-
-  <table tal:define="objects context/objectValues;
-                     sort_on python:(('title', 'nocase', 'asc'),);
-                     sorted_objects python:sequence.sort(objects, sort_on)">
-    <tr tal:repeat="item sorted_objects">
-      <td tal:content="item/title">title</td>
-    </tr>
-  </table>
-
-This example tries to make things clearer by defining the sort
-arguments outside the 'sort' function.  The 'sequence.sort'
-function takes a sequence and a description of how to sort
-it. In this example the description of how to sort the sequence
-is defined in the 'sort_on' variable.  See `Appendix B: API
-Reference <AppendixB.html>`_ for more information on the powerful
-'sequence.sort' function.
-
-Advanced Attribute Control
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You've already met the 'tal:attributes' statement. You can use
-it to dynamically replace tag attributes, for example, the
-'href' attribute on an 'a' element. You can replace more than
-one attribute on a tag by separating attributes with
-semicolons. For example, the code below will generate an
-"href" and a "class" attribute::
-
-  <a href="link"
-     tal:attributes="href context/getLink;
-                     class context/getClass">link</a>
-
-You can also define attributes with XML namespaces. For example::
-
-  <Description 
-      dc:Creator="creator name"
-      tal:attributes="dc:Creator context/owner/getUserName">
-    Description</Description>
-
-Simply put the XML namespace prefix before the attribute name
-and you can create attributes with XML namespaces.
-
-Defining Variables
-~~~~~~~~~~~~~~~~~~
-
-You can define your own variable using the 'tal:define'
-attribute. There are several reasons that you might want to do
-this. One reason is to avoid having to write long expressions
-repeatedly in a template. Another is to avoid having to call
-expensive methods repeatedly. You can define a variable once
-within an element on a tag and then use it many times within
-elements which are enclosed by this tag. For example, here's a
-list that defines a variable and later tests it and repeats over
-it::
-
-  <ul tal:define="items container/objectIds"
-      tal:condition="items">
-    <li tal:repeat="item items">
-      <p tal:content="item">id</p>
-    </li>
-  </ul>
-
-The 'tal:define' statement creates the variable 'items', which
-you can use anywhere in the 'ul' element.  Notice also how you
-can have two TAL statements on the same 'ul' tag.  See the
-section "Interactions Between TAL Statements" later in this
-chapter for more information about using more than one statement
-on a tag.  In this case the first statement assigns the variable
-'items' and the second uses 'items' in a condition to see
-whether it is false (in this case, an empty sequence) or
-true. If the 'items' variable is false, then the 'ul' element is not
-shown.
-
-Now, suppose that instead of simply removing the list when there
-are no items, you want to show a message.  To do this, place the
-following before the list::
-
-  <h4 tal:condition="not:container/objectIds">
-    There Are No Items
-  </h4>
-
-The expression, 'not:container/objectIds' is true when
-'container/objectIds' is false, and vice versa. See the section,
-"Not Expressions" later in this chapter for more information.
-
-You can't use your 'items' variable here, because it isn't defined yet. If you
-move the definition of 'items' to the 'h4' element, then you can't use it in
-the 'ul' element any more, because it becomes a *local* variable of the 'h4'
-element. To have it available on both tags, you can place the definition on
-some element that encloses both the 'h4' and the 'ul' for example the 'body'.
-
-You can define more than one variable using 'tal:define' by separating them
-with semicolons. For example::
-
-  <p tal:define="ids container/objectIds; 
-                 title container/title">
-
-You can define as many variables as you wish. Each variable can
-have its own global or local scope. You can also refer to
-earlier defined variables in later definitions. For example::
-
-  <p tal:define="title template/title;
-                 untitled not:title;
-                 tlen python:len(title);">
-
-With judicious use of 'tal:define' you can improve the efficiency and
-readability of your templates.
-
-Omitting Tags
-~~~~~~~~~~~~~
-
-You can remove tags with the 'tal:omit-tag' statement. You will
-seldom need to use this TAL statement, but occasionally it's
-useful. The omit-tag attribute removes opening and closing tags,
-but does not affect the contents of the element. For example::
-
-  <b tal:omit-tag=""><i>this</i> stays</b>
-
-Renders to::
-
-  <i>this</i> stays
-
-At this level of usage, 'tal:omit-tag' operates almost like
-'tal:replace="default"'. However, 'tal:omit-tag' can also be
-used with a true/false expression, in which case it only removes
-the tags if the expression is true. For example::
-
-  Friends: <span tal:repeat="friend friends">
-    <b tal:omit-tag="not:friend/best"
-       tal:content="friend/name">Fred</b>
-  </span>
-
-This will produce a list of friends, with our "best" friend's
-name in bold.
-
-Error Handling
-~~~~~~~~~~~~~~
-
-If an error occurs in your page template, you can catch that
-error and show a useful error message to your user.  For
-example, suppose your template defines a
-variable using form data::
-
-  ...
-  <span tal:define="prefs request/form/prefs"
-        tal:omit-tag="" />
-  ...
-
-If Zope encounters a problem, like not being able to find the
-'prefs' variable in the form data, the entire page will break;
-you'll get an error page instead. Happily, you can avoid this
-kind of thing with limited error handling using the
-'tal:on-error' statement::
-
-  ...
-  <span tal:define="prefs context/scriptToGetPreferences"
-        tal:omit-tag=""
-        tal:on-error="string:An error occurred">
-  ...
-
-When an error is raised while rendering a template, Zope looks
-for a 'tal:on-error' statement to handle the error. It first
-looks in the current element, then on its enclosing element, and so on
-until it reaches the top-level element. When it finds an error
-handler, it replaces the contents of that element with the error
-handling expression. In this case, the 'span' element will contain
-an error message.
-
-Typically you'll define an error handler on an element that encloses
-a logical page element, for example a table. If an error crops
-up drawing the table, then the error handler can simply omit the
-table from the page, or else replace it with an error message of
-some sort.
-
-For more flexible error handling you can call a script. For
-example::
-
-  <div tal:on-error="structure context/handleError">
-  ...
-  </div>
-
-Any error that occurs inside the 'div' will call the
-'handleError' script. Note that the 'structure' option allows
-the script to return HTML. Your error handling script can
-examine the error and take various actions depending on the
-error. Your script gets access to the error through the 'error'
-variable in the namespace. For example::
-
-  ## Script (Python) "handleError"
-  ##bind namespace=_
-  ##
-  error=_['error']
-  if error.type==ZeroDivisionError:
-      return "<p>Can't divide by zero.</p>"
-  else:
-      return """<p>An error occurred.</p>
-                <p>Error type: %s</p>
-                <p>Error value: %s</p>""" % (error.type,
-                                             error.value)
-
-Your error handling script can take all kinds of actions, for
-example, it might log the error by sending email.
-
-The 'tal:on-error' statement is not meant for general purpose
-exception handling. For example, you shouldn't validate form
-input with it. You should use a script for that, since scripts
-allow you to do powerful exception handling. The 'tal:on-error'
-statement is for dealing with unusual problems that can occur
-when rendering templates.
-
-Interactions Between TAL Statements
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When there is only one TAL statement per element, the order in
-which they are executed is simple. Starting with the root
-element, each element's statements are executed, then each of
-its child elements are visited, in order, and their statements
-are executed, and so on.
-
-However, it's possible to have more than one TAL statement on
-the same element. Any combination of statements may appear on
-the same element, except that the 'tal:content' and
-'tal:replace' statements may not appear together.
-
-When an element has multiple statements, they are executed in
-this order:
-
-1. define
-
-2. condition
-
-3. repeat
-
-4. content or replace
-
-5. attributes
-
-6. omit-tag
-
-Since the 'tal:on-error' statement is only invoked when an error
-occurs, it does not appear in the list.
-
-The reasoning behind this ordering goes like this: you often
-want to set up variables for use in other statements, so define
-comes first. The very next thing to do is decide whether this
-element will be included at all, so condition is next; since the
-condition may depend on variables you just set, it comes after
-define. It is valuable to be able to replace various parts of an
-element with different values on each iteration of a repeat, so
-repeat comes before content, replace and attributes. Content and
-replace can't both be used on the same element so they occur at
-the same place. Omit-tag comes last since no other statements are
-likely to depend on it and since it should come after define and
-repeat.
-
-Here's an example element that includes several TAL 
-statements::
-
-  <p tal:define="x /root/a/long/path/x | nothing"
-     tal:condition="x"
-     tal:content="x/txt"
-     tal:attributes="class x/class">Ex Text</p>
-
-Notice how the 'tal:define' statement is executed first, and the
-other statements rely on its results.
-
-There are three limits you should be aware of when combining TAL
-statements on elements:
-
-1. Only one of each kind of statement can be used on a single
-   tag.  Since HTML does not allow multiple attributes with the
-   same name. For example, you can't have two 'tal:define' on the
-   same tag.
-
-2. Both of 'tal:content' and 'tal:replace' cannot be used on
-   the same tag, since their functions conflict.
-
-3. The order in which you write TAL attributes on a tag does
-   not affect the order in which they execute.  No matter how
-   you arrange them, the TAL statements on a tag always execute
-   in the fixed order described earlier.
-
-If you want to override the ordering of TAL statements, you must
-do so by enclosing the element in another element and placing
-some of the statements on this new element. For example suppose
-you want to loop over a series of items but skip some. Here's an
-attempt to write a template that loops over the numbers zero to
-nine and skips three::
-
-  <!-- broken template -->
-  <ul>
-    <li tal:repeat="n python:range(10)"
-        tal:condition="python:n != 3"
-        tal:content="n"> 
-      1
-    </li>
-  </ul>
-
-This template doesn't work due to TAL statement execution order.
-Despite the order in which they are written, the condition is
-always tested before the repeat is executed. This results in a
-situation in which the 'n' variable is not defined until after
-it is tested, which ultimately causes an error when you attempt
-to test or otherwise view the template. Here's a way around this
-problem::
-
-  <ul>
-    <div tal:repeat="n python:range(10)"
-         tal:omit-tag="">
-      <li tal:condition="python:n != 3"
-          tal:content="n"> 
-        1
-      </li>
-    </div>
-  </ul>
-
-This template solves the problem by defining the 'n' variable on
-an enclosing 'div' element. Notice that the 'div' tag will not
-appear in the output due to its 'tal:omit-tag' statement.
-
-Although 'span' and 'div' are natural choices for this in HTML,
-there is, in general, no equivalent natural element in XML.  In
-this case, you can use TAL's namespace in a new way: while TAL
-does not define any tags, it doesn't prohibit any either.  You
-can make up any tag name you like within the TAL namespace, and
-use it to make an element, like so::
-
-  <tal:series define="items context/getItems">
-    <tal:items repeat="item items">
-    <tal:parts repeat="part item">
-      <p tal:content="part">Part</p>
-    </tal:parts>
-    </tal:items>
-    <p tal:condition="not:items">No parts!</p>
-  </tal:series>
-
-The 'tal:series', 'tal:items', and 'tal:parts' tags in this
-example should be acceptable to tools that handle XML namespaces
-properly, and to many HTML tools.  This method has two
-additional advantages over a 'div'.  First, TAL tags are omitted
-just like TAL attributes, so no 'tal:omit-tag' is necessary.
-Second, TAL attributes in these tags don't require their
-own 'tal:' prefix, since they inherit the namespace of the tag.
-The METAL namespace can be used in exactly the same fashion.
-
-Form Processing
-~~~~~~~~~~~~~~~
-
-With Zope Page Templates you can use the form/action/response pattern. The form
-and response should be Page Templates and the action should be a script. The
-form template gathers the input and calls the action script. The action script
-should process the input and return a response template.
-
-For example here's a part of a form template::
-
-  ...
-  <form action="action">
-    <input type="text" name="name">
-    <input type="text" name="age:int">
-    <input type="submit">
-  </form>
-  ...
-
-This form could be processed by this script::
-
-  ## Script (Python) "action"
-  ##parameters=name, age
-  ##
-  container.addPerson(name, age)
-  return container.responseTemplate()
-
-This script calls a method to process the input and then
-returns another template, the response. You can render a Page
-Template from Python by calling it. The response template
-typically contains an acknowledgment that the form has been
-correctly processed.
-
-The action script can do all kinds of things. It can validate
-input, handle errors, send email, or whatever it needs to do to
-"get the job done".  Here's a sketch of how to validate input
-with a script::
-
-  ## Script (Python) "action"
-  ##
-  if not context.validateData(request):
-      # if there's a problem return the form page template
-      # along with an error message
-      return context.formTemplate(error_message='Invalid data')
-
-  # otherwise return the thanks page
-  return context.responseTemplate()
-
-This script validates the form input and returns the form
-template with an error message if there's a problem. The
-Script's 'context' variable is equivalent to 'context' in
-TALES. You can pass Page Templates extra information with
-keyword arguments. The keyword arguments are available to the
-template via the 'options' built-in variable. So the form
-template in this example might include a section like this::
-
-  <span tal:condition="options/error_message | nothing">
-  Error: <b tal:content="options/error_message">
-    Error message goes here.
-  </b></span>
-
-This example shows how you can display an error message that is
-passed to the template via keyword arguments. Notice the use of
-'| nothing' to handle the case where no 'error_message' argument
-has been passed to the template.
-
-Depending on your application you may choose to redirect the
-user to a response Page Template instead of returning it
-directly. This results in twice as much network activity, but
-might be useful because it changes the URL displayed in the
-user's browser to the URL of the Page Template, rather than that
-of the action script.
-
-If you need to set up a quick-and-dirty form, you can always
-create a version of the form-action pair using Page Templates
-alone. You should only do this when you don't care about error
-handling and when the response will always be the same, no
-matter what the user submits. You can use one of any number of
-hacks to call an input processing method without inserting its
-results. For example::
-
-  <span tal:define="unused context/processInputs" 
-        tal:omit-tag=""/>
-
-This sample calls the 'processInputs' method and assigns the
-result to the 'unused' variable.
-
-Expressions
------------
-
-You've already encountered Page Template expressions. Expressions
-provide values to template statements. For example, in the TAL
-statement '<td tal:content="request/form/age">Age</td>', the
-expression of the statement is 'request/form/age'.
-'request/form/age' is an example of a *path expression*.  Path
-expressions describe objects by giving them paths such as
-'request/form/age', or 'user/getUserName'. Expressions only work
-in the context of a TAL statement; they do not work in "normal"
-HTML inserted in your page templates.  In this section you'll
-learn about all the different types of expressions, and variables.
-
-Built-in Page Template Variables
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Variables are names that you can use in expressions. You have
-already seen some examples of the built-in variables such as
-'template', 'user', 'repeat', and 'request'.  Here is the
-complete list of the other built-in variables and their uses.
-Note that these variables are different than the built-in
-variables that you would use in a Script (Python), they are only
-effective for Page Templates:
-
-'nothing'
-  A false value, similar to a blank string, that you
-  can use in 'tal:replace' or 'tal:content' to erase an element or
-  its contents.  If you set an attribute to 'nothing', the
-  attribute is removed from the tag (or not inserted).  A blank
-  string, on the other hand, would insert the tag with an empty
-  value, as in 'alt=""'.
-
-'default'
-  A special value that doesn't change anything when
-  used in 'tal:replace', 'tal:content', or 'tal:attributes'.  It
-  leaves the template text in place.
-
-'options'
-  The keyword arguments, if any, that were passed to
-  the template. When a template is rendered from the web, no
-  options are present. Options are only available when a template
-  is called from Python or by similarly complex means.  For
-  example, when the template 't' is called by the Python expression
-  't(foo=1)', the path 'options/foo' equals '1'.
-
-'attrs'
-  A dictionary of attributes of the current tag in the
-  template.  The keys are the attributes names, and the values are
-  the original values of the attributes in the template. This
-  variable is rarely needed.
-
-'root'
-  The root Zope object.  Use this to get Zope objects
-  from fixed locations, no matter where your template is placed or
-  called.
-
-'context'
-  The object on which the template is being called.
-  This is often the same as the *container*, but can be different
-  if you are using acquisition.  Use this to get Zope objects that
-  you expect to find in different places depending on how the
-  template is called.
-
-'container'
-  The container (usually a Folder) in which the
-  template is kept.  Use this to get Zope objects from locations
-  relative to the template's permanent home. The 'container' and
-  'context' variables refer to the same object when a template is
-  called from its normal location. However, when a template is
-  applied to another object (for example, a ZSQL Method) the
-  'container' and 'context' will not refer to the same object.
-
-'modules'
-  The collection of Python modules available to
-  templates.  See the section on writing Python expressions.
-
-You'll find examples of how to use these variables throughout
-this chapter.
-
-String Expressions
-~~~~~~~~~~~~~~~~~~
-
-String expressions allow you to easily mix path expressions with
-text.  All of the text after the leading 'string:' is taken and
-searched for path expressions.  Each path expression must be
-preceded by a dollar sign ('$').  Here are some examples::
-
-  "string:Just text. There's no path here."
-  "string:copyright $year by Fred Flintstone."
-
-If the path expression has more than one part (if it contains a
-slash), or needs to be separated from the text that follows it,
-it must be surrounded by braces ('{}'). For example::
-
-  "string:Three ${vegetable}s, please."
-  "string:Your name is ${user/getUserName}!"
-
-Notice how in the example above, you need to surround the
-'vegetable' path with braces so that Zope doesn't mistake it for
-'vegetables'.
-
-Since the text is inside of an attribute value, you can only
-include a double quote by using the entity syntax '&quot;'.
-Since dollar signs are used to signal path expressions, a
-literal dollar sign must be written as two dollar signs
-('$$'). For example::
-
-  "string:Please pay $$$dollars_owed"
-  "string:She said, &quot;Hello world.&quot;"
-
-Some complex string formatting operations (such as search and
-replace or changing capitalization) can't easily be done with
-string expressions. For these cases, you should use Python
-expressions or Scripts.
-
-Path Expressions
-~~~~~~~~~~~~~~~~
-
-Path expressions refer to objects with a path that resembles a
-URL path. A path describes a traversal from object to
-object. All paths begin with a known object (such as a built-in
-variable, a repeat variable, or a user defined variable) and
-depart from there to the desired object. Here are some example
-paths expressions::
-
-  template/title
-  container/files/objectValues
-  user/getUserName
-  container/master.html/macros/header
-  request/form/address
-  root/standard_look_and_feel.html
-
-With path expressions you can traverse from an object to its
-sub-objects including properties and methods. You can also use
-acquisition in path expressions. See the section entitled
-"Calling Scripts from the Web" in the chapter entitled `Advanced
-Zope Scripting <ScriptingZope.html>`_ for more information on
-acquisition and path traversal.
-
-Zope restricts object traversal in path expressions in the same
-way that it restricts object access via URLs. You must have
-adequate permissions to access an object in order to refer to it
-with a path expression. See the chapter entitled `Users and
-Security <Security.html>`_ for more information about object access
-controls.
-
-Alternate Paths
-%%%%%%%%%%%%%%%
-
-The path 'template/title' is guaranteed to exist every time
-the template is used, although it may be a blank string.  Some
-paths, such as 'request/form/x', may not exist during some
-renderings of the template.  This normally causes an error
-when Zope evaluates the path expression.
-
-When a path doesn't exist, you may have a fall-back path or
-value that you would like to use instead.  For instance, if
-'request/form/x' doesn't exist, you might want to use 'context/x'
-instead.  You can do this by listing the paths in order of
-preference, separated by vertical bar characters ('|')::
-
-  <h4 tal:content="request/form/x | context/x">Header</h4>
-
-Two variables that are very useful as the last path in a list
-of alternates are 'nothing' and 'default'.  For example,
-'default' tells 'tal:content' to leave the dummy
-content. Different TAL statements interpret 'default' and
-'nothing' differently. See `Appendix C: Zope Page Templates
-Reference`_ for more information.
-
-You can also use a non-path expression as the final part in an
-alternate-path expression. For example::
-
-  <p tal:content="request/form/age|python:18">age</p>
-
-In this example, if the 'request/form/age' path doesn't exist,
-then the value is the number 18. This form allows you to
-specify default values to use which can't be expressed as
-paths. Note, you can only use a non-path expression as the
-last alternative.
-
-You can also test the existence of a path directly with the
-*exists* expression type prefix. See the section "Exists
-Expressions" below for more information on exists expressions.
-
-Not Expressions
-~~~~~~~~~~~~~~~
-
-`Not` expressions let you negate the value of other
-expressions. For example::
-
-  <p tal:condition="not:context/objectIds">
-    There are no contained objects.
-  </p>
-
-Not expressions return true when the expression they are applied
-to is false, and vice versa. In Zope, zero, empty strings, empty
-sequences, nothing, and None are considered false, while
-everything else is true.  Non-existent paths are neither true
-nor false, and applying a 'not:' to such a path will fail.
-
-There isn't much reason to use not expressions with Python
-expressions since you can use the Python 'not' keyword instead.
-
-Nocall Expressions
-~~~~~~~~~~~~~~~~~~
-
-An ordinary path expression tries to render the object
-that it fetches.  This means that if the object is a function,
-Script, Method, or some other kind of executable thing, then
-the expression will evaluate to the result of calling the object.
-This is usually what you want, but not always.  For example,
-if you want to put a page template into a variable so that
-you can refer to its properties, you can't use a normal path
-expression because it will render the template into a string.
-
-If you put the 'nocall:' expression type prefix in front of a
-path, it prevents the rendering and simply gives you the
-object.  For example::
-
-  <span tal:define="page nocall:context/aPage"
-        tal:content="string:${page/getId}: ${page/title}">
-  Id: Title</span>
-
-This expression type is also valuable when you want to define
-a variable to hold a function or class from a module, for use
-in a Python expression.
-
-Nocall expressions can also be used on functions, rather than
-objects::
-
-  <p tal:define="join nocall:modules/string/join">
-
-This expression defines the 'join' variable as a function
-('string.join'), rather than the result of calling a function.
-
-Exists Expressions
-~~~~~~~~~~~~~~~~~~
-
-An exists expression is true if its path exists, and otherwise
-is false.  For example here's one way to display an error
-message only if it is passed in the request::
-
-  <h4 tal:define="err request/form/errmsg | nothing"
-      tal:condition="err" 
-      tal:content="err">Error!</h4>
-
-You can do the same thing more easily with an exists
-expression::
-
-  <h4 tal:condition="exists:request/form/errmsg"
-      tal:content="request/form/errmsg">Error!</h4>
-
-You can combine exists expressions with not expressions, for
-example::
-
-  <p tal:condition="not:exists:request/form/number">Please enter
-  a number between 0 and 5</p>
-
-Note that in this example you can't use the expression,
-"not:request/form/number", since that expression will be true if
-the 'number' variable exists and is zero.
-
-Python Expressions
-~~~~~~~~~~~~~~~~~~
-
-The Python programming language is a simple and expressive one.
-If you have never encountered it before, you should read one of
-the excellent tutorials or introductions available at the
-`Python website <http://www.python.org>`_.
-
-A Page Template Python expression can contain anything that the
-Python language considers an expression.  You can't use
-statements such as 'if' and 'while'. In addition, Zope imposes
-some security restrictions to keep you from accessing protected
-information, changing secured data, and creating problems such
-as infinite loops. See the chapter entitled `Advanced Zope
-Scripting <ScriptingZope.html>`_ for more information on Python
-security restrictions.
-
-Comparisons
-%%%%%%%%%%%
-
-One place where Python expressions are practically necessary
-is in 'tal:condition' statements.  You usually want to compare
-two strings or numbers, and there is no support in TAL to do
-this without Python expressions.  In Python expressions, you
-can use the comparison operators '<' (less than), '>' (greater
-than), '==' (equal to), and '!=' (not equal to).  You can also
-use the boolean operators 'and', 'not', and 'or'.  For
-example::
-
-  <p tal:repeat="widget widgets">
-    <span tal:condition="python:widget.type == 'gear'">
-    Gear #<span tal:replace="repeat/widget/number>1</span>:
-    <span tal:replace="widget/name">Name</span>
-    </span>
-  </p>
-
-This example loops over a collection of objects, printing
-information about widgets which are of type 'gear'.
-
-Sometimes you want to choose different values inside a single
-statement based on one or more conditions.  You can do this
-with the and and or operators, like this::
-
-  You <span tal:define="name user/getUserName"
-       tal:replace="python:name=='Anonymous User' and
-                           'need to log in' or default">
-        are logged in as
-        <span tal:replace="name">Name</span>
-      </span>
-
-If the user is 'Anonymous', then the 'span' element is
-replaced with the text 'need to log in'.  Otherwise, the
-default content is used, which is in this case 'are logged in
-as ...'.
-
-This operator combinaion works like an if/then/else statement.
-Here's another example of how you can use this pattern::
-
-  <tr tal:define="oddrow repeat/item/odd"
-      tal:attributes="class python:oddrow and 'oddclass' or 'evenclass'">
-
-This assigns 'oddclass' and 'evenclass' class attributes to
-alternate rows of the table, allowing them to be styled
-differently in HTML output, for example.
-
-Without this pattern you could also write two 'tr'
-elements with different conditions, one for even rows,
-and the other for odd rows.
-
-Using other Expression Types
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-You can use other expression types inside of a Python
-expression.  Each expression type has a corresponding function
-with the same name, including: 'path()', 'string()',
-'exists()', and 'nocall()'.  This allows you to write
-expressions such as::
-
-  "python:path('context/%s/thing' % foldername)"
-  "python:path(string('context/$foldername/thing'))"
-  "python:path('request/form/x') or default"
-
-The final example has a slightly different meaning than the
-path expression, "request/form/x | default", since it will use
-the default text if "request/form/x" doesn't exists *or* if it
-is false.
-
-Getting at Zope Objects
-%%%%%%%%%%%%%%%%%%%%%%%
-
-Much of the power of Zope involves tying together specialized
-objects.  Your Page Templates can use Scripts, SQL Methods,
-Catalogs, and custom content objects.  In order to use these
-objects you have to know how to get access to them within Page
-Templates.
-
-Object properties are usually attributes, so you can get a
-template's title with the expression "template.title". Most
-Zope objects support acquisition, which allows you to get
-attributes from "parent" objects.  This means that the Python
-expression "context.Control_Panel" will acquire the Control Panel
-object from the root Folder.  Object methods are attributes,
-as in "context.objectIds" and "request.set".  Objects contained
-in a Folder can be accessed as attributes of the Folder, but
-since they often have Ids that are not valid Python
-identifiers, you can't use the normal notation.  For example,
-you cannot access the 'penguin.gif' object with the following
-Python expression::
-
-  "python:context.penguin.gif"
-
-Instead, you must write::
-
-  "python:getattr(context, 'penguin.gif')"
-
-since Python doesn't support attribute names with periods.
-
-Some objects, such as 'request', 'modules', and Zope Folders
-support Python item access, for example::
-
-  request['URL']
-  modules['math']
-  context['thing']
-
-When you use item access on a Folder, it doesn't try to
-acquire the name, so it will only succeed if there is actually
-an object with that Id contained in the Folder.
-
-As shown in previous chapters, path expressions allow you to
-ignore details of how you get from one object to the next.
-Zope tries attribute access, then item access.  You can
-write::
-
-  "context/images/penguin.gif"
-
-instead of::
-
-  "python:getattr(context.images, 'penguin.gif')"
-
-and::
-
-  "request/form/x" 
-
-instead of::
-
-  "python:request.form['x']"
-
-The trade-off is that path expressions don't allow you to
-specify those details.  For instance, if you have a form
-variable named "get", you must write::
-
-  "python:request.form['get']"
-
-since this path expression::
-
-  "request/form/get" 
-
-will evaluate to the "get" *method* of the form dictionary.
-
-If you prefer you can use path expressions inside Python
-expressions using the 'path()' function, as described above.
-
-Using Scripts
-%%%%%%%%%%%%%
-
-Script objects are often used to encapsulate business logic
-and complex data manipulation.  Any time that you find
-yourself writing lots of TAL statements with complicated
-expressions in them, you should consider whether you could do
-the work better in a Script. If you have trouble understanding your
-template statements and expressions, then it's better to
-simplify your Page Template and use Scripts for the complex
-stuff.
-
-Each Script has a list of parameters that it expects to be
-given when it is called.  If this list is empty, then you can
-use the Script by writing a path expression.  Otherwise, you
-will need to use a Python expression in order to supply the
-argument, like this::
-
-  "python:context.myscript(1, 2)"
-  "python:context.myscript('arg', foo=request.form['x'])"
-
-If you want to return more than one item of data from a Script
-to a Page Template, it is a good idea to return it in a
-dictionary.  That way, you can define a variable to hold all
-the data, and use path expressions to refer to each item.  For
-example, suppose the 'getPerson' script returns a dictionary
-with 'name' and 'age' keys::
-
-  <span tal:define="person context/getPerson"
-        tal:replace="string:${person/name} is ${person/age}">
-  Name is 30</span> years old.
-
-Of course, it's fine to return Zope objects and Python lists
-as well.
-
-Python Modules
-%%%%%%%%%%%%%%
-
-The Python language comes with a large number of modules,
-which provide a wide variety of capabilities to Python
-programs.  Each module is a collection of Python functions,
-data, and classes related to a single purpose, such as
-mathematical calculations or regular expressions.
-
-Several modules, including "math" and "string", are available
-in Python expressions by default.  For example, you can get
-the value of pi from the math module by writing
-"python:math.pi".  To access it from a path expression,
-however, you need to use the 'modules' variable,
-"modules/math/pi".
-
-The "string" module is hidden in Python expressions by the
-"string" expression type function, so you need to access it
-through the 'modules' variable.  You can do this directly in
-an expression in which you use it, or define a variable
-for it, like this::
-
-  tal:define="mstring modules/string"
-  tal:replace="python:mstring.join(slist, ':')"
-
-In practice you'll rarely need to do this since you can use
-string methods most of the time rather than having to rely on
-functions in the string module.
-
-Modules can be grouped into packages, which are simply a way
-of organizing and naming related modules.  For instance,
-Zope's Python-based Scripts are provided by a collection of
-modules in the "PythonScripts" subpackage of the Zope
-"Products" namespace package.  In particular, the "standard" module in
-this package provides a number of useful formatting functions. The full name
-of this module is "Products.PythonScripts.standard", so you could
-get access to it using either of the following statements::
-
-  tal:define="global pps modules/Products.PythonScripts.standard"
-  tal:define="global pps python:modules['Products.PythonScripts.standard']"
-
-Many Python modules cannot be accessed from Page Templates
-or Scripts unless you add Zope security assertions to
-them.  See the `Zope Developer's Guide's security
-chapter <http://www.zope.org/Documentation/Books/ZDG/current/Security.stx>`_
-for more information on making more Python modules available
-to your templates and scripts by using "ModuleSecurityInfo".
-
-Caching Templates
------------------
-
-While rendering Page Templates normally is quite fast, sometimes
-it's not fast enough. For frequently accessed pages, or pages that
-take a long time to render, you may want to trade some dynamic
-behavior for speed. Caching lets you do this. For more information
-on caching see the "Cache Manager" section of the chapter entitled
-`Zope Services <ZopeServices.html>`_.
-
-You can cache Page Templates using a cache manager in the same way
-that you cache other objects. To cache a Page Template, you must
-associate it with a cache manager. You can either do this by going
-to the *Cache* view of your Page Template and selecting the cache
-manager (there must be one in the acquisition path of the template
-for the *Cache* view to appear), or by going to the *Associate*
-view of your cache manager and locating your Page Template.
-
-Here's an example of how to cache a Page Template. First create a
-Python-based script name 'long.py' with these contents::
-
-  ## Script (Python) "long.py"
-  ##
-  for i in range(250):
-    for j in range(250):
-      for k in range(250):
-        pass
-  return 'Done'
-
-The purpose of this script is to take up a noticeable amount of
-execution time. Now create a Page Template that uses this script,
-for example::
-
-  <html>
-    <body>
-      <p tal:content="context/long.py">results</p>
-    </body>
-  </html>
-
-Now view this page. Notice how it takes a while to render. Now
-let's radically improve its rendering time with caching.  Create a
-Ram Cache Manager if you don't already have one. Make sure to
-create it within the same folder as your Page Template, or in a
-higher level. Now visit the *Cache* view of your Page
-Template. Choose the Ram Cache Manager you just created and click
-*Save Changes*.  Click the *Cache Settings* link to see how your
-Ram Cache Manager is configured.  By default, your cache stores
-objects for one hour (3600 seconds). You may want to adjust this
-number depending on your application. Now return to your Page
-Template and view it again. It should take a while for it to
-render. Now reload the page, and watch it render immediately. You
-can reload the page again and again, and it will always render
-immediately since the page is now cached.
-
-If you change your Page Template, then it will be removed from the
-cache. So the next time you view it, it will take a while to
-render. But after that it will render quickly since it will be
-cached again.
-
-Caching is a simple but very powerful technique for improving
-performance. You don't have to be a wizard to use caching, and it
-can provide great speed-ups. It's well worth your time to use
-caching for performance-critical applications.
-
-For more information on caching in the context of Zope, see the
-chapter entitled `Zope Services <ZopeServices.html>`_.
-
-Page Template Utilities
------------------------
-
-Zope Page Templates are powerful but simple.
-They don't give you a lot of convenience features for things
-like batching, drawing trees, sorting, etc. The creators of Page
-Templates wanted to keep them simple. To address these
-needs, Zope comes with utilities designed to enhance Page
-Templates.
-
-Batching Large Sets of Information
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When a user queries a database and gets hundreds of results, it's
-often better to show them several pages with only twenty results
-per page, rather than putting all the results on one
-page. Breaking up large lists into smaller lists is called
-*batching*.
-
-Page Templates support batching by using a special 'Batch'
-object that comes from the 'ZTUtils' utility module.  See
-`Appendix B: API Reference`_, for more information
-on the 'ZTUtils' Python module.
-
-Here's a simple example, showing how to create a 'Batch'
-object::
-
-  <ul tal:define="lots python:range(100);
-                  batch python:modules['ZTUtils'].Batch(lots, 
-                                                        size=10,
-                                                        start=0)">
-    <li tal:repeat="num batch"
-        tal:content="num">0
-    </li>
-  </ul>
-
-This example renders a list with 10 items (in this case, the
-numbers 0 through 9). The 'Batch' object chops a long list up
-into groups or batches. In this case it broke a one hundred item
-list up into batches of ten items.
-
-You can display a different batch of ten items by passing a
-different start number::
-
-  <ul tal:define="lots python:range(100);
-                  batch python:modules['ZTUtils'].Batch(lots, 
-                                                        size=10,
-                                                        start=13)">
-
-This batch starts with the fourteenth item and ends with the
-twenty third item. In other words, it displays the numbers 13
-through 22. It's important to notice that the batch 'start'
-argument is the *index* of the first item. Indexes count from
-zero, rather than from one. So index 13 points to the fourteenth
-item in the sequence. Python uses indexes to refer to list
-items. 
-
-Normally when you use batches you'll want to include navigation
-elements on the page to allow users to go from batch to batch.
-Here's a full-blow batching example that shows how to navigate
-between batches::
-
-  <html>
-    <head>
-      <title tal:content="template/title">The title</title>
-    </head>
-    <body tal:define="employees context/getEmployees;
-           start python:int(path('request/start | nothing') or 0);
-           batch python:modules['ZTUtils'].Batch(employees, 
-                                                 size=3, 
-                                                 start=start);
-           previous python:batch.previous;
-           next python:batch.next">
-
-    <p>
-      <a tal:condition="previous"
-         tal:attributes="href string:${request/URL0}?start:int=${previous/first}"
-         href="previous_url">previous</a>
-      <a tal:condition="next"
-         tal:attributes="href string:${request/URL0}?start:int=${next/first}"
-         href="next_url">next</a>
-    </p>
-
-    <ul tal:repeat="employee batch" >
-      <li>
-        <span tal:replace="employee/name">Bob Jones</span>
-        makes $<span tal:replace="employee/salary">100,000</span>
-        a year.
-      </li>
-    </ul>
-
-    </body>
-  </html>
-
-Define a Script (Python) with the name getEmployees in the same
-folder with the following body (no parameters are necessary)::
-
-  return [  {'name': 'Chris McDonough', 'salary':'5'},
-            {'name': 'Guido van Rossum', 'salary': '10'},
-            {'name': 'Casey Duncan', 'salary':'20' },
-            {'name': 'Andrew Sawyers', 'salary':'30' },
-            {'name': 'Evan Simpson', 'salary':'35' }, 
-            {'name': 'Stephanie Hand', 'salary':'40' }, ]
-
-This example iterates over batches of results from the
-'getEmployees' method. It draws a *previous* and a *next* link
-as necessary to allow you to page through all the results a
-batch at a time.  The batch size in this case is 3.
-
-Take a look at the 'tal:define' statement on the 'body'
-element. It defines a bunch of batching variables. The
-'employees' variable is a list of employee objects returned by
-the 'getEmployees' Script.  It is not very big now, but it could
-grow fairly large (especially if it were a call into a SQL
-Method of *real* employees). The second variable, 'start', is
-either set to the value of 'request/start' or to zero if there
-is no 'start' variable in the request.  The 'start' variable
-keeps track of where you are in the list of employees. The
-'batch' variable is a batch of ten items from the lists of
-employees. The batch starts at the location specified by the
-'start' variable. The 'previous' and 'next' variables refer to
-the previous and next batches (if any). Since all these
-variables are defined on the 'body' element, they are available
-to all elements inside the body.
-
-Next let's look at the navigation links. They create hyper links
-to browse previous and next batches. The 'tal:condition'
-statement first tests to see if there is a previous and next
-batch. If there is a previous or next batch, then the link is
-rendered, otherwise there is no link. The 'tal:attributes'
-statement creates a link to the previous and next batches. The
-link is simply the URL or the current page ('request/URL0')
-along with a query string indicating the start index of the
-batch. For example, if the current batch starts with index 10,
-then the previous batch will start with an index of 0. The
-'first' variable of a batch gives its starting index, so in this
-case, 'previous.start' would be 0.
-
-It's not important to fully understand the workings of this
-example. Simply copy it, or use a batching example created by
-the *Z Search Interface*. Later when you want to do more complex
-batching you can experiment by changing the example code. Don't
-forget to consult `Appendix B: API Reference`_ for
-more information on the 'ZTUtils' module and 'Batch' objects.
-
-Miscellaneous Utilities
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Zope provides a couple Python modules which may come in handy
-when using Page Templates. The 'string', 'math', and 'random'
-modules can be used in Python expressions for string formatting,
-math function, and pseudo-random number generation. These same
-modules are available in Python-based scripts.
-
-The 'Products.PythonScripts.standard' module is designed to
-provide utilities to Python-based scripts, but it's also useful
-for Page Templates. It includes various string and number
-formatting functions.
-
-As mentioned earlier in the chapter, the 'sequence' module
-provides a handy 'sort' function.
-
-Finally the 'AccessControl' module includes a function and a
-class which you'll need if you want to test access and to get
-the authenticated user.
-
-See `Appendix B: API Reference`_ for more
-information on these utilities.
-
-Conclusion
-----------
-
-This chapter covers some useful and some obscure nooks and
-crannies of Page Templates, and after reading it you may feel a
-bit overwhelmed. Don't worry, you don't need to know everything
-in this chapter to effectively use Page Templates. You should
-understand the different path types and macros, but you can come
-back to the rest of the material when you need it. The advanced
-features that you've learned about in this chapter are there for
-you if and when you need them.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/AppendixA.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/AppendixA.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/AppendixA.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,1655 +0,0 @@
-##########################
-Appendix A: DTML Reference
-##########################
-
-DTML is the *Document Template Markup Language*, a handy presentation and
-templating language that comes with Zope. This Appendix is a reference to all
-of DTMLs markup tags and how they work.
-
-call: Call a method
-===================
-
-The 'call' tag lets you call a method without inserting the results into the
-DTML output.
-
-Syntax
-------
-
-'call' tag syntax::
-
-  <dtml-call Variable|expr="Expression">
-
-If the call tag uses a variable, the methods arguments are passed automatically
-by DTML just as with the 'var' tag. If the method is specified in a expression,
-then you must pass the arguments yourself.
-
-Examples
---------
-
-Calling by variable name::
-
-  <dtml-call UpdateInfo>
-
-This calls the 'UpdateInfo' object automatically passing arguments.
-
-Calling by expression::
-
-  <dtml-call expr="RESPONSE.setHeader('content-type', 'text/plain')">
-
-See Also
---------
-
-- var tag
-
-
-comment: Comments DTML
-======================
-
-The comment tag lets you document your DTML with comments. You can also use it
-to temporarily disable DTML tags by commenting them out.
-
-Syntax
-------
-
-'comment' tag syntax::
-
-  <dtml-comment>
-  </dtml-comment>
-
-The 'comment' tag is a block tag. The contents of the block are not executed,
-nor are they inserted into the DTML output.
-
-Examples
---------
-
-Documenting DTML::
-
-  <dtml-comment>
-    This content is not executed and does not appear in the output.
-  </dtml-comment>
-
-Commenting out DTML::
-
-  <dtml-comment>
-    This DTML is disabled and will not be executed.
-    <dtml-call someMethod>
-  </dtml-comment>
-
-Zope still validates the DTML inside the comment block and will not save any
-comments that are not valid DTML. It is also not possible to comment in a way
-that breaks code flow, for example you cannot inproperly nest a comment and a
-dtml-in.
-
-
-functions: DTML Functions
-=========================
-
-DTML utility functions provide some Python built-in functions and some
-DTML-specific functions.
-
-Functions
----------
-
-abs(number)
-  Return the absolute value of a number. The argument may be a plain or long
-  integer or a floating point number. If the argument is a complex number, its
-  magnitude is returned.
-
-chr(integer)
-  Return a string of one character whose ASCII code is the integer, e.g.,
-  'chr(97)' returns the string 'a'. This is the inverse of ord(). The argument
-  must be in the range 0 to 255, inclusive; 'ValueError' will be raised if the
-  integer is outside that range.
-
-DateTime()
-  Returns a Zope 'DateTime' object given constructor arguments. See the
-  DateTime API reference for more information on constructor arguments.
-
-divmod(number, number)
-  Take two numbers as arguments and return a pair of numbers consisting of
-  their quotient and remainder when using long division. With mixed operand
-  types, the rules for binary arithmetic operators apply. For plain and long
-  integers, the result is the same as '(a / b, a % b)'. For floating point
-  numbers the result is '(q, a % b)', where *q* is usually 'math.floor(a / b)'
-  but may be 1 less than that. In any case 'q * b + a % b' is very close to
-  *a*, if 'a % b' is non-zero it has the same sign as *b*, and '0 <= abs(a % b)
-  < abs(b)'.
-
-float(number)
-  Convert a string or a number to floating point. If the argument is a string,
-  it must contain a possibly signed decimal or floating point number, possibly
-  embedded in whitespace; this behaves identical to 'string.atof(number)'.
-  Otherwise, the argument may be a plain or long integer or a floating point
-  number, and a floating point number with the same value (within Python's
-  floating point precision) is returned.
-
-getattr(object, string)
-  Return the value of the named attributed of object. name must be a string. If
-  the string is the name of one of the object's attributes, the result is the
-  value of that attribute. For example, 'getattr(x, "foobar")' is equivalent to
-  'x.foobar'. If the named attribute does not exist, default is returned if
-  provided, otherwise 'AttributeError' is raised.
-
-getitem(variable, render=0)
-  Returns the value of a DTML variable. If 'render' is true, the variable is
-  rendered. See the 'render' function.
-
-hasattr(object, string)
-  The arguments are an object and a string. The result is 1 if the string is
-  the name of one of the object's attributes, 0 if not. (This is implemented by
-  calling getattr(object, name) and seeing whether it raises an exception or
-  not.)
-
-hash(object)
-  Return the hash value of the object (if it has one). Hash values are
-  integers. They are used to quickly compare dictionary keys during a
-  dictionary lookup. Numeric values that compare equal have the same hash value
-  (even if they are of different types, e.g. 1 and 1.0).
-
-has_key(variable)
-  Returns true if the DTML namespace contains the named variable.
-
-hex(integer)
-  Convert an integer number (of any size) to a hexadecimal string. The result
-  is a valid Python expression. Note: this always yields an unsigned literal,
-  e.g. on a 32-bit machine, 'hex(-1)' yields '0xffffffff'. When evaluated on a
-  machine with the same word size, this literal is evaluated as -1; at a
-  different word size, it may turn up as a large positive number or raise an
-  'OverflowError' exception.
-
-int(number)
-  Convert a string or number to a plain integer. If the argument is a string,
-  it must contain a possibly signed decimal number representable as a Python
-  integer, possibly embedded in whitespace; this behaves identical to
-  'string.atoi(number[, radix]'). The 'radix' parameter gives the base for the
-  conversion and may be any integer in the range 2 to 36. If 'radix' is
-  specified and the number is not a string, 'TypeError' is raised. Otherwise,
-  the argument may be a plain or long integer or a floating point number.
-  Conversion of floating point numbers to integers is defined by the C
-  semantics; normally the conversion truncates towards zero.
-
-len(sequence)
-  Return the length (the number of items) of an object. The argument may be a
-  sequence (string, tuple or list) or a mapping (dictionary).
-
-max(s)
-  With a single argument s, return the largest item of a non-empty sequence
-  (e.g., a string, tuple or list). With more than one argument, return the
-  largest of the arguments.
-
-min(s)
-  With a single argument s, return the smallest item of a non-empty sequence
-  (e.g., a string, tuple or list). With more than one argument, return the
-  smallest of the arguments.
-
-namespace([name=value]...)
-  Returns a new DTML namespace object. Keyword argument 'name=value' pairs are
-  pushed into the new namespace.
-
-oct(integer)
-  Convert an integer number (of any size) to an octal string. The result is a
-  valid Python expression. Note: this always yields an unsigned literal, e.g.
-  on a 32-bit machine, 'oct(-1)' yields '037777777777'. When evaluated on a
-  machine with the same word size, this literal is evaluated as -1; at a
-  different word size, it may turn up as a large positive number or raise an
-  OverflowError exception.
-
-ord(character)
-  Return the ASCII value of a string of one character. E.g., 'ord("a")' returns
-  the integer 97. This is the inverse of 'chr()'.
-
-pow(x, y [,z])
-  Return *x* to the power *y*; if *z* is present, return *x* to the power *y*,
-  modulo *z* (computed more efficiently than 'pow(x, y) % z'). The arguments
-  must have numeric types. With mixed operand types, the rules for binary
-  arithmetic operators apply. The effective operand type is also the type of
-  the result; if the result is not expressible in this type, the function
-  raises an exception; e.g., 'pow(2, -1)' or 'pow(2, 35000)' is not allowed.
-
-range([start,] stop [,step])
-  This is a versatile function to create lists containing arithmetic
-  progressions. The arguments must be plain integers. If the step argument is
-  omitted, it defaults to 1. If the start argument is omitted, it defaults to
-  0. The full form returns a list of plain integers '[start, start + step,
-  start + 2 * step, ...]'. If step is positive, the last element is the largest
-  'start + i * step' less than *stop*; if *step* is negative, the last element
-  is the largest 'start + i * step' greater than *stop*. *step* must not be
-  zero (or else 'ValueError' is raised).
-
-round(x [,n])
-  Return the floating point value *x* rounded to *n* digits after the decimal
-  point. If n is omitted, it defaults to zero. The result is a floating point
-  number. Values are rounded to the closest multiple of 10 to the power minus
-  n; if two multiples are equally close, rounding is done away from 0 (so e.g.
-  round(0.5) is 1.0 and round(-0.5) is -1.0).
-
-render(object)
-  Render 'object'. For DTML objects this evaluates the DTML code with the
-  current namespace. For other objects, this is equivalent to 'str(object)'.
-
-reorder(s [,with] [,without])
-  Reorder the items in s according to the order given in 'with' and without the
-  items mentioned in 'without'. Items from s not mentioned in with are removed.
-  s, with, and without are all either sequences of strings or sequences of
-  key-value tuples, with ordering done on the keys. This function is useful for
-  constructing ordered select lists.
-
-SecurityCalledByExecutable()
-  Return a true if the current object (e.g. DTML document or method) is being
-  called by an executable (e.g. another DTML document or method, a script or a
-  SQL method).
-
-SecurityCheckPermission(permission, object)
-  Check whether the security context allows the given permission on the given
-  object. For example, 'SecurityCheckPermission("Add Documents, Images, and
-  Files", this())' would return true if the current user was authorized to
-  create documents, images, and files in the current location.
-
-SecurityGetUser()
-  Return the current user object. This is normally the same as the
-  'REQUEST.AUTHENTICATED_USER' object. However, the 'AUTHENTICATED_USER' object
-  is insecure since it can be replaced.
-
-SecurityValidate([object] [,parent] [,name] [,value])
-  Return true if the value is accessible to the current user. 'object' is the
-  object the value was accessed in, 'parent' is the container of the value, and
-  'name' is the named used to access the value (for example, if it was obtained
-  via 'getattr'). You may omit some of the arguments, however it is best to
-  provide all available arguments.
-
-SecurityValidateValue(object)
-  Return true if the object is accessible to the current user. This function is
-  the same as calling 'SecurityValidate(None, None, None, object)'.
-
-str(object)
-  Return a string containing a nicely printable representation of an object.
-  For strings, this returns the string itself.
-
-test(condition, result [,condition, result]... [,default])
-  Takes one or more condition, result pairs and returns the result of the first
-  true condition. Only one result is returned, even if more than one condition
-  is true. If no condition is true and a default is given, the default is
-  returned. If no condition is true and there is no default, None is returned.
-
-unichr(number)
-  Return a unicode string representing the value of number as a unicode
-  character. This is the inverse of ord() for unicode characters.
-
-unicode(string[, encoding[, errors ] ])
-  Decodes string using the codec for encoding. Error handling is done according
-  to errors. The default behavior is to decode UTF-8 in strict mode, meaning
-  that encoding errors raise ValueError.
-
-Attributes
-----------
-
-None
-  The 'None' object is equivalent to the Python built-in object 'None'. This is
-  usually used to represent a Null or false value.
-
-See Also
---------
-
-- `string module <http://docs.python.org/library/string.html>`_
-
-- `random module <http://docs.python.org/library/random.html>`_
-
-- `math module <http://docs.python.org/library/math.html>`_
-
-- `sequence module <http://docs.python.org/library/functions.html>`_
-
-
-if: Tests Conditions
-====================
-
-The 'if' tags allows you to test conditions and to take different actions
-depending on the conditions. The 'if' tag mirrors Python's 'if/elif/else'
-condition testing statements.
-
-Syntax
-------
-
-If tag syntax::
-
-  <dtml-if ConditionVariable|expr="ConditionExpression">
-  [<dtml-elif ConditionVariable|expr="ConditionExpression">]
-   ...
-  [<dtml-else>]
-  </dtml-if>
-
-The 'if' tag is a block tag. The 'if' tag and optional 'elif' tags
-take a condition variable name or a condition expression, but not
-both. If the condition name or expression evaluates to true then
-the 'if' block is executed. True means not zero, an empty string
-or an empty list.  If the condition variable is not found then the
-condition is considered false.
-
-If the initial condition is false, each 'elif' condition is tested
-in turn. If any 'elif' condition is true, its block is
-executed. Finally the optional 'else' block is executed if none of
-the 'if' and 'elif' conditions were true. Only one block will be
-executed.
-
-Examples
---------
-
-Testing for a variable::
-
-  <dtml-if snake>
-    The snake variable is true
-  </dtml-if>
-
-Testing for expression conditions::
-
-  <dtml-if expr="num > 5">
-    num is greater than five
-  <dtml-elif expr="num < 5">
-    num is less than five
-  <dtml-else>
-    num must be five
-  </dtml-if>
-
-See Also
---------
-
-`Python Tutorial If Statements <http://docs.python.org/tutorial/controlflow.html#if-statements>`_
-
-
-in: Loops over sequences
-========================
-
-The 'in' tag gives you powerful controls for looping over sequences
-and performing batch processing.
-
-Syntax
-------
-
-'in' tag syntax::
-
-  <dtml-in SequenceVariable|expr="SequenceExpression">
-  [<dtml-else>]
-  </dtml-in>
-
-a commenting identifier at the end tag is allowed and will be ignored like::
-
-  </dtml-in my_short_sequ_name>
-
-same for '</dtml-if>' and '</dtml-let>'
-
-The 'in' block is repeated once for each item in the sequence
-variable or sequence expression. The current item is pushed on to
-the DTML namespace during each executing of the 'in' block.
-
-If there are no items in the sequence variable or expression, the
-optional 'else' block is executed.
-
-Attributes
-----------
-
-mapping
-  Iterates over mapping objects rather than instances. This allows values of
-  the mapping objects to be accessed as DTML variables.
-
-reverse
-  Reverses the sequence.
-
-sort=string
-  Sorts the sequence by the given attribute name.
-
-start=int
-  The number of the first item to be shown, where items are numbered from 1.
-
-end=int
-  The number of the last item to be shown, where items are numbered from 1.
-
-size=int
-  The size of the batch.
-
-skip_unauthorized
-  Don't raise an exception if an unauthorized item is encountered.
-
-orphan=int
-  The desired minimum batch size. This controls how sequences are split into
-  batches. If a batch smaller than the orphan size would occur, then no split
-  is performed, and a batch larger than the batch size results.
-
-  For example, if the sequence size is 12, the batch size is 10 the orphan size
-  is 3, then the result is one batch with all 12 items since splitting the
-  items into two batches would result in a batch smaller than the orphan size.
-
-  The default value is 0.
-
-overlap=int
-  The number of items to overlap between batches. The default is no overlap.
-
-previous
-  Iterates once if there is a previous batch. Sets batch variables for previous
-  sequence.
-
-next
-  Iterates once if there is a next batch. Sets batch variables for the next
-  sequence.
-
-prefix=string
-  Provide versions of the tag variables that start with this prefix instead of
-  "sequence", and that use underscores (_) instead of hyphens (-). The prefix
-  must start with a letter and contain only alphanumeric characters and
-  underscores (_).
-
-sort_expr=expression
-  Sorts the sequence by an attribute named by the value of the expression. This
-  allows you to sort on different attributes.
-
-reverse_expr=expression
-  Reverses the sequence if the expression evaluates to true. This allows you to
-  selectively reverse the sequence.
-
-Tag Variables
--------------
-
-Current Item Variables
-++++++++++++++++++++++
-
-These variables describe the current item.
-
-sequence-item
-  The current item.
-
-sequence-key
-  The current key. When looping over tuples of the form '(key,value)', the 'in'
-  tag interprets them as '(sequence-key, sequence-item)'.
-
-sequence-index
-  The index starting with 0 of the current item.
-
-sequence-number
-  The index starting with 1 of the current item.
-
-sequence-roman
-  The index in lowercase Roman numerals of the current item.
-
-sequence-Roman
-  The index in uppercase Roman numerals of the current item.
-
-sequence-letter
-  The index in lowercase letters of the current item.
-
-sequence-Letter
-  The index in uppercase letters of the current item.
-
-sequence-start
-  True if the current item is the first item.
-
-sequence-end
-  True if the current item is the last item.
-
-sequence-even
-  True if the index of the current item is even.
-
-sequence-odd
-  True if the index of the current item is odd.
-
-sequence-length
-  The length of the sequence.
-
-sequence-var-*variable*
-  A variable in the current item. For example, 'sequence-var-title' is the
-  'title' variable of the current item. Normally you can access these variables
-  directly since the current item is pushed on the DTML namespace. However
-  these variables can be useful when displaying previous and next batch
-  information.
-
-sequence-index-*variable*
-  The index of a variable of the current item.
-
-Summary Variables
-+++++++++++++++++
-
-These variable summarize information about numeric item variables. To use these
-variable you must loop over objects (like database query results) that have
-numeric variables.
-
-total-*variable*
-  The total of all occurrences of an item variable. 
-
-count-*variable*
-  The number of occurrences of an item variable.
-
-min-*variable*
-  The minimum value of an item variable.
-
-max-*variable*
-  The maximum value of an item variable.
-
-mean-*variable*
-  The mean value of an item variable.
-
-variance-*variable*
-  The variance of an item variable with count-1 degrees of freedom.
-
-variance-n-*variable*
-  The variance of an item variable with n degrees of freedom.
-
-standard-deviation-*variable*
-  The standard-deviation of an item variable with count-1 degrees of freedom.
-
-standard-deviation-n-*variable*
-  The standard-deviation of an item variable with n degrees of freedom.
-
-Grouping Variables
-++++++++++++++++++
-
-These variables allow you to track changes in current item variables.
-
-first-*variable*
-  True if the current item is the first with a particular value for a variable.
-
-last-*variable*
-  True if the current item is the last with a particular value for a variable.
-
-Batch Variables
-+++++++++++++++
-
-sequence-query
-  The query string with the 'start' variable removed. You can use this variable
-  to construct links to next and previous batches.
-
-sequence-step-size
-  The batch size.
-
-previous-sequence
-  True if the current batch is not the first one. Note, this variable is only
-  true for the first loop iteration.
-
-previous-sequence-start-index
-  The starting index of the previous batch.
-
-previous-sequence-start-number
-  The starting number of the previous batch. Note, this is the same as
-  'previous-sequence-start-index' + 1.
-
-previous-sequence-end-index
-  The ending index of the previous batch.
-
-previous-sequence-end-number
-  The ending number of the previous batch. Note, this is the same as
-  'previous-sequence-end-index' + 1.
-
-previous-sequence-size
-  The size of the previous batch.
-
-previous-batches
-  A sequence of mapping objects with information about all previous batches.
-  Each mapping object has these keys 'batch-start-index', 'batch-end-index',
-  and 'batch-size'.
-
-next-sequence
-  True if the current batch is not the last batch. Note, this variable is only
-  true for the last loop iteration.
-
-next-sequence-start-index
-  The starting index of the next sequence.
-
-next-sequence-start-number
-  The starting number of the next sequence. Note, this is the same as
-  'next-sequence-start-index' + 1.
-
-next-sequence-end-index
-  The ending index of the next sequence.
-
-next-sequence-end-number
-  The ending number of the next sequence. Note, this is the same as
-  'next-sequence-end-index' + 1.
-
-next-sequence-size
-  The size of the next index.
-
-next-batches
-  A sequence of mapping objects with information about all following batches.
-  Each mapping object has these keys 'batch-start-index', 'batch-end-index',
-  and 'batch-size'.
-
-Examples
---------
-
-Looping over sub-objects::
-
-  <dtml-in objectValues>
-    title: <dtml-var title><br>
-  </dtml-in>
-
-Looping over two sets of objects, using prefixes::
-
-  <dtml-let rows="(1,2,3)" cols="(4,5,6)">
-    <dtml-in rows prefix="row">
-      <dtml-in cols prefix="col">
-        <dtml-var expr="row_item * col_item"><br>
-        <dtml-if col_end>
-          <dtml-var expr="col_total_item * row_mean_item">
-        </dtml-if>
-      </dtml-in>
-    </dtml-in>
-  </dtml-let>
-
-Looping over a list of '(key, value)' tuples::
-
-  <dtml-in objectItems>
-    id: <dtml-var sequence-key>, title: <dtml-var title><br>
-  </dtml-in> 
-
-Creating alternate colored table rows::
-
-  <table>
-  <dtml-in objectValues>
-  <tr <dtml-if sequence-odd>bgcolor="#EEEEEE"
-      <dtml-else>bgcolor="#FFFFFF"
-      </dtml-if>>
-    <td><dtml-var title></td>
-  </tr>
-  </dtml-in>
-  </table>
-
-Basic batch processing::
-
-  <p>
-  <dtml-in largeSequence size=10 start=start previous>
-    <a href="<dtml-var absolute_url>
-      <dtml-var sequence-query>start=<dtml-var previous-sequence-start-number>">
-      Previous
-    </a>
-  </dtml-in>
-
-  <dtml-in largeSequence size=10 start=start next>
-    <a href="<dtml-var absolute_url>
-      <dtml-var sequence-query>start=<dtml-var next-sequence-start-number>">
-      Next
-    </a>
-  </dtml-in>
-  </p>
-
-  <p>
-  <dtml-in largeSequence size=10 start=start>
-    <dtml-var sequence-item>
-  </dtml-in>
-  </p>
-
-This example creates *Previous* and *Next* links to navigate between batches.
-Note, by using 'sequence-query', you do not lose any GET variables as you
-navigate between batches.
-
-let: Defines DTML variables
-===========================
-
-The 'let' tag defines variables in the DTML namespace.
-
-Syntax
-------
-
-'let' tag syntax::
-
-  <dtml-let [Name=Variable][Name="Expression"]...>
-  </dtml-let>
-
-The 'let' tag is a block tag. Variables are defined by tag arguments. Defined
-variables are pushed onto the DTML namespace while the 'let' block is executed.
-Variables are defined by attributes. The 'let' tag can have one or more
-attributes with arbitrary names. If the attributes are defined with double
-quotes they are considered expressions, otherwise they are looked up by name.
-Attributes are processed in order, so later attributes can reference, and/or
-overwrite earlier ones.
-
-Examples
---------
-
-Basic usage::
-
-  <dtml-let name="'Bob'" ids=objectIds>
-    name: <dtml-var name>
-    ids: <dtml-var ids>
-  </dtml-let>
-
-Using the 'let' tag with the 'in' tag::
-
- <dtml-in expr="(1,2,3,4)">
-   <dtml-let num=sequence-item
-             index=sequence-index
-             result="num*index">
-     <dtml-var num> * <dtml-var index> = <dtml-var result>
-   </dtml-let>
- </dtml-in>
-
-This yields::
-
-  1 * 0 = 0
-  2 * 1 = 2
-  3 * 2 = 6
-  4 * 3 = 12
-
-See Also
---------
-
-- with tag
-
-
-mime: Formats data with MIME
-============================
-
-The 'mime' tag allows you to create MIME encoded data. It is chiefly used to
-format email inside the 'sendmail' tag.
-
-Syntax
-------
-
-'mime' tag syntax::
-
-  <dtml-mime>
-  [<dtml-boundry>]
-  ...
-  </dtml-mime>
-
-The 'mime' tag is a block tag. The block is can be divided by one or more
-'boundry' tags to create a multi-part MIME message. 'mime' tags may be nested.
-The 'mime' tag is most often used inside the 'sendmail' tag.
-
-Attributes
-----------
-
-Both the 'mime' and 'boundry' tags have the same attributes.
-
-encode=string
-  MIME Content-Transfer-Encoding header, defaults to 'base64'. Valid encoding
-  options include 'base64', 'quoted-printable', 'uuencode', 'x-uuencode',
-  'uue', 'x-uue', and '7bit'. If the 'encode' attribute is set to '7bit' no
-  encoding is done on the block and the data is assumed to be in a valid MIME
-  format.
-
-type=string
-  MIME Content-Type header.
-
-type_expr=string
-  MIME Content-Type header as a variable expression. You cannot use both 'type'
-  and 'type_expr'.
-
-name=string
-  MIME Content-Type header name.
-
-name_expr=string
-  MIME Content-Type header name as a variable expression. You cannot use both
-  'name' and 'name_expr'.
-
-disposition=string
-  MIME Content-Disposition header.
-
-disposition_expr=string
-  MIME Content-Disposition header as a variable expression. You cannot use both
-  'disposition' and 'disposition_expr'.
-
-filename=string
-  MIME Content-Disposition header filename.
-
-filename_expr=string
-  MIME Content-Disposition header filename as a variable expression. You cannot
-  use both 'filename' and 'filename_expr'.
-
-skip_expr=string
-  A variable expression that if true, skips the block. You can use this
-  attribute to selectively include MIME blocks.
-
-Examples
---------
-
-Sending a file attachment::
-
-  <dtml-sendmail>
-  To: <dtml-var recipient>
-  Subject: Resume
-  <dtml-mime type="text/plain" encode="7bit">
-
-  Hi, please take a look at my resume.
-
-  <dtml-boundary type="application/octet-stream" disposition="attachment" 
-  encode="base64" filename_expr="resume_file.getId()"><dtml-var expr="resume_file.read()"></dtml-mime>
-  </dtml-sendmail>
-
-See Also
---------
-
-- `Python Library mimetools <http://docs.python.org/library/mimetools.html>`_
-
-raise: Raises an exception
-==========================
-
-The 'raise' tag raises an exception, mirroring the Python 'raise'
-statement.
-
-Syntax
-------
-
-'raise' tag syntax::
-
-  <dtml-raise ExceptionName|ExceptionExpression>
-  </dtml-raise>
-
-The 'raise' tag is a block tag. It raises an exception. Exceptions
-can be an exception class or a string. The contents of the tag are
-passed as the error value.
-
-Examples
---------
-
-Raising a KeyError::
-
-  <dtml-raise KeyError></dtml-raise>
-
-Raising an HTTP 404 error::
-
-  <dtml-raise NotFound>Web Page Not Found</dtml-raise>
-
-See Also
---------
-
-- try tag
-
-- `Python Tutorial Errors and Exceptions <http://docs.python.org/tutorial/errors.html>`_
-
-- `Python Built-in Exceptions <http://docs.python.org/library/exceptions.html>`_
-
-return: Returns data
-====================
-
-The 'return' tag stops executing DTML and returns data. It mirrors
-the Python 'return' statement.
-
-Syntax
-------
-
-'return' tag syntax::
-
-  <dtml-return ReturnVariable|expr="ReturnExpression">
-
-Stops execution of DTML and returns a variable or expression. The
-DTML output is not returned. Usually a return expression is more
-useful than a return variable. Scripts largely obsolete this tag.
-
-Examples
-
-Returning a variable::
-
-  <dtml-return result>
-
-Returning a Python dictionary::
-
-  <dtml-return expr="{'hi':200, 'lo':5}">
-
-sendmail: Sends email with SMTP
-===============================
-
-The 'sendmail' tag sends an email message using SMTP.
-
-Syntax
-------
-
-'sendmail' tag syntax::
-
-  <dtml-sendmail>
-  </dtml-sendmail>
-
-The 'sendmail' tag is a block tag. It either requires a 'mailhost' or a
-'smtphost' argument, but not both. The tag block is sent as an email message.
-The beginning of the block describes the email headers. The headers are
-separated from the body by a blank line. Alternately the 'To', 'From' and
-'Subject' headers can be set with tag arguments.
-
-Attributes
-----------
-
-mailhost
-  The name of a Zope MailHost object to use to send email. You cannot specify
-  both a mailhost and a smtphost.
-
-smtphost
-  The name of a SMTP server used to send email. You cannot specify both a
-  mailhost and a smtphost.
-
-port
-  If the smtphost attribute is used, then the port attribute is used to specify
-  a port number to connect to. If not specified, then port 25 will be used.
-
-mailto
-  The recipient address or a list of recipient addresses separated by commas.
-  This can also be specified with the 'To' header.
-
-mailfrom
-  The sender address. This can also be specified with the 'From' header.
-
-subject
-  The email subject. This can also be specified with the 'Subject' header.
-
-Examples
---------
-
-Sending an email message using a Mail Host::
-
-  <dtml-sendmail mailhost="mailhost">
-  To: <dtml-var recipient>
-  From: <dtml-var sender>
-  Subject: <dtml-var subject>
-
-  Dear <dtml-var recipient>,
-
-  You order number <dtml-var order_number> is ready.
-  Please pick it up at your soonest convenience.
-  </dtml-sendmail>
-
-See Also
---------
-
-- `RFC 821 (SMTP Protocol) <http://www.ietf.org/rfc/rfc0821.txt>`_
-
-- mime tag
-
-
-sqlgroup: Formats complex SQL expressions
-=========================================
-
-The 'sqlgroup' tag formats complex boolean SQL expressions. You can use it
-along with the 'sqltest' tag to build dynamic SQL queries that tailor
-themselves to the environment. This tag is used in SQL Methods.
-
-Syntax
-------
-
-'sqlgroup' tag syntax::
-
-  <dtml-sqlgroup>
-  [<dtml-or>]
-  [<dtml-and>]
-  ...
-  </dtml-sqlgroup>
-
-The 'sqlgroup' tag is a block tag. It is divided into blocks with
-one or more optional 'or' and 'and' tags. 'sqlgroup' tags can be
-nested to produce complex logic.
-
-Attributes
-----------
-
-required=boolean
-  Indicates whether the group is required. If it is not required and contains
-  nothing, it is excluded from the DTML output.
-
-where=boolean
-  If true, includes the string "where". This is useful for the outermost
-  'sqlgroup' tag in a SQL 'select' query.
-
-Examples
---------
-
-Sample usage::
-
-  select * from employees 
-  <dtml-sqlgroup where>
-    <dtml-sqltest salary op="gt" type="float" optional>
-  <dtml-and>
-    <dtml-sqltest first type="nb" multiple optional>
-  <dtml-and>
-    <dtml-sqltest last type="nb" multiple optional>
-  </dtml-sqlgroup>  
-
-If 'first' is 'Bob' and 'last' is 'Smith, McDonald' it renders::
-
-  select * from employees
-  where
-  (first='Bob'
-   and
-   last in ('Smith', 'McDonald')
-  )
-
-If 'salary' is 50000 and 'last' is 'Smith' it renders::
-
-  select * from employees
-  where 
-  (salary > 50000.0
-   and
-   last='Smith'
-  )
-
-Nested 'sqlgroup' tags::
-
-  select * from employees
-  <dtml-sqlgroup where>
-    <dtml-sqlgroup>
-       <dtml-sqltest first op="like" type="nb">
-    <dtml-and>
-       <dtml-sqltest last op="like" type="nb">
-    </dtml-sqlgroup>
-  <dtml-or>
-    <dtml-sqltest salary op="gt" type="float">
-  </dtml-sqlgroup>
-
-Given sample arguments, this template renders to SQL like so::
-
-  select * form employees
-  where
-  (
-    (
-     name like 'A*'
-     and
-     last like 'Smith'
-     )
-   or
-   salary > 20000.0
-  )
-
-See Also
---------
-
-- sqltest tag
-
-
-sqltest: Formats SQL condition tests
-====================================
-
-The 'sqltest' tag inserts a condition test into SQL code. It tests a column
-against a variable. This tag is used in SQL Methods.
-
-Syntax
-------
-
-'sqltest' tag syntax::
-
-  <dtml-sqltest Variable|expr="VariableExpression">
-
-The 'sqltest' tag is a singleton. It inserts a SQL condition test statement. It
-is used to build SQL queries. The 'sqltest' tag correctly escapes the inserted
-variable. The named variable or variable expression is tested against a SQL
-column using the specified comparison operation.
-
-Attributes
-----------
-
-type=string
-  The type of the variable. Valid types include: 'string', 'int', 'float' and
-  'nb'. 'nb' means non-blank string, and should be used instead of 'string'
-  unless you want to test for blank values. The type attribute is required and
-  is used to properly escape inserted variable.
-
-column=string
-  The name of the SQL column to test against. This attribute defaults to the
-  variable name.
-
-multiple=boolean
-  If true, then the variable may be a sequence of values to test the column
-  against.
-
-optional=boolean
-  If true, then the test is optional and will not be rendered if the variable
-  is empty or non-existent.
-
-op=string
-  The comparison operation. Valid comparisons include: 
-
-  eq
-    equal to
-
-  gt
-    greater than
-
-  lt
-    less than
-
-  ne
-    not equal to
-
-  ge
-    greater than or equal to
-
-  le
-    less than or equal to
-
-  The comparison defaults to equal to. If the comparison is not
-  recognized it is used anyway. Thus you can use comparisons such
-  as 'like'.
-
-Examples
---------
-
-Basic usage::
-
-  select * from employees
-    where <dtml-sqltest name type="nb">
-
-If the 'name' variable is 'Bob' then this renders::
-
-  select * from employees
-    where name = 'Bob'
-
-Multiple values::
-
-  select * from employees
-    where <dtml-sqltest empid type=int multiple>
-
-If the 'empid' variable is '(12,14,17)' then this renders::
-
-  select * from employees
-    where empid in (12, 14, 17)
-
-See Also
---------
-
-- sqlgroup tag
-
-- sqlvar tag
-
-
-sqlvar: Inserts SQL variables
-=============================
-
-The 'sqlvar' tag safely inserts variables into SQL code. This tag is used in
-SQL Methods.
-
-Syntax
-------
-
-'sqlvar' tag syntax::
-
-  <dtml-sqlvar Variable|expr="VariableExpression">
-
-The 'sqlvar' tag is a singleton. Like the 'var' tag, the 'sqlvar' tag looks up
-a variable and inserts it. Unlike the var tag, the formatting options are
-tailored for SQL code.
-
-Attributes
-----------
-
-type=string
-  The type of the variable. Valid types include: 'string', 'int', 'float' and
-  'nb'. 'nb' means non-blank string and should be used in place of 'string'
-  unless you want to use blank strings. The type attribute is required and is
-  used to properly escape inserted variable.
-
-optional=boolean
-  If true and the variable is null or non-existent, then nothing is inserted.
-
-Examples
---------
-
-Basic usage::
-
-  select * from employees 
-    where name=<dtml-sqlvar name type="nb">
-
-This SQL quotes the 'name' string variable.
-
-See Also
---------
-
-- sqltest tag
-
-
-tree: Inserts a tree widget
-===========================
-
-The 'tree' tag displays a dynamic tree widget by querying Zope objects.
-
-Syntax
-------
-
-'tree' tag syntax::
-
-  <dtml-tree [VariableName|expr="VariableExpression"]>
-  </dtml-tree>
-
-The 'tree' tag is a block tag. It renders a dynamic tree widget in
-HTML. The root of the tree is given by variable name or
-expression, if present, otherwise it defaults to the current
-object. The 'tree' block is rendered for each tree node, with the
-current node pushed onto the DTML namespace.
-
-Tree state is set in HTTP cookies. Thus for trees to work, cookies
-must be enabled. Also you can only have one tree per page.
-
-Attributes
-----------
-
-branches=string
-  Finds tree branches by calling the named method. The default method is
-  'tpValues' which most Zope objects support.
-
-branches_expr=string
-  Finds tree branches by evaluating the expression.
-
-id=string
-  The name of a method or id to determine tree state. It defaults to 'tpId'
-  which most Zope objects support. This attribute is for advanced usage only.
-
-url=string
-  The name of a method or attribute to determine tree item URLs. It defaults to
-  'tpURL' which most Zope objects support. This attribute is for advanced usage
-  only.
-
-leaves=string
-  The name of a DTML Document or Method used to render nodes that don't have
-  any children. Note: this document should begin with '<dtml-var
-  standard_html_header>' and end with '<dtml-var standard_html_footer>' in
-  order to ensure proper display in the tree.
-
-header=string
-  The name of a DTML Document or Method displayed before expanded nodes. If the
-  header is not found, it is skipped.
-
-footer=string
-  The name of a DTML Document or Method displayed after expanded nodes. If the
-  footer is not found, it is skipped.
-
-nowrap=boolean
-  If true then rather than wrap, nodes may be truncated to fit available space.
-
-sort=string
-  Sorts the branches by the named attribute.
-
-reverse
-  Reverses the order of the branches.
-
-assume_children=boolean
-  Assumes that nodes have children. This is useful if fetching and querying
-  child nodes is a costly process. This results in plus boxes being drawn next
-  to all nodes.
-
-single=boolean
-  Allows only one branch to be expanded at a time. When you expand a new
-  branch, any other expanded branches close.
-
-skip_unauthorized
-  Skips nodes that the user is unauthorized to see, rather than raising an
-  error.
-
-urlparam=string
-  A query string which is included in the expanding and contracting widget
-  links. This attribute is for advanced usage only.
-
-prefix=string
-  Provide versions of the tag variables that start with this prefix instead of
-  "tree", and that use underscores (_) instead of hyphens (-). The prefix must
-  start with a letter and contain only alphanumeric characters and underscores
-  (_).
-
-Tag Variables
--------------
-
-tree-item-expanded
-  True if the current node is expanded.
-
-tree-item-url
-  The URL of the current node.
-
-tree-root-url
-  The URL of the root node.
-
-tree-level
-  The depth of the current node. Top-level nodes have a depth of zero.
-
-tree-colspan
-  The number of levels deep the tree is being rendered. This variable along
-  with the 'tree-level' variable can be used to calculate table rows and
-  colspan settings when inserting table rows into the tree table.
-
-tree-state
-  The tree state expressed as a list of ids and sub-lists of ids. This variable
-  is for advanced usage only.
-
-Tag Control Variables
----------------------
-
-You can control the tree tag by setting these variables.
-
-expand_all
-  If this variable is true then the entire tree is expanded.
-
-collapse_all
-  If this variable is true then the entire tree is collapsed.
-
-Examples
---------
-
-Display a tree rooted in the current object::
-
-  <dtml-tree>
-    <dtml-var title_or_id>
-  </dtml-tree>
-
-Display a tree rooted in another object, using a custom branches
-method::
-
-  <dtml-tree expr="folder.object" branches="objectValues">
-    Node id : <dtml-var getId>
-  </dtml-tree>
-
-try: Handles exceptions
-=======================
-
-The 'try' tag allows exception handling in DTML, mirroring the Python
-'try/except' and 'try/finally' constructs.
-
-Syntax
-------
-
-The 'try' tag has two different syntaxes, 'try/except/else' and 'try/finally'.
-
-'try/except/else' Syntax::
-
-  <dtml-try>
-  <dtml-except [ExceptionName] [ExceptionName]...>
-  ... 
-  [<dtml-else>]
-  </dtml-try>
-
-The 'try' tag encloses a block in which exceptions can be caught and handled.
-There can be one or more 'except' tags that handles zero or more exceptions. If
-an 'except' tag does not specify an exception, then it handles all exceptions.
-
-When an exception is raised, control jumps to the first 'except' tag that
-handles the exception. If there is no 'except' tag to handle the exception,
-then the exception is raised normally.
-
-If no exception is raised, and there is an 'else' tag, then the 'else' tag will
-be executed after the body of the 'try' tag.
-
-The 'except' and 'else' tags are optional.
-
-'try/finally' Syntax::
-
-  <dtml-try>
-  <dtml-finally>
-  </dtml-try>
-
-The 'finally' tag cannot be used in the same 'try' block as the 'except' and
-'else' tags. If there is a 'finally' tag, its block will be executed whether or
-not an exception is raised in the 'try' block.
-
-Attributes
-----------
-
-except
-  Zero or more exception names. If no exceptions are listed then the except tag
-  will handle all exceptions.
-
-Tag Variables
--------------
-
-Inside the 'except' block these variables are defined.
-
-error_type
-  The exception type.
-
-error_value
-  The exception value.
-
-error_tb
-  The traceback.
-
-Examples
---------
-
-Catching a math error::
-
-  <dtml-try>
-  <dtml-var expr="1/0">
-  <dtml-except ZeroDivisionError>
-  You tried to divide by zero.
-  </dtml-try>
-
-Returning information about the handled exception::
-
-  <dtml-try>
-  <dtml-call dangerousMethod>
-  <dtml-except>
-  An error occurred.
-  Error type: <dtml-var error_type>
-  Error value: <dtml-var error_value>
-  </dtml-try>
-
-Using finally to make sure to perform clean up regardless of whether an error
-is raised or not::
-
-  <dtml-call acquireLock>
-  <dtml-try>
-  <dtml-call someMethod>
-  <dtml-finally>
-  <dtml-call releaseLock>
-  </dtml-try>
-
-See Also
---------
-
-- raise tag
-
-- `Python Tutorial Errors and Exceptions <http://docs.python.org/tutorial/errors.html>`_
-
-- `Python Built-in Exceptions <http://docs.python.org/library/exceptions.html>`_
-
-
-unless: Tests a condition
-=========================
-
-The 'unless' tag provides a shortcut for testing negative conditions. For more
-complete condition testing use the 'if' tag.
-
-Syntax
-------
-
-'unless' tag syntax::
-
-  <dtml-unless ConditionVariable|expr="ConditionExpression">
-  </dtml-unless>
-
-The 'unless' tag is a block tag. If the condition variable or expression
-evaluates to false, then the contained block is executed. Like the 'if' tag,
-variables that are not present are considered false.
-
-Examples
---------
-
-Testing a variable::
-
-  <dtml-unless testMode>
-    <dtml-call dangerousOperation>
-  </dtml-unless>
-
-The block will be executed if 'testMode' does not exist, or exists but is
-false.
-
-See Also
---------
-
-- if tag
-
-
-var: Inserts a variable
-=======================
-
-The 'var' tags allows you insert variables into DTML output.
-
-Syntax
-------
-
-'var' tag syntax::
-
-  <dtml-var Variable|expr="Expression">
-
-The 'var' tag is a singleton tag. The 'var' tag finds a variable by searching
-the DTML namespace which usually consists of current object, the current
-object's containers, and finally the web request. If the variable is found, it
-is inserted into the DTML output. If not found, Zope raises an error.
-
-'var' tag entity syntax::
-
-  &dtml-variableName;
-
-Entity syntax is a short cut which inserts and HTML quotes the variable. It is
-useful when inserting variables into HTML tags.
-
-'var' tag entity syntax with attributes::
-
-  &dtml.attribute1[.attribute2]...-variableName;
-
-To a limited degree you may specify attributes with the entity syntax. You may
-include zero or more attributes delimited by periods. You cannot provide
-arguments for attributes using the entity syntax. If you provide zero or more
-attributes, then the variable is not automatically HTML quoted. Thus you can
-avoid HTML quoting with this syntax, '&dtml.-variableName;'.
-
-Attributes
-----------
-
-html_quote
-  Convert characters that have special meaning in HTML to HTML character
-  entities.
-
-missing=string
-  Specify a default value in case Zope cannot find the variable.
-
-fmt=string
-  Format a variable. Zope provides a few built-in formats including C-style
-  format strings. For more information on C-style format strings see the
-  `Python Library Reference <http://docs.python.org/library/stdtypes.html#typesseq-strings>`_.
-  If the format string is not a built-in format, then it is assumed to be a
-  method of the object, and it called.
-
-  collection-length
-    The length of the variable, assuming it is a sequence.
-
-null=string
-  A default value to use if the variable is None.
-
-lower
-  Converts upper-case letters to lower case. 
-
-upper
-  Converts lower-case letters to upper case. 
-
-capitalize
-  Capitalizes the first character of the inserted word.
-
-spacify
-  Changes underscores in the inserted value to spaces.
-
-thousands_commas
-  Inserts commas every three digits to the left of a decimal point in values
-  containing numbers for example '12000' becomes '12,000'.
-
-url
-  Inserts the URL of the object, by calling its 'absolute_url' method.
-
-url_quote
-  Converts characters that have special meaning in URLs to HTML character
-  entities.
-
-url_quote_plus
-  URL quotes character, like 'url_quote' but also converts spaces to plus
-  signs.
-
-sql_quote
-  Converts single quotes to pairs of single quotes. This is needed to safely
-  include values in SQL strings.
-
-newline_to_br
-  Convert newlines (including carriage returns) to HTML break tags.
-
-size=arg
-  Truncates the variable at the given length (Note: if a space occurs in the
-  second half of the truncated string, then the string is further truncated to
-  the right-most space).
-
-etc=arg
-  Specifies a string to add to the end of a string which has been truncated (by
-  setting the 'size' attribute listed above). By default, this is '...'
-
-
-Examples
---------
-
-Inserting a simple variable into a document::
-
-  <dtml-var standard_html_header>
-
-Truncation::
-
-  <dtml-var colors size=10 etc=", etc.">
-
-will produce the following output if *colors* is the string 'red yellow
-green'::
-
-  red yellow, etc.
-
-C-style string formatting::
-
-  <dtml-var expr="23432.2323" fmt="%.2f">
-
-renders to::
-
-  23432.23
-
-Inserting a variable, *link*, inside an HTML 'A' tag with the entity syntax::
-
-  <a href="&dtml-link;">Link</a>
-
-Inserting a link to a document 'doc', using entity syntax with attributes::
-
-  <a href="&dtml.url-doc;"><dtml-var doc fmt="title_or_id"></a>
-
-This creates an HTML link to an object using its URL and title. This example
-calls the object's 'absolute_url' method for the URL (using the 'url'
-attribute) and its 'title_or_id' method for the title.
-
-with: Controls DTML variable look up
-====================================
-
-The 'with' tag pushes an object onto the DTML namespace. Variables will be
-looked up in the pushed object first.
-
-Syntax
-------
-
-'with' tag syntax::
-
-  <dtml-with Variable|expr="Expression">
-  </dtml-with>
-
-The 'with' tag is a block tag. It pushes the named variable or variable
-expression onto the DTML namespace for the duration of the 'with' block. Thus
-names are looked up in the pushed object first.
-
-Attributes
-----------
-
-only
-  Limits the DTML namespace to only include the one defined in the 'with' tag.
-
-mapping
-  Indicates that the variable or expression is a mapping object. This ensures
-  that variables are looked up correctly in the mapping object.
-
-Examples
---------
-
-Looking up a variable in the REQUEST::
-
-  <dtml-with REQUEST only>
-    <dtml-if id>
-      <dtml-var id>
-    <dtml-else>
-      'id' was not in the request.
-    </dtml-if>
-  </dtml-with>
-
-Pushing the first child on the DTML namespace::
-
-  <dtml-with expr="objectValues()[0]">
-    First child's id: <dtml-var id>
-  </dtml-with>
-
-See Also
---------
-
-- let tag

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/AppendixB.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/AppendixB.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/AppendixB.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,27 +0,0 @@
-Appendix B: API Reference
-#########################
-
-Introduction
-============
-
-This reference describes the interfaces to the most common set of basic Zope
-objects. This reference is useful while writing Page Templates, DTML, Python
-scripts, and Product code.
-
-The intended audience is able to read simple Python code and has at least
-passing experience with object-oriented programming.
-
-The reference is not a tutorial. Nor is it a substitute for reading the rest of
-the Zope Book. Examples, where they are provided, are intended to be
-illustrative, but not comprehensive.
-
-Sorry
-=====
-
-The manually maintained API reference wasn't such a good idea.
-
-Converting it from the original source of structured text to reStructuredText
-was too much work to be done. We will look into auto-generating the API
-documentation from docstrings at some point.
-
-Reading the code is your best bet for now.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/AppendixC.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/AppendixC.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/AppendixC.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,1382 +0,0 @@
-Appendix C: Zope Page Templates Reference
-#########################################
-
-Zope Page Templates are an HTML/XML generation tool. This appendix is a
-reference to Zope Page Templates standards: Template Attribute Language (TAL),
-TAL Expression Syntax (TALES), and Macro Expansion TAL (METAL). It also
-describes some ZPT-specific behaviors that are not part of the standards.
-
-TAL Overview
-============
-
-The *Template Attribute Language* (TAL) standard is an attribute language used
-to create dynamic templates. It allows elements of a document to be replaced,
-repeated, or omitted.
-
-The statements of TAL are XML attributes from the TAL namespace. These
-attributes can be applied to an XML or HTML document in order to make it act as
-a template.
-
-A **TAL statement** has a name (the attribute name) and a body (the attribute
-value). For example, an `content` statement might look like::
-
-  tal:content="string:Hello"
-
-The element on which a statement is defined is its **statement element**. Most
-TAL statements require expressions, but the syntax and semantics of these
-expressions are not part of TAL. TALES is recommended for this purpose.
-
-TAL Namespace
-+++++++++++++
-
-The TAL namespace URI and recommended alias are currently defined
-as::
-
-  xmlns:tal="http://xml.zope.org/namespaces/tal"
-
-This is not a URL, but merely a unique identifier. Do not expect a browser to
-resolve it successfully.
-
-Zope does not require an XML namespace declaration when creating templates with
-a content-type of `text/html`. However, it does require an XML namespace
-declaration for all other content-types.
-
-TAL Statements
-++++++++++++++
-
-These are the tal statements:
-
-- tal:attributes - dynamically change element attributes.
-
-- tal:define - define variables.
-
-- tal:condition - test conditions.
-
-- tal:content - replace the content of an element.
-
-- tal:omit-tag - remove an element, leaving the content of the element.
-
-- tal:on-error - handle errors.
-
-- tal:repeat - repeat an element.
-
-- tal:replace - replace the content of an element and remove the element
-  leaving the content.
-
-Expressions used in statements may return values of any type, although most
-statements will only accept strings, or will convert values into a string
-representation. The expression language must define a value named *nothing*
-that is not a string. In particular, this value is useful for deleting elements
-or attributes.
-
-Order of Operations
-+++++++++++++++++++
-
-When there is only one TAL statement per element, the order in which they are
-executed is simple. Starting with the root element, each element's statements
-are executed, then each of its child elements is visited, in order, to do the
-same.
-
-Any combination of statements may appear on the same elements, except that the
-`content` and `replace` statements may not appear together.
-
-Due to the fact that TAL sees statements as XML attributes, even in HTML
-documents, it cannot use the order in which statements are written in the tag
-to determine the order in which they are executed. TAL must also forbid
-multiples of the same kind of statement on a single element, so it is
-sufficient to arrange the kinds of statement in a precedence list.
-
-When an element has multiple statements, they are executed in this order:
-
-
-1. define
-
-2. condition
-
-3. repeat
-
-4. content or replace
-
-5. attributes
-
-6. omit-tag
-
-Since the `on-error` statement is only invoked when an error occurs, it does
-not appear in the list.
-
-It may not be apparent that there needs to be an ordering. The reason that
-there must be one is that TAL is XML based. The XML specification specifically
-states that XML processors are free to rewrite the terms. In particular, you
-cannot assume that attributes of an XML statement will be processed in the
-order written, particularly if there is another preprocessor involved. To avoid
-needless proliferation of tags, and still permit unambiguous execution of
-complex TAL, a precedence order was chosen according to the following
-rationale.
-
-The reasoning behind this ordering goes like this: You often want to set up
-variables for use in other statements, so `define` comes first. The very next
-thing to do is decide whether this element will be included at all, so
-`condition` is next; since the condition may depend on variables you just set,
-it comes after `define`. It is valuable be able to replace various parts of an
-element with different values on each iteration of a repeat, so `repeat` is
-next. It makes no sense to replace attributes and then throw them away, so
-`attributes` is last. The remaining statements clash, because they each replace
-or edit the statement element.
-
-attributes: Replace element attributes
-======================================
-
-Syntax
-++++++
-
-tal:attributes syntax::
-
-  argument             ::= attribute_statement [';' attribute_statement]*
-  attribute_statement  ::= attribute_name expression
-  attribute_name       ::= [namespace-prefix ':'] Name
-  namespace-prefix     ::= Name
-
-*Note: If you want to include a semi-colon (;) in an `expression`, it must be
-escaped by doubling it (;;).*
-
-Description
-+++++++++++
-
-The `tal:attributes` statement replaces the value of an attribute (or creates
-an attribute) with a dynamic value. You can qualify an attribute name with a
-namespace prefix, for example::
-
-  html:table
-
-if you are generating an XML document with multiple namespaces. The value of
-each expression is converted to a string, if necessary.
-
-If the expression associated with an attribute assignment evaluates to
-*nothing*, then that attribute is deleted from the statement element. If the
-expression evaluates to *default*, then that attribute is left unchanged. Each
-attribute assignment is independent, so attributes may be assigned in the same
-statement in which some attributes are deleted and others are left alone.
-
-If you use `tal:attributes` on an element with an active `tal:replace` command,
-the `tal:attributes` statement is ignored.
-
-
-If you use `tal:attributes` on an element with a `tal:repeat` statement, the
-replacement is made on each repetition of the element, and the replacement
-expression is evaluated fresh for each repetition.
-
-Examples
-++++++++
-
-Replacing a link::
-
-  <a href="/sample/link.html"
-     tal:attributes="href context/sub/absolute_url">
-
-Replacing two attributes::
-
-  <textarea
-    rows="80" cols="20"
-    tal:attributes="rows request/rows;cols request/cols">
-
-condition: Conditionally insert or remove an element
-====================================================
-
-Syntax
-++++++
-
-tal:condition syntax::
-
-  argument ::= expression
-
-Description
-+++++++++++
-
-The `tal:condition` statement includes the statement element in the template
-only if the condition is met, and omits it otherwise. If its expression
-evaluates to a *true* value, then normal processing of the element continues,
-otherwise the statement element is immediately removed from the template. For
-these purposes, the value *nothing* is false, and *default* has the same effect
-as returning a true value.
-
-*Note: Zope considers missing variables, None, zero, empty strings, and empty
-sequences false; all other values are true.*
-
-Examples
-++++++++
-
-Test a variable before inserting it (the first example tests for existence and
-truth, while the second only tests for existence)::
-
-  <p tal:condition="request/message | nothing"
-     tal:content="request/message">message goes here</p>
-
-  <p tal:condition="exists:request/message"
-     tal:content="request/message">message goes here</p>
-
-Test for alternate conditions::
-
-  <div tal:repeat="item python:range(10)">
-    <p tal:condition="repeat/item/even">Even</p>
-    <p tal:condition="repeat/item/odd">Odd</p>
-  </div>
-
-content: Replace the content of an element
-==========================================
-
-Syntax
-++++++
-
-tal:content syntax::
-
-  argument ::= (['text'] | 'structure') expression
-
-Description
-+++++++++++
-
-Rather than replacing an entire element, you can insert text or structure in
-place of its children with the `tal:content` statement. The statement argument
-is exactly like that of `tal:replace`, and is interpreted in the same fashion.
-If the expression evaluates to *nothing*, the statement element is left
-childless. If the expression evaluates to *default*, then the element's
-contents are unchanged.
-
-The default replacement behavior is `text`, which replaces angle-brackets and
-ampersands with their HTML entity equivalents. The `structure` keyword passes
-the replacement text through unchanged, allowing HTML/XML markup to be
-inserted. This can break your page if the text contains unanticipated markup
-(e.g.. text submitted via a web form), which is the reason that it is not the
-default.
-
-Examples
-++++++++
-
-Inserting the user name::
-
-  <p tal:content="user/getUserName">Fred Farkas</p>
-
-Inserting HTML/XML::
-
-  <p tal:content="structure context/getStory">
-    marked <b>up</b> content goes here.
-  </p>
-
-define: Define variables
-========================
-
-Syntax
-++++++
-
-tal:define syntax::
-
-  argument       ::= define_scope [';' define_scope]*
-  define_scope   ::= (['local'] | 'global') define_var
-  define_var     ::= variable_name expression
-  variable_name  ::= Name
-
-*Note: If you want to include a semi-colon (;) in an `expression`, it must be
-escaped by doubling it (;;).*
-
-Description
-+++++++++++
-
-The `tal:define` statement defines variables. You can define two different
-kinds of TAL variables: local and global. When you define a local variable in a
-statement element, you can only use that variable in that element and the
-elements it contains. If you redefine a local variable in a contained element,
-the new definition hides the outer element's definition within the inner
-element. When you define a global variables, you can use it in any element
-processed after the defining element. If you redefine a global variable, you
-replace its definition for the rest of the template.
-
-*Note: local variables are the default*
-
-If the expression associated with a variable evaluates to *nothing*, then that
-variable has the value *nothing*, and may be used as such in further
-expressions. Likewise, if the expression evaluates to *default*, then the
-variable has the value *default*, and may be used as such in further
-expressions.
-
-Examples
-++++++++
-
-Defining a global variable::
-
-  tal:define="global company_name string:Zope Corp, Inc."
-
-Defining two variables, where the second depends on the first::
-
-  tal:define="mytitle template/title; tlen python:len(mytitle)"
-
-
-omit-tag: Remove an element, leaving its contents
-=================================================
-
-Syntax
-++++++
-
-tal:omit-tag syntax::
-
-  argument ::= [ expression ]
-
-Description
-+++++++++++
-
-The `tal:omit-tag` statement leaves the contents of an element in place while
-omitting the surrounding start and end tags.
-
-If the expression evaluates to a *false* value, then normal processing of the
-element continues and the tags are not omitted. If the expression evaluates to
-a *true* value, or no expression is provided, the statement element is replaced
-with its contents.
-
-Zope treats empty strings, empty sequences, zero, None, and *nothing* as false.
-All other values are considered true, including *default*.
-
-Examples
-++++++++
-
-Unconditionally omitting a tag::
-
-  <div tal:omit-tag="" comment="This tag will be removed">
-    <i>...but this text will remain.</i>
-  </div>
-
-Conditionally omitting a tag::
-
-  <b tal:omit-tag="not:bold">
-    I may be bold.
-  </b>
-
-The above example will omit the `b` tag if the variable `bold` is false.
-
-Creating ten paragraph tags, with no enclosing tag::
-
-  <span tal:repeat="n python:range(10)"
-        tal:omit-tag="">
-    <p tal:content="n">1</p>
-  </span>
-
-
-on-error: Handle errors
-=======================
-
-Syntax
-++++++
-
-tal:on-error syntax::
-
-  argument ::= (['text'] | 'structure') expression
-
-Description
-+++++++++++
-
-The `tal:on-error` statement provides error handling for your template. When a
-TAL statement produces an error, the TAL interpreter searches for a
-`tal:on-error` statement on the same element, then on the enclosing element,
-and so forth. The first `tal:on-error` found is invoked. It is treated as a
-`tal:content` statement.
-
-A local variable `error` is set. This variable has these attributes:
-
-type
-  the exception type
-
-value
-  the exception instance
-
-traceback
-  the traceback object
-
-The simplest sort of `tal:on-error` statement has a literal error string or
-*nothing* for an expression. A more complex handler may call a script that
-examines the error and either emits error text or raises an exception to
-propagate the error outwards.
-
-Examples
-++++++++
-
-Simple error message::
-
-  <b tal:on-error="string: Username is not defined!" 
-     tal:content="context/getUsername">Ishmael</b>
-
-Removing elements with errors::
-
-  <b tal:on-error="nothing"
-     tal:content="context/getUsername">Ishmael</b>
-
-Calling an error-handling script::
-
-  <div tal:on-error="structure context/errorScript">
-  ...
-  </div>
-
-Here's what the error-handling script might look like::
-
-  ## Script (Python) "errHandler"
-  ##bind namespace=_
-  ##
-  error=_['error']
-  if error.type==ZeroDivisionError:
-      return "<p>Can't divide by zero.</p>"
-  else
-      return """<p>An error ocurred.</p>
-      <p>Error type: %s</p>
-      <p>Error value: %s</p>""" % (error.type, error.value)
-
-
-repeat: Repeat an element
-=========================
-
-Syntax
-++++++
-
-tal:repeat syntax::
-
-  argument      ::= variable_name expression
-  variable_name ::= Name
-
-Description
-+++++++++++
-
-The `tal:repeat` statement replicates a sub-tree of your document once for each
-item in a sequence. The expression should evaluate to a sequence. If the
-sequence is empty, then the statement element is deleted, otherwise it is
-repeated for each value in the sequence. If the expression is *default*, then
-the element is left unchanged, and no new variables are defined.
-
-The `variable_name` is used to define a local variable and a repeat variable.
-For each repetition, the local variable is set to the current sequence element,
-and the repeat variable is set to an iteration object.
-
-Repeat Variables
-++++++++++++++++
-
-You use repeat variables to access information about the current repetition
-(such as the repeat index). The repeat variable has the same name as the local
-variable, but is only accessible through the built-in variable named `repeat`.
-
-
-The following information is available from the repeat variable:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-- *index*- - repetition number, starting from zero.
-
-- *number*- - repetition number, starting from one.
-
-- *even*- - true for even-indexed repetitions (0, 2, 4, ...).
-
-- *odd*- - true for odd-indexed repetitions (1, 3, 5, ...).
-
-- *start*- - true for the starting repetition (index 0).
-
-- *end*- - true for the ending, or final, repetition.
-
-- *first*- - true for the first item in a group - see note below
-
-- *last*- - true for the last item in a group - see note below
-
-- *length*- - length of the sequence, which will be the total number of
-  repetitions.
-
-- *letter*- - repetition number as a lower-case letter: "a" - "z", "aa" - "az",
-  "ba" - "bz", ..., "za" - "zz", "aaa" - "aaz", and so forth.
-
-- *Letter*- - upper-case version of - *letter*- .
-
-- *roman*- - repetition number as a lower-case roman numeral: "i", "ii", "iii",
-  "iv", "v", etc.
-
-- *Roman*- - upper-case version of - *roman*- .
-
-You can access the contents of the repeat variable using path expressions or
-Python expressions. In path expressions, you write a three-part path consisting
-of the name `repeat`, the statement variable's name, and the name of the
-information you want, for example, `repeat/item/start`. In Python expressions,
-you use normal dictionary notation to get the repeat variable, then attribute
-access to get the information, for example, "python:repeat['item'].start".
-
-With the exception of `start`, `end`, and `index`, all of the attributes of a
-repeat variable are methods. Thus, when you use a Python expression to access
-them, you must call them, as in "python:repeat['item'].length()".
-
-Note that `first` and `last` are intended for use with sorted sequences. They
-try to divide the sequence into group of items with the same value. If you
-provide a path, then the value obtained by following that path from a sequence
-item is used for grouping, otherwise the value of the item is used. You can
-provide the path by passing it as a parameter, as in::
-
-  python:repeat['item'].first(color)
-  
-or by appending it to the path from the repeat variable, as in
-"repeat/item/first/color".
-
-Examples
-++++++++
-
-Iterating over a sequence of strings::
-
-  <p tal:repeat="txt python: ('one', 'two', 'three')">
-    <span tal:replace="txt" />
-  </p>
-
-Inserting a sequence of table rows, and using the repeat variable to number the
-rows::
-
-  <table>
-    <tr tal:repeat="item context/cart">
-      <td tal:content="repeat/item/number">1</td>
-      <td tal:content="item/description">Widget</td>
-      <td tal:content="item/price">$1.50</td>
-    </tr>
-  </table>
-
-Nested repeats::
-
-  <table border="1">
-    <tr tal:repeat="row python:range(10)">
-      <td tal:repeat="column python:range(10)">
-        <span tal:define="x repeat/row/number; 
-                          y repeat/column/number; 
-                          z python:x*y"
-              tal:replace="string:$x * $y = $z">
-            1 * 1 = 1
-        </span>
-      </td>
-    </tr>
-  </table>
-
-
-Insert objects. Separate groups of objects by meta-type by drawing a rule
-between them::
-
-  <div tal:repeat="object objects">
-    <h2 tal:condition="repeat/object/first/meta_type"
-        tal:content="object/meta_type">Meta Type</h2>
-    <p tal:content="object/getId">Object ID</p>
-    <hr tal:condition="repeat/object/last/meta_type" />
-  </div>
-
-Note, the objects in the above example should already be sorted by meta-type.
-
-replace: Replace an element
-===========================
-
-Syntax
-++++++
-
-tal:replace syntax::
-
-  argument ::= (['text'] | 'structure') expression
-
-Description
-+++++++++++
-
-The `tal:replace` statement replaces an element with dynamic content. It
-replaces the statement element with either text or a structure (unescaped
-markup). The body of the statement is an expression with an optional type
-prefix. The value of the expression is converted into an escaped string if you
-prefix the expression with `text` or omit the prefix, and is inserted unchanged
-if you prefix it with `structure`. Escaping consists of converting "&amp;" to
-"&amp;amp;", "&lt;" to "&amp;lt;", and "&gt;" to "&amp;gt;".
-
-If the value is *nothing*, then the element is simply removed. If the value is
-*default*, then the element is left unchanged.
-
-Examples
-++++++++
-
-The two ways to insert the title of a template::
-
-  <span tal:replace="template/title">Title</span>
-  <span tal:replace="text template/title">Title</span>
-
-Inserting HTML/XML::
-
-  <div tal:replace="structure table" />
-
-Inserting nothing::
-
-  <div tal:replace="nothing">
-    This element is a comment.
-  </div>
-
-TALES Overview
-==============
-
-The *Template Attribute Language Expression Syntax* (TALES) standard describes
-expressions that supply TAL and METAL with data. TALES is *one* possible
-expression syntax for these languages, but they are not bound to this
-definition. Similarly, TALES could be used in a context having nothing to do
-with TAL or METAL.
-
-TALES expressions are described below with any delimiter or quote markup from
-higher language layers removed. Here is the basic definition of TALES syntax::
-
-  Expression  ::= [type_prefix ':'] String
-  type_prefix ::= Name
-
-Here are some simple examples::
-
-  a/b/c
-  path:a/b/c
-  nothing
-  path:nothing
-  python: 1 + 2
-  string:Hello, ${user/getUserName}
-
-The optional *type prefix* determines the semantics and syntax of the
-*expression string* that follows it. A given implementation of TALES can define
-any number of expression types, with whatever syntax you like. It also
-determines which expression type is indicated by omitting the prefix.
-
-If you do not specify a prefix, Zope assumes that the expression is a *path*
-expression.
-
-TALES Expression Types
-++++++++++++++++++++++
-
-These are the TALES expression types supported by Zope:
-
-- path expressions - locate a value by its path.
-
-- exists expressions - test whether a path is valid.
-
-- nocall expressions - locate an object by its path.
-
-- not expressions - negate an expression
-
-- string expressions - format a string
-
-- python expressions - execute a Python expression
-
-Built-in Names
-++++++++++++++
-
-These are the names always available to TALES expressions in Zope:
-
-- *nothing*- - special value used by to represent a - *non-value*- (e.g. void,
-  None, Nil, NULL).
-
-- *default*- - special value used to specify that existing text should not be
-  replaced. See the documentation for individual TAL statements for details on
-  how they interpret - *default*- .
-
-- *options*- - the - *keyword*- arguments passed to the template. These are
-  generally available when a template is called from Methods and Scripts,
-  rather than from the web.
-
-- *repeat*- - the repeat variables; see the tal:repeat documentation.
-
-- *attrs*- - a dictionary containing the initial values of the attributes of
-  the current statement tag.
-
-- *CONTEXTS*- - the list of standard names (this list). This can be used to
-  access a built-in variable that has been hidden by a local or global variable
-  with the same name.
-
-- *root*- - the system's top-most object: the Zope root folder.
-
-- *context*- - the object to which the template is being applied.
-
-- *container*- - The folder in which the template is located.
-
-- *template*- - the template itself.
-
-- *request*- - the publishing request object.
-
-- *user*- - the authenticated user object.
-
-- *modules*- - a collection through which Python modules and packages can be
-  accessed. Only modules which are approved by the Zope security policy can be
-  accessed.
-
-Note the names `root`, `context`, `container`, `template`, `request`, `user`, and
-`modules` are optional names supported by Zope, but are not required by the
-TALES standard.
-
-TALES Exists expressions
-========================
-
-Syntax
-++++++
-
-Exists expression syntax::
-
-  exists_expressions ::= 'exists:' path_expression
-
-Description
-+++++++++++
-
-Exists expressions test for the existence of paths. An exists expression
-returns true when the path expressions following it expression returns a value.
-It is false when the path expression cannot locate an object.
-
-Examples
-++++++++
-
-Testing for the existence of a form variable::
-
-  <p tal:condition="not:exists:request/form/number">
-    Please enter a number between 0 and 5
-  </p>
-
-Note that in this case you can't use the expression, `not:request/form/number`,
-since that expression will be true if the `number` variable exists and is zero.
-
-TALES Nocall expressions
-========================
-
-Syntax
-++++++
-
-Nocall expression syntax::
-
-  nocall_expression ::= 'nocall:' path_expression
-
-Description
-+++++++++++
-
-Nocall expressions avoid rendering the results of a path expression.
-
-An ordinary path expression tries to render the object that it fetches. This
-means that if the object is a function, Script, Method, or some other kind of
-executable thing, then expression will evaluate to the result of calling the
-object. This is usually what you want, but not always. For example, if you want
-to put a DTML Document into a variable so that you can refer to its properties,
-you can't use a normal path expression because it will render the Document into
-a string.
-
-Examples
-++++++++
-
-Using nocall to get the properties of a document::
-
-  <span tal:define="doc nocall:context/aDoc"
-        tal:content="string:${doc/getId}: ${doc/title}">
-    Id: Title
-  </span>
-
-Using nocall expressions on a functions::
-
-  <p tal:define="join nocall:modules/string/join">
-
-This example defines a variable:: `join` which is bound to the `string.join`
-function.
-
-TALES Not expressions
-=====================
-
-Syntax
-++++++
-
-Not expression syntax::
-
-  not_expression ::= 'not:' expression
-
-Description
-+++++++++++
-
-Not expression evaluates the expression string (recursively) as a full
-expression, and returns the boolean negation of its value. If the expression
-supplied does not evaluate to a boolean value, *not* will issue a warning and
-*coerce* the expression's value into a boolean type based on the following
-rules:
-
-1. the number 0 is *false*
-
-2. positive and negative numbers are *true*
-
-3. an empty string or other sequence is *false*
-
-4. a non-empty string or other sequence is *true*
-
-5. a #. *non-value*#. (e.g. void, None, Nil, NULL, etc) is *false*
-
-6. all other values are implementation-dependent.
-
-If no expression string is supplied, an error should be generated.
-
-Zope considers all objects not specifically listed above as *false* to be
-*true*.
-
-Examples
-++++++++
-
-Testing a sequence::
-
-  <p tal:condition="not:context/objectIds">
-    There are no contained objects.
-  </p>
-
-TALES Path expressions
-======================
-
-Syntax
-++++++
-
-Path expression syntax::
-
-  PathExpr    ::= Path [ '|' Expression ]
-  Path        ::= variable [ '/' PathSegment ]*
-  variable    ::= Name
-  PathSegment ::= ( '?' variable ) | PathChar+
-  PathChar    ::= AlphaNumeric | ' ' | '_' | '-' | '.' | ',' | '~'
-
-Description
-+++++++++++
-
-A path expression consists of a *path* optionally followed by a vertical bar
-(|) and alternate expression. A path consists of one or more non-empty strings
-separated by slashes. The first string must be a variable name (a built-in
-variable or a user defined variable), and the remaining strings, the *path
-segments*, may contain letters, digits, spaces, and the punctuation characters
-underscore, dash, period, comma, and tilde.
-
-A limited amount of indirection is possible by using a variable name prefixed
-with `?` as a path segment. The variable must contain a string, which replaces
-that segment before the path is traversed.
-
-For example::
-
-  request/cookies/oatmeal
-  nothing
-  context/some-file 2009_02.html.tar.gz/foo
-  root/to/branch | default
-  request/name | string:Anonymous Coward
-  context/?tname/macros/?mname
-
-When a path expression is evaluated, Zope attempts to traverse the path, from
-left to right, until it succeeds or runs out of paths segments. To traverse a
-path, it first fetches the object stored in the variable. For each path
-segment, it traverses from the current object to the sub-object named by the
-path segment. Sub-objects are located according to standard Zope traversal rules
-(via getattr, getitem, or traversal hooks).
-
-Once a path has been successfully traversed, the resulting object is the value
-of the expression. If it is a callable object, such as a method or template, it
-is called.
-
-If a traversal step fails, and no alternate expression has been specified, an
-error results. Otherwise, the alternate expression is evaluated.
-
-The alternate expression can be any TALES expression. For example::
-
-  request/name | string:Anonymous Coward
-
-is a valid path expression. This is useful chiefly for providing default
-values, such as strings and numbers, which are not expressible as path
-expressions. Since the alternate expression can be a path expression, it is
-possible to "chain" path expressions, as in::
-
-  first | second | third | nothing
-
-If no path is given the result is *nothing*.
-
-Since every path must start with a variable name, you need a set of starting
-variables that you can use to find other objects and values. See the TALES
-overview for a list of built-in variables. Variable names are looked up first
-in locals, then in globals, then in the built-in list, so the built-in
-variables act just like built-ins in Python; They are always available, but
-they can be shadowed by a global or local variable declaration. You can always
-access the built-in names explicitly by prefixing them with *CONTEXTS*. (e.g.
-CONTEXTS/root, CONTEXTS/nothing, etc).
-
-Examples
-++++++++
-
-Inserting a cookie variable or a property::
-
-  <span tal:replace="request/cookies/pref | context/pref">
-    preference
-  </span>
-
-Inserting the user name::
-
-  <p tal:content="user/getUserName">
-    User name
-  </p>
-
-TALES Python expressions
-========================
-
-Syntax
-++++++
-
-Python expression syntax::
-
-  Any valid Python language expression
-
-Description
-+++++++++++
-
-Python expressions evaluate Python code in a security-restricted environment.
-Python expressions offer the same facilities as those available in Python-based
-Scripts and DTML variable expressions.
-
-Security Restrictions
-~~~~~~~~~~~~~~~~~~~~~
-
-Python expressions are subject to the same security restrictions as
-Python-based scripts. These restrictions include:
-
-
-access limits
-  Python expressions are subject to Zope permission and role security
-  restrictions. In addition, expressions cannot access objects whose names
-  begin with underscore.
-
-write limits
-  Python expressions cannot change attributes of Zope objects.
-
-Despite these limits malicious Python expressions can cause problems.
-
-Built-in Functions
-~~~~~~~~~~~~~~~~~~
-
-Python expressions have the same built-ins as Python-based Scripts with a few
-additions.
-
-These standard Python built-ins are available:
-
-- None
-
-- abs
-
-- apply
-
-- callable
-
-- chr
-
-- cmp
-
-- complex
-
-- delattr
-
-- divmod
-
-- filter
-
-- float
-
-- getattr
-
-- hash
-
-- hex
-
-- int
-
-- isinstance
-
-- issubclass
-
-- list
-
-- len
-
-- long
-
-- map
-
-- max
-
-- min
-
-- oct
-
-- ord
-
-- repr
-
-- round
-
-- setattr
-
-- str
-
-- tuple
-
-The `range` and `pow` functions are available and work the same way they do in
-standard Python; however, they are limited to keep them from generating very
-large numbers and sequences. This limitation helps protect against denial of
-service attacks.
-
-These functions are available in Python expressions, but not in Python-based
-scripts:
-
-path(string)
-  Evaluate a TALES path expression.
-
-string(string)
-  Evaluate a TALES string expression.
-
-exists(string)
-  Evaluates a TALES exists expression.
-
-nocall(string)
-  Evaluates a TALES nocall expression.
-
-Python Modules
-~~~~~~~~~~~~~~
-
-A number of Python modules are available by default. You can make more modules
-available. You can access modules either via path expressions (for example
-`modules/string/join`) or in Python with the `modules` mapping object (for
-example `modules["string"].join`). Here are the default modules:
-
-string
-  The standard `Python string module
-  <http://www.python.org/doc/current/lib/module-string.html>`_ Note: most of
-  the functions in the module are also available as methods on string objects.
-
-random
-
-The standard 
-  `Python random module
-  <http://www.python.org/doc/current/lib/module-random.html>`_
-
-math
-  The standard `Python math module
-  <http://www.python.org/doc/current/lib/module-math.html>`_ .
-
-sequence
-  A module with a powerful sorting function. See sequence for more information.
-
-Products.PythonScripts.standard
-  Various HTML formatting functions available in DTML. See
-  Products.PythonScripts.standard for more information.
-
-ZTUtils
-  Batch processing facilities similar to those offered by `dtml-in`. See
-  ZTUtils for more information.
-
-AccessControl
-  Security and access checking facilities. See AccessControl for more
-  information.
-
-Examples
-++++++++
-
-Using a module usage (pick a random choice from a list)::
-
-  <span tal:replace="python:modules['random'].choice(
-                         ['one', 'two', 'three', 'four', 'five'])">
-    a random number between one and five
-  </span>
-
-String processing (capitalize the user name)::
-
-  <p tal:content="python:user.getUserName().capitalize()">
-    User Name
-  </p>
-
-Basic math (convert an image size to megabytes)::
-
-  <p tal:content="python:image.getSize() / 1048576.0">
-    12.2323
-  </p>
-
-String formatting (format a float to two decimal places)::
-
-  <p tal:content="python:'%0.2f' % size">
-    13.56
-  </p>
-
-TALES String expressions
-========================
-
-Syntax
-++++++
-
-String expression syntax::
-
-  string_expression ::= ( plain_string | [ varsub ] )*
-  varsub            ::= ( '$' Path ) | ( '${' Path '}' )
-  plain_string      ::= ( '$$' | non_dollar )*
-  non_dollar        ::= any character except '$'
-
-Description
-+++++++++++
-
-String expressions interpret the expression string as text. If no expression
-string is supplied the resulting string is *empty*. The string can contain
-variable substitutions of the form `$name` or `${path}`, where `name` is a
-variable name, and `path` is a path expression. The escaped string value of the
-path expression is inserted into the string. To prevent a `$` from being
-interpreted this way, it must be escaped as `$$`.
-
-Examples
-++++++++
-
-Basic string formatting::
-
-  <span tal:replace="string:$this and $that">
-    Spam and Eggs
-  </span>
-
-Using paths::
-
-  <p tal:content="string:total: ${request/form/total}">
-    total: 12
-  </p>
-
-Including a dollar sign::
-
-  <p tal:content="string:cost: $$$cost">
-    cost: $42.00
-  </p>
-
-METAL Overview
-==============
-
-The *Macro Expansion Template Attribute Language* (METAL) standard is a
-facility for HTML/XML macro preprocessing. It can be used in conjunction with
-or independently of TAL and TALES.
-
-Macros provide a way to define a chunk of presentation in one template, and
-share it in others, so that changes to the macro are immediately reflected in
-all of the places that share it. Additionally, macros are always fully
-expanded, even in a template's source text, so that the template appears very
-similar to its final rendering
-
-METAL Namespace
-+++++++++++++++
-
-The METAL namespace URI and recommended alias are currently defined as::
-
-  xmlns:metal="http://xml.zope.org/namespaces/metal"
-
-Just like the TAL namespace URI, this URI is not attached to a web page; it's
-just a unique identifier.
-
-Zope does not require an XML namespace declaration when creating templates with
-a content-type of `text/html`. However, it does require an XML namespace
-declaration for all other content-types.
-
-METAL Statements
-++++++++++++++++
-
-METAL defines a number of statements:
-
-- metal:define-macro - Define a macro.
-
-- metal:use-macro - Use a macro.
-
-- metal:define-slot - Define a macro customization point.
-
-- metal:fill-slot - Customize a macro.
-
-Although METAL does not define the syntax of expression non-terminals, leaving
-that up to the implementation, a canonical expression syntax for use in METAL
-arguments is described in TALES Specification.
-
-define-macro: Define a macro
-============================
-
-Syntax
-++++++
-
-metal:define-macro syntax::
-
-  argument ::= Name
-
-Description
-+++++++++++
-
-The `metal:define-macro` statement defines a macro. The macro is named by the
-statement expression, and is defined as the element and its sub-tree.
-
-In Zope, a macro definition is available as a sub-object of a template's
-`macros` object. For example, to access a macro named `header` in a template
-named `master.html`, you could use the path expression::
-
-  master.html/macros/header
-
-Examples
-++++++++
-
-Simple macro definition::
-
-  <p metal:define-macro="copyright">
-    Copyright 2009, <em>Foobar</em> Inc.
-  </p>
-
-
-define-slot: Define a macro customization point
-===============================================
-
-Syntax
-++++++
-
-metal:define-slot syntax::
-
-  argument ::= Name
-
-Description
-+++++++++++
-
-The `metal:define-slot` statement defines a macro customization point or
-*slot*. When a macro is used, its slots can be replaced, in order to customize
-the macro. Slot definitions provide default content for the slot. You will get
-the default slot contents if you decide not to customize the macro when using
-it.
-
-The `metal:define-slot` statement must be used inside a `metal:define-macro`
-statement.
-
-Slot names must be unique within a macro.
-
-Examples
-++++++++
-
-Simple macro with slot::
-
-  <p metal:define-macro="hello">
-    Hello <b metal:define-slot="name">World</b>
-  </p>
-
-This example defines a macro with one slot named `name`. When you use this
-macro you can customize the `b` element by filling the `name` slot.
-
-fill-slot: Customize a macro
-============================
-
-Syntax
-++++++
-
-metal:fill-slot syntax::
-
-  argument ::= Name
-
-Description
-+++++++++++
-
-The `metal:fill-slot` statement customizes a macro by replacing a *slot* in the
-macro with the statement element (and its content).
-
-The `metal:fill-slot` statement must be used inside a `metal:use-macro`
-statement. Slot names must be unique within a macro.
-
-If the named slot does not exist within the macro, the slot contents will be
-silently dropped.
-
-Examples
-++++++++
-
-Given this macro::
-
-  <p metal:define-macro="hello">
-    Hello <b metal:define-slot="name">World</b>
-  </p>
-
-You can fill the `name` slot like so::
-
-  <p metal:use-macro="container/master.html/macros/hello">
-    Hello <b metal:fill-slot="name">Kevin Bacon</b>
-  </p>
-
-use-macro: Use a macro
-======================
-
-Syntax
-++++++
-
-metal:use-macro syntax::
-
-  argument ::= expression
-
-Description
-+++++++++++
-
-The `metal:use-macro` statement replaces the statement element with a macro.
-The statement expression describes a macro definition.
-
-In Zope the expression will generally be a path expression referring to a macro
-defined in another template. See "metal:define-macro" for more information.
-
-The effect of expanding a macro is to graft a subtree from another document (or
-from elsewhere in the current document) in place of the statement element,
-replacing the existing sub-tree. Parts of the original subtree may remain,
-grafted onto the new subtree, if the macro has *slots*. See metal:define-slot
-for more information. If the macro body uses any macros, they are expanded
-first.
-
-When a macro is expanded, its `metal:define-macro` attribute is replaced with
-the `metal:use-macro` attribute from the statement element. This makes the root
-of the expanded macro a valid `use-macro` statement element.
-
-Examples
-++++++++
-
-Basic macro usage::
-
-  <p metal:use-macro="container/other.html/macros/header">
-    header macro from defined in other.html template
-  </p>
-
-This example refers to the `header` macro defined in the `other.html` template
-which is in the same folder as the current template. When the macro is
-expanded, the `p` element and its contents will be replaced by the macro. Note:
-there will still be a `metal:use-macro` attribute on the replacement element.
-
-ZPT-specific Behaviors
-======================
-
-The behavior of Zope Page Templates is almost completely described by the TAL,
-TALES, and METAL specifications. ZPTs do, however, have a few additional
-features that are not described in the standards.
-
-HTML Support Features
-+++++++++++++++++++++
-
-When the content-type of a Page Template is set to `text/html`, Zope processes
-the template somewhat differently than with any other content-type. As
-mentioned under TAL Namespace, HTML documents are not required to declare
-namespaces, and are provided with `tal` and `metal` namespaces by default.
-
-HTML documents are parsed using a non-XML parser that is somewhat more
-forgiving of malformed markup. In particular, elements that are often written
-without closing tags, such as paragraphs and list items, are not treated as
-errors when written that way, unless they are statement elements. This laxity
-can cause a confusing error in at least one case; a `<div>` element is
-block-level, and therefore technically not allowed to be nested in a `<p>`
-element, so it will cause the paragraph to be implicitly closed. The closing
-`</p>` tag will then cause a NestingError, since it is not matched up with the
-opening tag. The solution is to use `<span>` instead.
-
-Unclosed statement elements are always treated as errors, so as not to cause
-subtle errors by trying to infer where the element ends. Elements which
-normally do not have closing tags in HTML, such as image and input elements,
-are not required to have a closing tag, or to use the XHTML `<tag />` form.
-
-Certain boolean attributes, such as `checked` and `selected`, are treated
-differently by `tal:attributes`. The value is treated as true or false (as
-defined by `tal:condition`). The attribute is set to `attr="attr"` in the true
-case and omitted otherwise. If the value is `default`, then it is treated as
-true if the attribute already exists, and false if it does not. For example,
-each of the following lines::
-
-  <input type="checkbox" checked tal:attributes="checked default">
-  <input type="checkbox" tal:attributes="checked string:yes">
-  <input type="checkbox" tal:attributes="checked python:42">
-
-will render as::
-
-  <input type="checkbox" checked="checked">
-
-while each of these::
-
-  <input type="checkbox" tal:attributes="checked default">
-  <input type="checkbox" tal:attributes="checked string:">
-  <input type="checkbox" tal:attributes="checked nothing">
-
-will render as::
-
-  <input type="checkbox">
-
-This works correctly in all browsers in which it has been tested.
-

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/AppendixD.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/AppendixD.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/AppendixD.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,72 +0,0 @@
-Appendix D: Zope Resources
-##########################
-
-At the time of this writing there is a multitude of sources for Zope
-information on the Internet and in print. We've collected a number of the most
-important links which you can use to find out more about Zope.
-
-Zope Web Sites
-==============
-
-`Zope.org <http://www.zope.org>`_ is the official Zope website. It has
-downloads, documentation, news, and lots of community resources.
-
-`DZUG <http://dzug.org/>`_ was started as the main community site for the
-German Zope community and combines documentation translated to German,
-downloads, a portal for the various regional German Zope User Groups as well as
-information about Zope-related events in Europe.
-
-`Zope Italia <http://www.zope.it/>`_ forms the focal point for the Italian Zope
-community with news, events information and local Zope group contacts.
-
-Zope Documentation
-==================
-
-`ZopeWiki - A wiki for the Zope community <http://zopewiki.org/>`_ is a
-community-run Zope documentation website set up by Simon Michael, author of the
-famus ZWiki wiki product for Zope.
-
-`Zope Developer's Guide <http://www.zope.org/DocProjects/DevGuide>`_ teaches
-you how to write Zope products. It is somewhat outdated but cotains some
-nuggets you don't find elsewhere.
-
-(Other) Zope Books
-==================
-
-`The Zope Bible
-<http://www.amazon.com/exec/obidos/ASIN/0764548573/qid=1030511472/sr=2-1/ref=sr_2_1/002-3988880-4512056>`_
-by Scott Robertson and Michael Bernstein.
-
-`The Book of Zope
-<http://www.amazon.com/exec/obidos/ASIN/1886411573/qid=1030511472/sr=2-2/ref=sr_2_2/002-3988880-4512056>`_
-by Beehive.
-
-`The Zope Web Application Construction Kit
-<http://www.amazon.com/exec/obidos/tg/detail/-/0672321335/qid=1030511472/sr=1-5/ref=sr_1_5/002-3988880-4512056?v=glance&amp;s=books>`_
-edited by Martina Brockman, et. al.
-
-`Zope: Web Application Development and Content Management
-<http://www.amazon.com/exec/obidos/tg/detail/-/0735711100/qid=1030511472/sr=1-2/ref=sr_1_2/002-3988880-4512056?v=glance&amp;s=books>`_
-edited by Steve Spicklemire et al.
-
-`Zope: Timely, Practical, Reliable
-<http://www.amazon.com/exec/obidos/tg/detail/-/0470844515/ref=ase_zopezone-20/102-5632760-7919306?v=glance&s=books>`_
-written by Pierre Julien Grizel.
-
-`The Zope Book
-<http://www.amazon.com/exec/obidos/ASIN/0735711372/zopezone-20/102-5632760-7919306>`_
-is the hardcover version of the original edition Zope Book on which this text
-is based.
-
-Mailing Lists
-=============
-
-`mail.zope.org <http://www.zope.org/Resources/MailingLists>`_ maintains a collection
-of the many Zope mailing lists.
-
-Python Information
-==================
-
-`Python.org <http://www.python.org>`_ has lots of information about Python
-including a tutorial and reference documentation.
-

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/AppendixE.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/AppendixE.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/AppendixE.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,49 +0,0 @@
-Appendix E: DTML Name Lookup Rules
-##################################
-
-These are the rules which DTML uses to resolve names mentioned in `name=` and
-`expr=` tags. The rules are in order from first to last in the search path.
-
-The DTML call signature is as follows::
-
-  def __call__(client=None, mapping={}, **kw)
-
-The `client` argument is typically unreferenced in the body of DTML text, but
-typically resolves to the "context" in which the method was called (for
-example, in the simplest case, its client is the folder in which it lives).
-
-The `mapping` argument is typically referred to as `_` in the body of DTML
-text.
-
-The keyword arguments (i.e. `**kw` ) are referred to by their respective names
-in the body of DTML text.
-
-1. The keyword arguments are searched.
-
-2. The mapping object is searched.
-
-3. Attributes of the client, including inherited and acquired attributes, are
-   searched.
-
-4. If DTML is used in a Zope DTML Method or Document object and the variable
-   name is `document_id` or `document_title`, then the id or title of the
-   document or method is used.
-
-5. Attributes of the folder containing the DTML object (its container) are
-   searched. Attributes include objects in the contents of the folder,
-   properties of the folder, and other attributes defined by Zope, such as
-   `ZopeTime`. Folder attributes include the attributes of folders containing
-   the folder, with contained folders taking precedence over containing
-   folders.
-
-6. User-defined Web-request variables (ie. in the REQUEST.other namespace) are
-   searched.
-
-7. Form-defined Web-request variables (ie. in the REQUEST.form namespace) are
-   searched.
-
-8. Cookie-defined Web-request variables (ie. in the REQUEST.cookies namespace)
-   are searched.
-
-9. CGI-defined Web-request variables (ie. in the REQUEST.environ namespace) are
-   searched.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/BasicObject.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/BasicObject.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/BasicObject.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,688 +0,0 @@
-Using Basic Zope Objects
-########################
-
-When building a web application with Zope, you construct the application
-with *objects*.  The most fundamental Zope objects are explained in this
-chapter.
-
-Basic Zope Objects
-==================
-
-Zope ships with objects that help you perform different tasks. By design,
-different objects handle different parts of your application.  Some objects
-hold your content data, such as word processor documents, spreadsheets, and
-images.  Some objects handle your application's logic by accepting input
-from a web form, or by executing a script.  Some objects control the way
-your content is displayed, or *presented* to your viewer, for example, as a
-web page or via email.
-
-In general, basic Zope objects take on one of three types of roles:
-
-Content
-  Zope objects like documents, images, and files hold different kinds of
-  textual and binary data.  In addition to objects in Zope containing
-  content, Zope can work with content stored externally, such as
-  information in a relational database.
-
-Presentation
-  You can control the look and feel of your site with Zope objects that act
-  as web page "templates". Zope comes with two facilities to help you
-  manage presentation: Zope Page Templates (ZPT) and Document Templates
-  (DTML). In the first part of the book we will only cover page templates
-  and later on expand on document templates. If you already know HTML, page
-  templates are easier to work with and more limited in their options. For
-  some of the more advanced tasks DTML can be a better option as explained
-  later on.
-
-Logic
-  Scripting business logic in Zope is done using Python. "Logic" is any kind of
-  programming that does not involve presentation, but rather involves the
-  carrying out of tasks such as changing objects, sending messages, testing
-  conditions, and responding to events.
-
-Zope also has other kinds of objects that fit into none of these categories,
-which are explored further in the chapter entitled `Zope Services
-<ZopeServices.html>`_. You may also install "third party" Zope objects ,
-defined in Python packages, to expand Zope's capabilities. You can browse a
-list of packages specifically aimed at Zope at the
-`Python Package Index <http://pypi.python.org/pypi?:action=browse&c=514>`_.
-
-
-Content Objects: Folders, Files, and Images
-===========================================
-
-Folders
--------
-
-You've already met one of the fundamental Zope objects: the *Folder*.
-Folders are the basic building blocks of Zope. The purpose of a folder is
-simple: a Folder's only job in life is to *contain* other objects.
-
-Folders can contain any other kind of Zope object, including other folders.
-You can nest folders inside each other to form a tree of folders.  This
-kind of "folder within a folder" arrangement provides your Zope site with
-*structure*.  Good structure is very important, as Zope security and
-presentation is influenced by your site's folder structure.  Folder
-structure should be very familiar to anyone who has worked with files and
-folders on their computer using a file manager like Microsoft *Windows
-Explorer*.
-
-Files
------
-
-Zope Files contain raw data, just as the files on your computer do.
-Software, audio, video and documents are typically transported around the
-Internet and the world as files. A Zope File object is an analogue to these
-kinds of files.  You can use Files to hold any kind of information that
-Zope doesn't specifically support, such as Flash files, audio files,
-"tarballs", etc. 
-
-Files do not consider their contents to be of any special format, textual
-or otherwise.  Files are good for holding any kind of *binary content*,
-which is just raw computer information of some kind. Files are also good
-for holding textual content if the content doesn't necessarily need to be
-edited through the web.
-
-Every File object has a particular *content type*, which is a standard
-Internet MIME designation for different categories of content. Examples of
-content types are "text/plain" (plain text content), "text/html" (html text
-content), and "application/pdf" (an Adobe Portable Document Format file).
-When you upload a file into Zope, Zope tries to guess the content type from
-the name of the file.
-
-Creating and Editing Files
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To create a File object in your Zope instance, visit the root folder in the
-ZMI and choose *File* from Zope's Add list.  Before filling out the "id" or
-"title" of the File object, click the *Browse* button from the resulting
-"Add File" screen.  This should trigger your browser to display a dialog
-box that allows you to choose a "real" file from your local computer, which
-will be uploaded to Zope when the "Add" button on the "Add File" form is
-selected.  Try choosing a file on your local computer, such as a Word file
-(.doc) or a Portable Document Format (.pdf) file.
-
-.. figure:: ../Figures/addfile.jpg
-
-   Adding a PDF File Object
-
-Zope attempts to use the filename of the file you choose to upload as the
-File object's 'id' and 'title', thus you don't need to supply an 'id' or
-'title' in the "Add File" form unless you want the File object to be named
-differently than the filename of the file on your local computer.  After
-you select a file to upload, click *Add*.  Depending on the size of the
-file you want to upload, it may take a few minutes to add the file to Zope.
-
-After you add the File, a File object with the name of the file on your
-local computer will appear in the Workspace pane.  Look at its *Edit* view.
-Here you will see that Zope has guessed the content type, as shown in the
-figure below.
-
-.. figure:: ../Figures/fileobject.jpg
-
-   Editing an Uploaded PDF File Object
-
-If you add a Word document, the content type is *application/msword*.  If
-you add a PDF file, the content type is *application/pdf*.  If Zope does
-not recognize the file type, it chooses the default, generic content type
-of *application/octet-stream*.  Zope doesn't always guess correctly, so the
-ability to change the content type of a File object is provided in the
-object editing interface.  To change the content type of a File object,
-type the new content type into the *Content Type* field and click the *Save
-Changes* button.
-
-You can change the contents of an existing File object by selecting a new
-file from your local filesystem in the *File Data* form element and
-clicking *Upload*.
-
-Editing Text File Contents
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If your File holds only text and is smaller than 64 kilobytes, Zope will
-allow you to edit its contents in a textarea within the Edit view of the
-ZMI. A text file is one that has a content-type that starts with *text/*,
-such as *text/html*, or *text/plain*.
-
-Viewing Files
-~~~~~~~~~~~~~
-
-You can view a file in the Workspace frame by clicking the *View* tab in a
-File object's management screen. 
-
-.. figure:: ../Figures/viewingfile.jpg
-
-   Viewing an Uploaded PDF File Object
-
-You can also view a File by visiting its Zope URL.  For example, if you
-have a file in your Zope root folder called *Reader.pdf*, you can view that
-file in your web browser via the URL *http://localhost:8080/Reader.pdf*.
-Depending on the type of file and your web browser's configuration, your
-web browser may choose to display or download the file.
-
-Images 
-------
-
-Image objects contain the data from image files, such as GIF, JPEG, and PNG
-files. In Zope, Images are very similar to File objects, except that they
-include extra behavior for managing graphic content, such as an image's
-width and height attributes.
-
-Image objects use the same management interface as File objects.
-Everything in the previous section about using file objects also applies to
-images. In addition, Image objects display a preview of their images once
-they have been uploaded to Zope.
-
-Presentation Objects:  Zope Page Templates
-==========================================
-
-Zope encourages you to keep your presentation and logic separate by
-providing different objects that are intended to be used expressly for
-"presentation".  "Presentation" is defined as the task of dynamically
-defining layout of web pages and other user-visible data.  Presentation
-objects typically render HTML (and sometimes XML).
-
-Zope has one "presentation" facility: *Zope Page Templates* (ZPT). Zope Page
-Templates are objects that allow you to define dynamic presentation for a web
-page. The HTML in your template is made dynamic by inserting special XML
-namespace elements into your HTML that define the dynamic behavior for that
-page.
-
-ZPT has characteristics of a "server-side" scripting language, like SSI, PHP or
-JSP. This means that ZPT commands are executed by Zope on the server, and the
-result of that execution is sent to your web browser. By contrast, client-side
-scripting languages, like Javascript, are not processed by the server, but are
-rather sent to and executed by your web browser.
-
-Zope also has an older version of a presentation facility included, which is
-called *Document Template Markup Language* or short DTML.
-
-ZPT vs. DTML: Same Purpose, Different Approach
-----------------------------------------------
-
-There is a major problem with many languages designed for the purpose of
-creating dynamic HTML content: they don't allow for "separation of
-presentation and logic" very well.  For example, "tag-based" scripting
-languages, like DTML, SSI, PHP, and JSP, encourage programmers to embed
-special tags into HTML that are, at best, mysterious to graphics designers
-who "just want to make the page look good" and don't know (or want to
-know!) a lot about creating an application around the HTML that they
-generate.  Worse, these tags can sometimes cause the HTML on which the
-designer has been working to become "invalid" HTML, unrecognizable by any
-of his or her tools.
-
-Typically, when using these kinds of technologies, an HTML designer will
-"mock up" a page in a tool like Macromedia Dreamweaver or Adobe GoLive, and
-then hand it off to a web programmer, who will decorate the page with
-special tags to insert dynamic content.  However, using tag-based scripting
-languages, this is a "one way" workflow: if the presentation ever needs to
-change, the programmer cannot just hand back the page that has been
-"decorated" with the special tags, because these tags will often be ignored
-or stripped out by the designer's tools.  One of several things needs to
-happen at this point to enact the presentation changes:
-
-- the designer mocks up a new page and the programmer re-embeds the dynamic
-  tags "from scratch", or
-
-- the designer hand-edits the HTML, working around the dynamic tags, or
-
-- the programmer does the presentation himself.
-
-Clearly, none of these options are desirable, because neither the
-programmer nor the designer are doing the things that they are best at in
-the most efficient way.
-
-Zope's original dynamic presentation language was DTML.  It soon became
-apparent that DTML was great at allowing programmers to quickly generate
-dynamic web pages, but it failed to allow programmers to work
-effectively together with non-technical graphics designers.  Thus, ZPT was
-born.  ZPT is an "attribute-based" presentation language that tries to
-allow for the "round-tripping" of templates between programmers and
-non-technical designers.
-
-DTML is still fully supported in Zope. If you are familiar with PHP it might
-fit your mind better then ZPT. For some of the advanced topics covered later
-in the book, like relation database integration or more uncommon tasks like
-dynamic generation of non-xml files, DTML can be easier to work with.
-
-Zope Page Templates
--------------------
-
-Zope Page Templates (ZPTs) are typically used to create dynamic HTML pages.
-
-Creating a Page Template
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Create a Folder with the 'id' *Sales* in the root folder, and give it any
-title you like.  Enter the Sales folder by clicking on it, then select
-*Page Template* from the Add list.  The Add form for a page template will
-be displayed.  Specify the 'id' "SalesPage" and click *Add*.  You have
-successfully created a page template whose content is standard
-"boilerplate" text at this point.
-
-Editing a Page Template
-~~~~~~~~~~~~~~~~~~~~~~~
-
-The easiest way to edit a page template is by clicking on its name or icon
-in the ZMI.  When you click on either one of those items, you are taken to
-the *Edit* view of the page template, which displays a textarea in which
-you can edit the template.  Click on the "SalesPage" template.  You will
-see something like the following screen:
-
-.. figure:: ../Figures/salespage.jpg
-
-   Default Page Template Content
-
-Replace the original, boilerplate content included in the page template
-with the following HTML::
-
-  <html>
-    <body>
-      <h1>This is my first page template!</h1>
-    </body>
-  </html>
-
-Then click *Save Changes* at the bottom of the edit form.
-
-Uploading a Page Template
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you'd prefer not to edit your HTML templates in a web browser, or you
-have some existing HTML pages that you'd like to bring into Zope, Zope
-allows you to upload your existing html files and convert them to page
-templates.
-
-Create a text file on your local computer named 'upload_pt.html'.  Populate
-it with the following content::
-
-  <html>
-    <body>
-      <h1>This is my second page template!</h1>
-    </body>
-  </html>
-
-While in the Sales folder, choose *Page Template* from the add menu, which
-will cause the page template Add form to be displayed.  The last form
-element on the add form is the *Browse* button.  Click this button, and
-your browser will display a file selection dialog.  CHoose the
-'upload_pt.html' file, type in an 'id' of "upload_pt" for the new Page
-Template, and click *Add and Edit*.  After uploading your file, you will be
-taken back to the Edit form of your new page template.
-
-Viewing a Page Template
-~~~~~~~~~~~~~~~~~~~~~~~
-
-You can view a Page Template in the Workspace frame by clicking the *Test*
-tab from the template's management screen.  Click the *Test* tab of the
-SalesPage template, and you will see something like the following figure:
-
-.. figure:: ../Figures/viewingpt.png
-
-   Viewing a Page Template
-
-You can also view a Page Template by visiting its Zope URL directly.
-
-
-Logic Objects:  Script (Python) Objects
-=======================================
-
-"Logic" objects in Zope are objects that typically perform some sort of
-"heavy lifting" or "number crunching" in support of presentation objects.
-When they are executed, they need not return HTML or any other sort of
-structured presentation text.  Instead, they might return values that are
-easy for a presentation object to format for display.  For example, a logic
-object may return a "list" of "strings".  Then, a presentation object may
-"call in" to the logic object and format the results of the call into a
-one-column HTML table, where the rows of the table are populated by the
-strings.  Instead of embedding logic in a presentation object, you can (and
-should) elect to move the logic into a logic object, using a presentation
-object only to format the result for display.  In this manner, you can
-change or replace the presentation object without needing to "re-code" or
-replace the logic.
-
-Note that logic objects, like presentation and content objects, are also
-addressable directly via a URL, and *may* elect to return HTML, which can
-be displayed meaningfully in a browser.  However, the return value of a
-logic object can almost always be displayed in a browser, even if the logic
-object does not return HTML.
-
-There is one kind of logic objects supported by stock Zope: *Script (Python)*
-objects.
-
-The stock logic objects are written in the syntax of the *Python* scripting
-language. Python is a general-purpose programming language. You are encouraged
-to read the `Python Tutorial <http://docs.python.org/tutorial/>`_
-in order to understand the syntax and semantics of the example Script (Python)
-objects shown throughout this chapter and throughout this book. And don't
-panic: Python is very easy to learn and understand.
-
-One important Python feature that must be mentioned here, however: Python uses
-whitespace in the form of indentation to denote block structure. Where other
-languages, such as C, Perl, and PHP might use "curly braces" -- "{" and "}" --
-to express a block of code, Python determines code blocks by examining the
-indentation of code text. If you're used to other programming languages, this
-may take some "getting-used-to" (typically consisting of a few hours of
-unsavory spoken language ;-) ). If you have problems saving or executing Script
-objects, make sure to check your Script's indentation.
-
-Script (Python) Objects
------------------------
-
-Script (Python) objects are one type of logic object.  Note that the
-tortuous form of their name (as opposed to "Python Script") is unfortunate:
-a legal issue prevents Zope Corporation from naming them "Python Scripts",
-but most folks at Zope Corporation and in the Zope community refer to them
-in conversation as just that.
-
-Script (Python) objects are "security-constrained", web-editable pieces of
-code that are written in a subset of the Python scripting language.  Not
-all Python code is executable via a Script (Python) object.  Script
-(Python) objects are constrained by Zope's *security policy*, which means,
-for the most part, that they are unable to import all but a defined set of
-restricted Python modules, and that they cannot directly access files on
-your file system.  This is a security feature, as it allows site
-administrators to safely delegate the ability to create logic in Python to
-untrusted or "semi-trusted" users.  For more information about Zope's
-security features, see `Users and Security <Security.html>`_.
-
-Creating a Script (Python)
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Enter the Sales folder you created earlier by clicking on it, then select
-*Script (Python)* from the Add list.  The Add form for the object will be
-displayed.  Specify the 'id' "SalesScript" and click *Add*.  You will see
-an entry in the Sales folder Content view representing the "SalesScript"
-Script (Python) object, whose content is standard, boilerplate text at this
-point.
-
-Editing a Script (Python)
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The easiest way to edit a Script (Python) is by clicking on its name or
-icon in the ZMI: when you click on either of these items, you are taken to
-the *Edit* view of the Script (Python), which gives you a textarea in which
-you can edit the template.  Click on the 'SalesScript' icon.  You will see
-something like the following:
-
-.. figure:: ../Figures/scriptdefault.png
-
-   Default Script Content
-
-In the *Parameter List* form element, type 'name="Chris"'.
-
-Replace the original content that comes in the "body" (the big TEXTAREA
-below the 'Last Modified' line) of the Script (Python) object with the
-following text::
-
-   return 'Hello, %s from the SalesScript script' % name
-
-Then click *Save Changes* at the bottom of the edit form. You can now
-execute, or test, your Script (Python) object.
-
-Testing a Script (Python)
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can test a Script (Python) in the Workspace frame by clicking the
-*Test* tab from the Script's management screen.  When you test a script,
-the output of the script will be displayed in your browser.  Script testing
-may require that you provide values for the script's *parameters* before
-you can view the results.  Click the *Test* tab of the SalesScript object,
-and you will see something like the following figure:
-
-.. figure:: ../Figures/testscript.png
-
-   Testing a Script
-
-In the Value box next to the 'name' parameter, enter your name, and then
-click "Run Script".  You will be presented with output in the Workspace
-frame not unlike::
-
-   Hello, [yourname] from the SalesScript script
-
-If a Script does not require parameters or has defaults for its parameters
-(as does the example above), you may visit its URL directly to see its
-output.  In our case, visiting the URL of SalesScript directly in your
-browser will produce::
-
-   Hello, Chris from the SalesScript script
-
-If a Script *does* require or accept parameters, you may also influence its
-execution by visiting its URL directly and including a "query string".  In
-our case, visiting the URL
-'http://localhost:8080/Sales/SalesScript?name=Fred' will produce the
-following output::
-
-   Hello, Fred from the SalesScript script
-
-Zope maps query string argument values to their corresponding parameters
-automatically, as you can see by this output.
-
-Uploading a Script (Python)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Uploading the body of a Script (Python) object is much like uploading the
-body of a Page Template.  One significant difference is that
-Script (Python) objects interpret text that is offset by "double-pound"
-('##') at the beginning of the text as data about their parameters, title,
-and "bindings".  For example, if you entered the following in a text editor
-and uploaded it, the lines that start with "double-pound" signs would be
-interpreted as parameter data, and the only text in the "body" would be the
-'return' line.  It would appear exactly as our SalesScript did::
-
-  ## Script (Python) "SalesScript"
-  ##bind container=container
-  ##bind context=context
-  ##bind namespace=
-  ##bind script=script
-  ##bind subpath=traverse_subpath
-  ##parameters=name="Chris"
-  ##title=
-  ##
-  return 'Hello, %s from the SalesScript script' % name
-
-You may see this view of a Script (Python) object by clicking on the 'view
-or download' link in the description beneath the "body" textarea.
-
-You may also type the "double-pound" quoted text into the "body" textarea,
-along with the actual script lines, and the "double-pound" quoted text will
-be "auto-magically" turned into bindings and parameters for the Script
-(Python) object.
-
-SQL Methods:  Another Kind of Logic Object
-------------------------------------------
-
-*SQL Methods* are logic objects used to store and execute database queries
-that you can reuse in your web applications.  We don't explain them in this
-chapter, because we haven't yet explained how to interface Zope with a
-relational database.  SQL Methods are explained in the chapter entitled
-`Relational Database Connectivity <RelationalDatabases.html>`_, where an
-example of creating a web application using a relational database is given.
-
-Creating a Basic Zope Application Using Page Templates and Scripts
-==================================================================
-
-Here is a simple example of using Zope's logic and content objects to build
-an online web form to help your users calculate the amount of compound
-interest on their debts.  This kind of calculation involves the following
-procedure:
-
-1. You need the following information: your current account balance (or
-   debt), called the "principal"; the annual interest rate expressed as a
-   decimal (like 0.095), called the "interest_rate"; the number of times
-   during the year that interest is compounded (usually monthly), called
-   the "periods"; and the number of years from now you want to calculate,
-   called the "years".
-
-2. Divide your "interest_rate" by "periods" (usually 12). We'll call this
-   result "i".
-
-3. Take "periods" and multiply it by "years".  We'll call this result "n".
-
-4. Raise (1 + "i") to the power "n".
-
-5. Multiply the result by your "principal". This is the new balance (or
-   debt).
-
-We will use Page Template and Script (Python) objects to construct an
-application to perform this task.
-
-For this example, you will need two Page Templates with the 'ids'
-*interestRateForm* and *interestRateDisplay*, respectively, to collect and
-display information from the user.  You will also need a Script (Python)
-object with an 'id' of *calculateCompoundingInterest* that will do the
-actual calculation.
-
-The first step is to create a folder in which to hold the application.  In
-your Zope's root folder, create a folder with the 'id' "Interest".  You
-will create all of the objects that follow within this folder.
-
-Creating a Data Collection Form
--------------------------------
-
-Visit the 'Interest' folder by clicking on it within the Zope Management
-Interface.  Within the 'Interest' folder, create a Page Template with the
-'id' *interestRateForm* that collects "principal", "interest_rate",
-"periods", and "years" from your users.  Use this text as the body of your
-*interestRateForm* page template::
-
-  <html>
-    <body>
-
-    <form action="interestRateDisplay" method="POST">
-    <p>Please enter the following information:</p>
-
-    Your current balance (or debt): <input name="principal:float"><br>
-    Your annual interest rate: <input name="interest_rate:float"><br>
-    Number of periods in a year: <input name="periods:int"><br>
-    Number of years: <input name="years:int"><br>
-    <input type="submit" value=" Calculate "><br>
-    </form>
-
-    </body>
-  </html>
-
-This form collects information and, when it is submitted, calls the
-*interestRateDisplay* template (which we have not yet created).
-
-Creating a Script To Calculate Interest Rates
----------------------------------------------
-
-Now, revisit the Contents view of the *Interest* folder and create a Script
-(Python) object with the id *calculateCompoundingInterest* that accepts
-four parameters: 'principal', 'interest_rate', 'periods', and 'years'.
-Provide it with the following "body"::
-
-  """ 
-  Calculate compounding interest.
-  """
-  i = interest_rate / periods
-  n = periods * years
-  return ((1 + i) ** n) * principal 
-
-Remember: you enter the parameter names, separated by commas, into the
-*Parameters List* field, and the body into the body text area.  Remember
-also that when you're creating a Script (Python) object, you're actually
-programming in the Python programming language, which is
-indentation-sensitive.  Make sure each of the lines above line up along the
-left side of the text area, or you may get an error when you attempt to
-save it.
-
-Creating a Page Template To Display Results
--------------------------------------------
-
-Next, go back to the Contents view of the *Interest* folder and create a
-Page Template with the id *interestRateDisplay*.  This Page Template is
-**called by** *interestRateForm* and **calls**
-*calculateCompoundingInterest*.  It also renders and returns the results::
-
-  <html>
-    <body>
-    Your total balance (or debt) including compounded interest over
-    <span tal:define="years request/years;
-                      principal request/principal;
-                      interest_rate request/interest_rate;
-                      periods request/periods">
-      <span tal:content="years">2</span> years is:<br><br>
-      <b>$
-      <span tal:content="python: context.calculateCompoundingInterest(principal, 
-                                                       interest_rate,
-                                                       periods,
-                                                       years)" >1.00</span>
-      </b>
-    </span>
-    </body>
-  </html>
-
-Dealing With Errors
--------------------
-
-As in any programming venue, you will need to deal with errors.  Nobody's
-perfect!  You may have already encountered some errors as you entered these
-scripts.  Let's explore errors a bit by way of an example.  In our case, we
-cannot use the Page Template *Test* tab to test the *interestRateDisplay*
-without receiving an error, because it depends on the *interestRateForm* to
-supply it with the variables "years, "principal", "interest_rate", and
-"periods".  Thus, it is not directly "testable".  For the sake of "seeing
-the problem before it happens for real", click the *Test* tab.  Zope will
-present an error page with text not unlike the following text::
-
-    Site Error
-
-    An error was encountered while publishing this resource.
-
-    Error Type: KeyError
-    Error Value: years
-
-This error message is telling you that your Page Template makes a reference
-to a variable "years" that it can't find.  You can view the full error by
-visiting the *error_log* object and clicking the top-most error log entry,
-which will be named *KeyError: years* in the *Log* tab.  The error log
-entry contains information about the error, including the time, the user
-who received the error, the URL that caused the error to happen, the
-exception type, the exception value, and a "Traceback", which typically
-gives you enough technical information to understand what happened.  In our
-case, the part of the traceback that is interesting to us is::
-
-   * Module Products.PageTemplates.TALES, line 217, in evaluate
-     URL: /Interest/interestRateDisplay
-     Line 4, Column 8
-     Expression: standard:'request/years'
-
-This tells us that the failure occurred when the Page Template attempted to
-access the variable 'request/years'.  We know why: there is no variable
-'request/years', because that variable is only "filled in" as a result of
-posting via our *interestRateForm*, which calls in to our
-*interestRateDisplay* Page Template, which has the effect of inserting the
-variables 'principal', 'interest_rate', 'periods', and 'years' into the
-'request' "namespace".  We'll cover Page Template namespaces in a
-succeeding chapter.
-
-Using The Application
----------------------
-
-Let's use the application you've just created.  Visit the
-*interestRateForm* Page Template and click the *Test* tab.
-
-Type in '20000' for balance or debt, '.06' for interest rate, '4' for
-periods in a year, and '20' for number of years, and then click
-*Calculate*.  This will cause *interestRateForm* to submit the collect
-information to *interestRateDisplay*, which calls the Script (Python)
-object named *calculateCompoundingInterest*.  The display method uses the
-value returned by the script in the resulting display.  You will see the
-following result:
-
-.. figure:: ../Figures/interestdisplay.png
-
-   Result of the Interest Application
-
-If you see something close to this, it calls for congratulations, because
-you've just built your first Zope application successfully!  If you are
-having trouble, try to troubleshoot the application by using the tips in
-the section "Dealing With Errors."  If you're stuck entirely, it's
-advisable that you send a message to the `Zope mailing list
-<mailto:zope at zope.org>`_ detailing the problem that you're having as
-concisely and clearly as possible.  It is likely that someone there will be
-able to help you, and it is polite to subscribe to the Zope mailing list
-itself if you want to receive replies.  See the `Mailing list
-section <http://www.zope.org/Resources/MailingLists>`_ of Zope.org for
-information about how to subscribe to the Zope (zope at zope.org) mailing
-list.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/BasicScripting.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/BasicScripting.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/BasicScripting.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,725 +0,0 @@
-Basic Zope Scripting
-####################
-
-So far, you've learned about some basic Zope objects and how to manage them
-through the *Zope Management Interface*. This chapter shows you how to manage
-Zope objects programmatically.
-
-
-Calling Methods From the Web
-============================
-
-Since Zope is a web application server, the easiest way to communicate with
-Zope is through a web browser. Any URL your browser requests from the server is
-mapped to both an object and a method. The method is executed *on* the object,
-and a response is sent to your browser.
-
-As you might already know, visiting the URL :: 
-
-  http://localhost:8080/
-
-returns the *Zope Quick Start* page. In this case, we only specify an object --
-the *root* object -- but no method. This just works because there is a default
-method defined for *Folders*: *index_html*. Visiting the URL::
-
-  http://localhost:8080/index_html
-
-returns (almost) exactly the same page.
-
-You can also specify the root object as:: 
-
-  http://localhost:8080/manage_main
-
-but in this case the *manage_main* method is called, and the workspace frame
-displays the root content of your Zope site, without the navigator frame.
-
-The same method can be called *on* other objects: when you visit the URL::
-
-  http://localhost:8080/Control_Panel/manage_main
-
-the *manage_main* method is called *on* the *Control Panel* object.
-
-Sometimes a query string is added to the URL, e.g.:: 
-
-  http://localhost:8080/manage_main?skey=meta_type
-
-The query string is used for passing arguments to the method. In this case, the
-argument::
-
-  skey
-
-specifies the sort key with the value *meta_type*. Based on this argument, the
-*manage_main* method returns a modified version of the basic page: the
-sub-objects are sorted by *Type*, not by *Name* as they are without that query
-string.
-
-While the *manage_main* method is defined in the class of the object,
-*index_html* is (by default) a DTML Method object in the root folder that can
-be modified through the web. *index_html* itself is a presentation object, but
-when called *on* a folder, it behaves as a method that returns the default view
-of the folder.
-
-Method Objects and Context Objects
-++++++++++++++++++++++++++++++++++
-
-When you call a method, you usually want to single out some object that is
-central to the method's task, either because that object provides information
-that the method needs, or because the method will modify that object. In
-`object-oriented <ObjectOrientation.stx>`_ terms, we want to call the method
-*on* this particular object. But in conventional object-oriented programming,
-each object can perform the methods that are defined in (or inherited by) its
-class. How is it that one Zope object can be used as a method for (potentially)
-many other objects, without its being defined by the classes that define these
-objects?
-
-Recall that in the chapter entitled `Acquisition <Acquisition.stx>`_, we
-learned that Zope can find objects in different places by *acquiring* them from
-parent containers. Acquisition allows us to treat an object as a method that
-can be called *in the context of* any suitable object, just by constructing an
-appropriate URL. The object *on* which we call a method gives it a context in
-which to execute. Or, to put it another way: the context is the environment in
-which the method executes, from which the method may get information that it
-needs in order to do its job.
-
-Another way to understand the context of a method is to think of the method as
-a function in a procedural programming language, and its context as an implicit
-argument to that function.
-
-While the Zope way to call methods *in the context of* objects **works**
-differently than the normal object-oriented way to call class-defined methods
-*on* objects, they are **used** the same way, and it is simpler to say that you
-are calling the method *on* the object.
-
-There are two general ways to call methods *on* objects: by visiting an URL,
-and by calling the method from another method.
-
-URL Traversal and Acquisition
-+++++++++++++++++++++++++++++
-
-The concept of calling methods *in the context of* objects is a powerful
-feature that enables you to apply logic to objects, like documents or folders,
-without having to embed any actual code within the object.
-
-For example, suppose you have a collection of objects and methods, as shown in
-the figure below.
-
-`A collection of objects and methods <img:9-1:Figures/zoo.png>`_
-
-To call the *feed* method on the *hippo* object, you would visit the URL:: 
-
-  Zoo/LargeAnimals/hippo/feed
-
-To call the *feed* method on the *kangarooMouse* object you would visit the
-URL:: 
-
-  Zoo/SmallAnimals/kangarooMouse/feed
-
-These URLs place the *feed* method in the context of the *hippo* and
-*kangarooMouse* objects, respectively.
-
-Zope breaks apart the URL and compares it to the object hierarchy,
-working backwards until it finds a match for each part.  This process is
-called *URL traversal*.  For example, when you give Zope the URL:: 
-
-  Zoo/LargeAnimals/hippo/feed
-
-it starts at the root folder and looks for an object named *Zoo*. It then moves
-to the *Zoo* folder and looks for an object named *LargeAnimals*. It moves to
-the *LargeAnimals* folder and looks for an object named *hippo*. It moves to
-the *hippo* object and looks for an object named *feed*. The *feed* method
-cannot be found in the *hippo* object and is located in the *Zoo* folder by
-using acquisition. Zope always starts looking for an object in the last object
-it traversed, in this case: *hippo*. Since *hippo* does not contain anything,
-Zope backs up to *hippo's* immediate container *LargeAnimals*. The *feed*
-method is not there, so Zope backs up to *LargeAnimals* container, *Zoo*, where
-*feed* is finally found.
-
-Now Zope has reached the end of the URL and has matched objects to every name
-in the URL. Zope recognizes that the last object found, *feed*, is callable,
-and calls it *in the context of* the second-to-last object found: the *hippo*
-object. This is how the *feed* method is called *on* the *hippo* object.
-
-Likewise, you can call the *wash* method on the *hippo* by visiting the URL::
-
-  Zoo/LargeAnimals/hippo/wash
-
-In this case, Zope acquires the *wash* method from the *LargeAnimals* folder.
-
-Note that *Script (Python)* and *Page Template* objects are always method
-objects. You can't call another method *in the context* of one of them. Given
-*wash* is such a method object, visiting the URL ::
-
-  Zoo/LargeAnimals/hippo/wash/feed
-
-would also call the *wash* method on the *hippo* object. Instead of traversing
-to *feed*, everything after the method ::
-
-  wash
-
-is cut off of the URL and stored in the variable::
-
-  traverse_subpath
-
-
-The Special Folder Object *index_html*
-+++++++++++++++++++++++++++++++++++++++
-
-As already mentioned at the beginning of this chapter, Zope uses the default
-method if no other method is specified. The default method for Folders is
-*index_html*, which does not necessarily need to be a method itself. If it
-isn't a callable, the default method of the object *index_html* is called on
-*index_html*. This is analogous to how an *index.html* file provides a default
-view for a directory in Apache and other web servers. Instead of explicitly
-including the name *index_html* in your URL to show default content for a
-Folder, you can omit it and still gain the same effect.
-
-For example, if you create an *index_html* object in your *Zoo* Folder, and
-view the folder by clicking the View tab or by visiting the URL::
-
-  http://localhost:8080/Zoo/
-
-Zope will call the *index_html* object in the *Zoo* folder and display its
-results. You could instead use the more explicit URL::
-
-  http://localhost:8080/Zoo/index_html
-
-and it will display the same content.
-
-A Folder can also *acquire* an *index_html* object from its parent Folders. You
-can use this behavior to create a default view for a set of Folders. To do so,
-create an *index_html* object in a Folder that contains another set of Folders.
-This default view will be used for all the Folders in the set. This behavior is
-already evident in Zope: if you create a set of empty Folders in the Zope root
-Folder, you may notice that when you view any of the Folders via a URL, the
-content of the "root" Folder's *index_html* method is displayed. The
-*index_html* in the root Folder is acquired. Furthermore, if you create more
-empty Folders inside the Folders you've just created in the root Folder, a
-visit to these Folders' URLs will also display the root Folder's *index_html*.
-This is acquisition at work.
-
-If you want a different default view of a given Folder, just create a custom
-*index_html* object in that particular Folder. This allows you to override the
-default view of a particular Folder on a case-by-case basis, while allowing
-other Folders defined at the same level to acquire a common default view.
-
-The *index_html* object may be a *Page Template*, a *Script (Python)* object, a
-*DTML Method* or any other Zope object that is URL-accessible and that returns
-browser-renderable content. The content is typically HTML, but Zope doesn't
-care. You can return XML, or text, or anything you like.
-
-Using Python-based Scripts
-==========================
-
-Now let us take a look at a basic method object: *Script (Python)*.
-
-The Python Language
-+++++++++++++++++++
-
-`Python <http://www.python.org/>`_ is a high-level, object oriented scripting
-language. Most of Zope is written in Python. Many folks like Python because of
-its clarity, simplicity, and ability to scale to large projects.
-
-There are many resources available for learning Python. The python.org website
-has lots of Python documentation including a `tutorial
-<http://www.python.org/doc/current/tut/tut.html>`_ by Python's creator, Guido
-van Rossum.
-
-For people who have already some programming experience, `Dive Into Python
-<http://diveintopython.org/>`_ is a great online resource to learn python.
-
-Python comes with a rich set of modules and packages. You can find out more
-about the `Python standard library
-<http://www.python.org/doc/current/lib/lib.html>`_ at the python.org website.
-
-Creating Python-based Scripts
-+++++++++++++++++++++++++++++
-
-To create a Python-based Script, select *Script (Python)* from the Add
-drop-down list. Name the script *hello*, and click the *Add and Edit* button.
-You should now see the *Edit* view of your script.
-
-This screen allows you to control the parameters and body of your script. You
-can enter your script's parameters in the *parameter list* field. Type the body
-of your script in the text area at the bottom of the screen.
-
-Enter:: 
-
-  name="World"
-
-into the *parameter list* field, and in the body of the script, type::
-
-  return "Hello %s." % name
-
-Our script is now equivalent to the following function definition in standard
-Python syntax::
-
-  def hello(name="World"):
-      return "Hello %s." % name
-
-The script should return a result similar to the following image:
-
-`Script editing view <img:9-2:Figures/8-5.png>`_
-
-You can now test the script by going to the *Test* tab, as shown in the
-following figure.
-
-`Testing a Script <img:9-3:Figures/8-6.png>`_
-
-Leave the *name* field blank, and click the *Run Script* button. Zope should
-return "Hello World." Now go back and try entering your name in the *Value*
-field, and clicking the *Run Script* button. Zope should now say "hello" to
-you.
-
-Since scripts are called on Zope objects, you can get access to Zope objects
-via the *context* variable. For example, this script returns the number of
-objects contained by a given Zope object::
-
-  ## Script (Python) "numberOfObjects"
-  ##
-  return len( context.objectIds() )
-
-Note that the lines at the top starting with a double hash (##) are generated
-by Zope when you view the script outside the *Edit* tab of the ZMI, e.g., by
-clicking the *view or download* link at the bottom of the *Edit* tab. We'll use
-this format for our examples.
-
-The script calls::
-
-  context.objectIds()
-
-a method in the Zope API, to get a list of the contained objects. *objectIds*
-is a method of *Folders*, so the context object should be a Folder-like object.
-The script then calls::
-
-  len()
-
-to find the number of items in that list. When you call this script on a given
-Zope object, the *context* variable is bound to the context object. So, if you
-called this script by visiting the URL::
-
-  FolderA/FolderB/numberOfObjects
-
-the *context* parameter would refer to the `FolderB` object.
-
-When writing your logic in Python, you'll typically want to query Zope objects,
-call other scripts, and return reports. Suppose you want to implement a simple
-workflow system, in which various Zope objects are tagged with properties that
-indicate their status. You might want to produce reports that summarize which
-objects are in which state. You can use Python to query objects and test their
-properties. For example, here is a script named::
-
-  objectsForStatus
-
-with one parameter, 'status'::
-
-  ## Script (Python) "objectsForStatus"
-  ##parameters=status
-  ##
-  """ Returns all sub-objects that have a given status property.
-  """
-  results=[]
-  for object in context.objectValues():
-      if object.getProperty('status') == status:
-          results.append(object)
-  return results
-
-This script loops through an object's sub-objects, and returns all the
-sub-objects that have a::
-
-  status
-
-property with a given value.
-
-Accessing the HTTP Request
-++++++++++++++++++++++++++
-
-What if we need to get user input, e.g., values from a form? We can find the
-REQUEST object, which represents a Zope web request, in the context. For
-example, if we visited our *feed* script via the URL::
-
-  Zoo/LargeAnimals/hippo/feed?food_type=spam
-
-we could access the:: 
-
-  food_type
-
-variable as::
-
-  context.REQUEST.food_type
-
-This same technique works with variables passed from forms.
-
-Another way to get the REQUEST is to pass it as a parameter to the script. If
-REQUEST is one of the script's parameters, Zope will automatically pass the
-HTTP request and assign it to this parameter. We could then access the::
-
-  food_type
-
-variable as::
-
-  REQUEST.food_type
-
-String Processing in Python
-+++++++++++++++++++++++++++
-
-One common use for scripts is to do string processing. Python has a number of
-standard modules for string processing. Due to security restrictions, you
-cannot do regular expression processing within Python-based Scripts. If you
-really need regular expressions, you can easily use them in External Methods,
-described in a subsequent chapter. However, in a Script (Python) object, you do
-have access to string methods.
-
-Suppose you want to change all the occurrences of a given word in a text file.
-Here is a script, *replaceWord*, that accepts two arguments: *word* and
-*replacement*. This will change all the occurrences of a given word in a
-File::
-
-  ## Script (Python) "replaceWord"
-  ##parameters=word, replacement
-  ##
-  """ Replaces all the occurrences of a word with a replacement word in
-  the source text of a text file. Call this script on a text file to use
-  it.
-
-  Note: you will need permission to edit the file in order to call this
-  script on the *File* object.  This script assumes that the context is
-  a *File* object, which provides 'data', 'title', 'content_type' and
-  the manage_edit() method.
-  """
-  text = context.data
-  text = text.replace(word, replacement)
-  context.manage_edit(context.title, context.content_type, filedata=text)
-
-You can call this script from the web on a text *File* in order to change the
-text. For example, the URL::
-
-  Swamp/replaceWord?word=Alligator&replacement=Crocodile
-
-would call the *replaceWord* script on the text *File* named::
-
-  Swamp
-
-and would replace all occurrences of the word::
-
-  Alligator
-
-with::
-
-  Crocodile
-
-See the Python documentation for more information about manipulating strings
-from Python.
-
-One thing that you might be tempted to do with scripts is to use Python to
-search for objects that contain a given word within their text or as a
-property. You can do this, but Zope has a much better facility for this kind of
-work: the *Catalog*. See the chapter entitled `Searching and Categorizing
-Content <SearchingZCatalog.stx>`_ for more information on searching with
-Catalogs.
-
-Print Statement Support
-+++++++++++++++++++++++
-
-Python-based Scripts have a special facility to help you print information.
-Normally, printed data is sent to standard output and is displayed on the
-console. This is not practical for a server application like Zope, since the
-service does not always have access to the server's console. Scripts allow you
-to use print anyway, and to retrieve what you printed with the special variable
-*printed*. For example::
-
-  ## Script (Python) "printExample"
-  ##
-  for word in ('Zope', 'on', 'a', 'rope'):
-      print word
-  return printed
-
-This script will return::
-
-  Zope
-  on
-  a
-  rope
-
-The reason that there is a line break in between each word is that Python adds
-a new line after every string that is printed.
-
-You might want to use the::
-
-  print
-
-statement to perform simple debugging in your scripts. For more complex output
-control, you probably should manage things yourself by accumulating data,
-modifying it, and returning it manually, rather than relying on the::
-
-  print
-
-statement. And for controlling presentation, you should return the script
-output to a Page Template or DTML page, which then displays the return value
-appropriately.
-
-Built-in Functions
-++++++++++++++++++
-
-Python-based Scripts give you a slightly different menu of built-ins than you'd
-find in normal Python. Most of the changes are designed to keep you from
-performing unsafe actions. For example, the *open* function is not available,
-which keeps you from being able to access the file system. To partially make up
-for some missing built-ins, a few extra functions are available.
-
-The following restricted built-ins work the same as standard Python built-ins:
-*None*, *abs*, *apply*, *callable*, *chr*, *cmp*, *complex*, *delattr*,
-*divmod*, *filter*, *float*, *getattr*, *hash*, *hex*, *int*, *isinstance*,
-*issubclass*, *list*, *len*, *long*, *map*, *max*, *min*, *oct*, *ord*, *repr*,
-*round*, *setattr*, *str*, and *tuple*. For more information on what these
-built-ins do, see the online `Python Documentation
-<http://www.python.org/doc/>`_.
-
-The *range* and *pow* functions are available and work the same way they do in
-standard Python; however, they are limited to keep them from generating very
-large numbers and sequences. This limitation helps protect against
-denial-of-service attacks.
-
-In addition, these DTML utility functions are available: *DateTime* and *test*.
-See Appendix A, `DTML Reference <AppendixA.stx>`_ for more information on these
-functions.
-
-Finally, to make up for the lack of a *type* function, there is a *same_type*
-function that compares the type of two or more objects, returning *true* if
-they are of the same type. So, instead of saying::
-
-  if type(foo) == type([]):
-      return "foo is a list"
-
-... to check if::
-
-  foo
-
-is a list, you would instead use the *same_type* function::
-
-  if same_type(foo, []):
-      return "foo is a list"
-
-Calling ZPT from Scripts
-========================
-
-Often, you would want to call a *Page Template* from a Script. For instance, a
-common pattern is to call a Script from an HTML form. The Script would process
-user input, and return an output page with feedback messages - telling the user
-her request executed correctly, or signalling an error as appropriate.
-
-Scripts are good at logic and general computational tasks but ill-suited for
-generating HTML. Therefore, it makes sense to delegate the user feedback output
-to a *Page Template* and call it from the Script. Assume we have this Page
-Template with the *id* 'hello_world_pt'::
-
-  <p>Hello <span tal:replace="options/name | default">World</span>!</p>
-
-You will learn more about *Page Templates* in the next chapter. For now, just
-understand that this *Page Template* generates an HTML page based on the value
-*name*. Calling this template from a Script and returning the result could be
-done with the following line::
-
-  return context.hello_world_pt(name="John Doe")
-
-The *name* parameter to the Page Template ends up in the::
-
-  options/name
-
-path expression. So the returned HTML will be::
-
-  <p>Hello John Doe!</p>
-
-Note that::
-
-  context.hello_world_pt
-
-works because there is no dot in the id of the template. In Python, dots are
-used to separate ids. This is the reason why Zope often uses ids like::
-
-  index_html
-
-instead of the more common::
-
-  index.html
-
-and why this example uses::
-
-  hello_world_pt
-
-instead of::
-
-  hello_world.pt
-
-However, if desired, you can use dots within object ids. Using *getattr* to
-access the dotted id, the modified line would look like this::
-
-  return getattr(context, 'hello_world.pt')(name="John Doe")
-
-Returning Values from Scripts
-=============================
-
-Scripts have their own variable scope. In this respect, scripts in Zope behave
-just like functions, procedures, or methods in most programming languages. If
-you name a script *updateInfo*, for example, and *updateInfo* assigns a value
-to a variable *status*, then *status* is local to your script: it gets cleared
-once the script returns. To get at the value of a script variable, we must pass
-it back to the caller with a *return* statement.
-
-Scripts can only return a single object. If you need to return more than one
-value, put them in a dictionary and pass that back.
-
-Suppose you have a Python script *compute_diets*, out of which you want to get
-values::
-
-  ## Script (Python) "compute_diets"
-  d = {'fat': 10,
-       'protein': 20,
-       'carbohydrate': 40,
-  }
-  return d
-
-The values would, of course, be calculated in a real application; in this
-simple example, we've simply hard-coded some numbers.
-
-You could call this script from ZPT like this::
-
-  <p tal:repeat="diet context/compute_diets">
-      This animal needs
-      <span tal:replace="diet/fat" />kg fat,
-      <span tal:replace="diet/protein" />kg protein, and
-      <span tal:replace="diet/carbohydrate" />kg carbohydrates.
-  </p>
-
-More on ZPT in the next chapter.
-
-The Zope API
-============
-
-One of the main reasons to script in Zope is to get convenient access to the
-Zope Application Programmer Interface (API). The Zope API describes built-in
-actions that can be called on Zope objects. You can examine the Zope API in the
-help system, as shown in the figure below.
-
-`Zope API Documentation <img:9-4:Figures/8-4.png>`_
-
-Suppose you would like a script that takes a file you upload from a form, and
-creates a Zope File object in a Folder. To do this, you'd need to know a number
-of Zope API actions. It's easy enough to read files in Python, but once you
-have the file, you must know which actions to call in order to create a new
-File object in a Folder.
-
-There are many other things that you might like to script using the Zope API:
-any management task that you can perform through the web can be scripted using
-the Zope API, including creating, modifying, and deleting Zope objects. You can
-even perform maintenance tasks, like restarting Zope and packing the Zope
-database.
-
-The Zope API is documented in Appendix B, `API Reference <AppendixB.stx>`_, as
-well as in the Zope online help. The API documentation shows you which classes
-inherit from which other classes. For example, *Folder* inherits from
-*ObjectManager*, which means that Folder objects have all the methods listed in
-the *ObjectManager* section of the API reference.
-
-To get you started and whet your appetite, we will go through some example
-Python scripts that demonstrate how you can use the Zope API:
-
-Get all objects in a Folder
-+++++++++++++++++++++++++++
-
-The::
-
-  objectValues()
-
-method returns a list of objects contained in a Folder. If the context happens
-not to be a Folder, nothing is returned::
-
-  objs = context.objectValues()
-
-Get the id of an object
-+++++++++++++++++++++++
-
-The id is the "handle" to access an object, and is set at object creation::
-
-  id = context.getId()
-
-Note that there is no *setId()* method: you have to either use the ZMI to
-rename them, set their::
-
-  id
-
-attribute via security-unrestricted code, or use the::
-
-  manage_renameObject
-
-or::
-
-  manage_renameObjects
-
-API methods exposed upon the container of the object you want to rename.
-
-Get the Zope root Folder
-++++++++++++++++++++++++
-
-The root Folder is the top level element in the Zope object database::
-
-  root = context.getPhysicalRoot()
-
-Get the physical path to an object
-++++++++++++++++++++++++++++++++++
-
-The::
-
-  getPhysicalPath()
-
-method returns a list containing the ids of the object's containment
-hierarchy::
-
-  path_list = context.getPhysicalPath()
-  path_string = "/".join(path_list)
-
-Get an object by path
-+++++++++++++++++++++
-
-restrictedTraverse() is the complement to::
-
-  getPhysicalPath()
-
-The path can be absolute -- starting at the Zope root -- or relative to the
-context::
-
-  path = "/Zoo/LargeAnimals/hippo"
-  hippo_obj = context.restrictedTraverse(path)
-
-Get a property
-++++++++++++++
-
-getProperty()
-
-returns a property of an object. Many objects support properties (those that
-are derived from the PropertyManager class), the most notable exception being
-DTML Methods, which do not::
-
-  pattern = context.getProperty('pattern')
-  return pattern
-
-Change properties of an object
-++++++++++++++++++++++++++++++
-
-The object has to support properties, and the property must exist::
-
-  values = {'pattern' : 'spotted'}
-  context.manage_changeProperties(values)
-
-Traverse to an object and add a new property
-++++++++++++++++++++++++++++++++++++++++++++
-
-We get an object by its absolute path, add a property::
-
-  weight
-
-and set it to some value. Again, the object must support properties in order
-for this to work::
-
-  path = "/Zoo/LargeAnimals/hippo"
-  hippo_obj = context.restrictedTraverse(path)
-  hippo_obj.manage_addProperty('weight', 500, 'int')

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/Contributions.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/Contributions.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/Contributions.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,67 +0,0 @@
-Contributions
-=============
-
-Contributors to this book include Amos Latteier, Michel Pelletier,
-Chris McDonough, Evan Simpson, Tom Deprez, Paul Everitt, Bakhtiar
-A. Hamid, Geir Baekholt, Thomas Reulbach, Paul Winkler, Peter Sabaini,
-Andrew Veitch, Kevin Carlson, Joel Burton, John DeStefano, Tres Seaver,
-Hanno Schlicting, and the Zope Community.
-
-Amos and Michel wrote the entirety of the first edition of this
-book, and kept the online version of the book current up until Zope
-2.5.1.
-
-Tom Deprez provided much-needed editing assistance on the first
-book edition.
-
-Evan Simpson edited the chapters related to ZPT for the 2.6
-edition.
-
-Paul Everitt contributed to the first few chapters of the first
-edition, edited the first few chapters of the second edition for
-sanity and contributed some "Maintaining Zope" content for the
-2.6 edition.
-
-Bakhtiar Hamid edited the ZEO chapter for the 2.6 edition.
-
-Geir edited and extended the Users and Security chapter for the 2.6
-edition.
-
-Paul Winkler with help from Peter Sabaini expertly massaged the
-Advanced Scripting chapter into coherency for the 2.6 edition.
-
-Peter Sabaini greatly fleshed out and extended the "Maintaining Zope"
-and the "Searching and Categorizing Content" chapter for the 2.6 Edition. 
-
-Andrew Veitch cheerfully performed the thankless task of
-editing and extending the Relational Database Connectivity chapter
-for the 2.6 edition.
-
-Kevin Carlson masterfully edited and expanded the Advanced DTML
-chapter. 
-
-Joel Burton rewrote the ZCatalog chapter late in the 2.6 book's
-lifetime.
-
-Dario Lopez-Kästen updated the "Introducing Zope" chapter for the
-2.7 edition.
-
-Chris McDonough edited the entirety of the book for the 2.6
-edition, entirely rewrote a few chapters and added new material
-related to object orientation, using the Zope management interface,
-acquisition, installation, services, virtual hosting, sessions, and
-DTML name lookup rules.
-
-Jo <jo at winfix dot it> has contributed a number of spelling corrections.
-
-John DeStefano edited chapters of the book in a post-2.7-edition mode.
-
-Tres Seaver moved the text into the Zope Subversion repository, and
-helped with the conversion of the text from ``Structured Text``
-to ``ReStructured Text``.
-
-Hanno Schlichting did the remainder of the ``ReStructured Text`` conversion,
-completed the integration with Sphinx and rewrote many chapters for Zope 2.12.
-
-Anyone who added a comment to the online BackTalk edition of the
-first online edition of this book contributed greatly.  Thank you!

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/DTML.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/DTML.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/DTML.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,1427 +0,0 @@
-Basic DTML
-==========
-
-
-.. note::
-    DTML has been the primary markup language within Zope for a long time.  However
-    the *recommended* primary markup language within Zope is nowadays ZPT (Zope
-    Page Templates). ZPT is your choice for generating markupish output like HTML
-    or XML. The usage of DTML should be limited where you have to generate
-    non-markupish output like text files or other formats. Since DTML is pretty old
-    it really does not support features like internationalization or unicode very
-    well.  In addition the syntax of DTML is not always very easy to understand.
-    You have to learn DTML to some point if you intend to use ZSQL methods (for
-    RDBMS integration with Zope) - but even for the RDBMS integration we have
-    better solutions like Object-Relational-Mappers (check with the chapter about
-    relational database connectivity).
-
-
-DTML (Document Template Markup Language) is a templating facility which
-supports the creation of dynamic HTML and text. In Zope it is most often used
-when you want to generate non-HTML or non-XML content, like parts of SQL
-queries, dynamic CSS and JavaScript files or email templates. Generating HTML
-and XML is usually done with page templates inside Zope.
-
-DTML is a *tag-based* presentation and scripting language.  This
-means that *tags* (e.g. '<dtml-var name>') embedded in your text
-cause parts of your text to be replaced with "computed" content.
-
-DTML is a "server-side" scripting language.  This means that DTML
-commands are executed by Zope at the server, and the result of that
-execution is sent to your web browser. By contrast, "client-side"
-scripting languages like JavaScript are not processed by the server,
-but are rather sent to and executed by your web browser.
-
-How DTML Relates to Similar Languages and Templating Facilities
----------------------------------------------------------------
-
-DTML is similar in function to "HTML-embedded" scripting languages
-such as JSP, PHP, or mod_perl.  It differs from these facilities
-inasmuch as it will not allow you to create "inline" Python
-*statements* (if... then.. else..)  in the way that JSP, mod_perl
-or PHP will allow you to embed a block of their respective
-language's code into a page. DTML does allow you to embed
-Python *expressions* (a == 1) into tags.  It provides
-flow control and conditional logic by way of "special" tags.
-It is more similar to Perl's 'HTML::Template' package than it is
-to mod_perl in this way.  It can also be compared to the web
-server facility of Server Side Includes (SSI), but with far more
-features and flexibility.
-
-When To Use DTML
-----------------
-
-If you don't want to use page templates for whatever reason DTML might work
-well. Likewise, if you want to dynamically create non-HTML text (like CSS
-stylesheets or email messages), DTML can help.
-
-When Not To Use DTML
---------------------
-
-If you want code which expresses a set of complex algorithms to be
-maintainable (as "logic" programming should be), you shouldn't
-write it in DTML.  DTML is not a general purpose programming
-language, it instead is a special language designed for formatting
-and displaying content.  While it may be possible to implement
-complex algorithms in DTML, it is often painful.
-
-For example, let's suppose you want to output some text which
-displays a representation of the famous `Fibonacci sequence
-<http://www.mathacademy.com/pr/prime/articles/fibonac/index.asp>`_.
-You would not want to write the program that actually makes the
-calculation of the Fibonacci numbers by writing DTML.  It could be
-done in DTML, but the result would be difficult to understand and
-maintain.  However, DTML is perfect for describing the output that
-the results of the Fibonnacci calculations are inserted into.  You
-can "call out" from DTML to Script (Python) objects as necessary
-and process the results of the call in DTML.  For example, it is
-`trivial in Python <http://docs.python.org/tutorial/introduction.html>`_
-(search for the word Fibonacci on this page) to implement a Fibonacci
-sequence generator, and trivial in DTML to create some dynamic 
-output which shows these numbers in a readable format.  If you find
-yourself creating complex and hard-to-understand logic in DTML,
-it's likely time to explore the the Zope features which allow you
-to script "logic" in Python, while letting DTML do the
-presentation "dirty work".
-
-String processing is another area where DTML is likely not the
-best choice.  If you want to manipulate input from a user in a
-complex way, by using functions that manipulate strings, you are
-better off doing it in Python, which has more powerful string
-processing capabilities than DTML.
-
-The Difference Between DTML Documents and DTML Methods
-------------------------------------------------------
-
-You can use DTML scripting commands in two types of Zope objects,
-*DTML Documents* and *DTML Methods*.  These two types of DTML
-objects are subtly different from one another, and their
-differences cause many would-be DTML programmers to become
-confused when deciding to use one versus the other.  So what is
-the difference?
-
-DTML Methods are used to carry out actions. They are
-*presentation* objects (as used in the vernacular of the `Using
-Basic Zope Objects`_ chapter).  If you want to
-render the properties or attributes of another object like a DTML
-Document or a Folder, you will use a DTML Method.  DTML Methods do
-not have their own properties.
-
-DTML Documents are *content* objects (in the vernacular used in
-the chapter entitled `Using Basic Zope Objects`_).
-If you want to create a "stand-alone" text document, you
-might create a DTML Document object to hold the text.
-DTML Document objects have their own *properties* (attributes),
-unlike DTML Methods.
-
-In almost all cases, you will want to use a DTML Method object to
-perform DTML scripting.  DTML Document objects are an artifact of
-Zope's history that is somewhat unfortunate.  In Zope's earlier
-days, a consensus came about that it was important to have objects
-in Zope that could perform DTML commands but have properties of
-their own.  At the time, the other content objects in Zope, such
-as Files and Images were either nonexistent or had limitations in
-functionality that made the concept of a DTML Document attractive.
-That attraction has waned as Zope's other built-in content objects
-have become more functional.  DTML Documents remain in Zope almost
-solely as a backwards-compatibility measure.  If you never use a
-DTML Document in your work with Zope, you won't miss out on
-much!
-
-Details
--------
-
-DTML Methods are method objects.  The chapter named `Object
-Orientation <ObjectOrientation.html>`_ discusses the concept of a
-"method".  DTML Methods are *methods* of the folder that
-contains them, and thus they do not have regard for their own
-identity as a Zope object when they are used. For example, if
-you had a folder called Folder and a DTML method in that folder
-called Method::
-
-  AFolder/
-          AMethod
-
-AMethod is a *method* of AFolder. This means that AMethod does not
-have any of it's own attributes or properties.  Instead it uses
-those of AFolder. Suppose you put the following DTML string in
-AMethod::
-
-  <dtml-var id>
-
-When you view the AMethod DTML Method, you will see the string
-'AFolder', which is the 'id' of AMethod's containing Folder
-(AFolder). When this DTML method is viewed, it resolves the name
-'id' to the string which is the value of AFolder's 'id' property.
-
-DTML Documents, on the other hand, are not methods.  They are
-"aware" of their own identity as Zope objects. For example, if
-you created a DTML Document in the folder AFolder called
-ADocument, and you put the above DTML string into ADocument and
-viewed it, it would render to the string 'ADocument'.  It
-resolves the name 'id' to the string which is the value of
-its *own* id, not the id of its containing folder.
-
-.. important::
-   
-   For this chapter, unless stated otherwise, use DTML Methods to
-   hold the example DTML text, as opposed to DTML Documents!**
-
-DTML Tag Syntax
----------------
-
-DTML contains two kinds of tags, *singleton* and *block* tags.
-Singleton tags consist of one tag enclosed by less-than (&lt;) and
-greater-than (&gt;) symbols.  The *var* tag is an example of a
-singleton tag::
-
-  <dtml-var parrot>
-
-There's no need to close the *var* tag with a '</dtml-var>' tag
-because it is a singleton tag.
-
-Block tags consist of two tags, one that opens the block and one that
-closes the block, and content that goes between them::
-
-  <dtml-in mySequence>
-
-    this is a text inside the dtml-in tag block
-
-  </dtml-in>
-
-The opening tag starts the block and the closing tag ends it. The
-closing tag has the same name as the opening tag with a slash
-preceding it. This is the same convention that HTML and XML use.
-
-DTML Tag Names, Targets, and Attributes
----------------------------------------
-
-All DTML tags have *names*.  The name is simply the word which
-follows 'dtml-'.  For instance, the name of the DTML tag
-'dtml-var' is 'var', and the name of the DTML tag 'dtml-in' is
-'in'.
-
-Most DTML tags have *targets*.  The target of a DTML tag is just
-the word or expression that, after a space, follows the tag
-name.  For example, the target of the DTML tag '<dtml-var
-standard_html_header>' is 'standard_html_header'.  The target of
-the DTML tag '<dtml-in foo>' is 'foo'.  The target of the DTML
-tag '<dtml-var "objectIds()"> is the expression "objectIds()".
-The target typically refers to the name of an object (or a
-Python expression that resolves to an object) that you wish the
-tag to operate upon.
-
-All DTML tags have *attributes*. An attribute provides
-information about how the tag is supposed to work. Some
-attributes are optional. For example, the *var* tag inserts the
-value of its target. It has an optional *missing* attribute that
-specifies a default value in case the variable can't be found::
-
-  <dtml-var wingspan missing="unknown wingspan">
-
-If the *wingspan* variable is not found then 'unknown wingspan'
-is inserted instead.
-
-Some attributes don't have values. For example, you can convert
-an inserted variable to upper case with the *upper* attribute::
-
-  <dtml-var exclamation upper>
-
-Here we are referencing the *exclamation* target, modifying it
-with the attribute *upper*.  Notice that the *upper* attribute,
-unlike the *missing* attribute doesn't need a value.
-
-See the `DTML Reference <AppendixA.html>`_ appendix for more
-information on the syntax of different DTML tags.
-
-Creating a "Sandbox" for the Examples in This Chapter
------------------------------------------------------
-
-You should create a Folder in your Zope's root folder named
-"DTML_Examples" if you intend on creating objects from examples in
-this chapter.  Create the example objects within this "sandbox".
-This prevents you from littering your Zope root folder with DTML
-examples.
-
-Examples of Using DTML for Common Tasks
----------------------------------------
-
-Below, we show how to use DTML to complete three common tasks:
-inserting text into a web page, displaying results by iterating
-over a sequence, and processing form results.
-
-Inserting Text into HTML with DTML
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-DTML commands are written as tags that begin with *dtml-*.  You
-create dynamic content in DTML by mixing content and DTML tags
-together.  Inserting the value of a variable (a variable is also
-known as a "target") into HTML is the most basic task that you can
-perform with DTML.  Many DTML tags insert variable values, and
-they all do it in a similar way.  Let's look more closely at how
-Zope inserts variable values.
-
-Create a folder in your sandbox with the id "Feedbags" and the
-title "Bob's Fancy Feedbags". While inside the 'Feedbags' folder,
-create a DTML Method with an id of "pricelist". Note: an
-'id' is how you refer to an object such as a DTML Method
-or a Folder later on; titles are for informational
-purposes only. 
-
-Change the contents of the DTML Method to the following::
-
-  <dtml-var standard_html_header>
-
-  <h1>Price list for <dtml-var title></h1>
-
-  <p>Hemp Bag $2.50</p>
-  <p>Silk Bag $5.00</p>
-
-  <dtml-var standard_html_footer>
-
-Now view the DTML Method by clicking the *View* tab. When you view
-the DTML method this way, it will be *rendered*, which means that
-you will not necessarily see a straight representation of the HTML
-that you typed in to the form.  Instead you will see the
-*rendered* version of the page, which will include the extra text
-provided by DTML by way of the tags you've inserted.  You should
-see something like the figure below:
-
-.. figure:: ../Figures/9-1_bobsfeedbags.png
-
-   Viewing the pricelist method
-
-If you tell your browser to view the HTML source of the Workspace
-frame, you will see something not unlike the below::
-
-  <html>
-    <head><title>Bob's Fancy Feedbags</title>
-    </head>
-    <body bgcolor="#FFFFFF">
-      <h1>Price list for Bob's Fancy Feedbags</h1>
-      <p>Hemp Bag $2.50</p>
-      <p>Silk Bag $5.00</p>
-    </body>
-
-  </html>
-
-That's certainly not what you typed in, is it?
-
-DTML makes the reuse of content and layout possible.  In the
-example above, we've made use of the 'standard_html_header' DTML
-Method and the 'standard_html_footer' DTML Method, both of which
-live in the root folder, to insert HTML text into our page.  These
-DTML methods (and any other DTML method) can be used by other DTML
-methods to insert text into our rendered output.
-
-We've seen that DTML inserts an HTML header, an HTML footer, and a
-title into the web page.  But how does the "var" tag *find* the
-values that it inserts in place of "standard_html_header", "title"
-and "standard_html_footer"?
-
-DTML name lookup is somewhat "magical", because you don't need to
-explicitly tell DTML *where* to find a variable.  Instead, it
-tries to guess what you mean by following a preordained set of
-search rules.  DTML gets the values for variable names by
-searching an environment which includes the current object, the
-containment path, and request variables like values submitted by a
-form and cookies.  The `DTML Name Lookup Rules <AppendixE.html>`_
-represent the namespaces searched and their relative precedence.
-As an example, let's follow the 'pricelist' DTML code
-step-by-step.  In our 'pricelist' method, we've asked DTML to look
-up three names: "standard_html_header", "title", and
-"standard_html_footer".  It searches for these variables in the
-order that they are mentioned in the page.
-
-DTML looks first for "standard_html_header".  It looks in the
-"current object" first, which is its container, the 'Feedbags'
-folder. The 'Feedbags' folder doesn't have any methods or
-properties or sub-objects by that name. Next Zope tries to
-`acquire <Acquisition.html>`_ the object from its containers.  It
-examines the 'Feedbags' folder's container (your sandbox folder,
-likely named "DTML_Examples"), which also doesn't turn up
-anything.  It continues searching through any intermediate
-containters, which also don't have a method or property named
-"standard_html_header" unless you've put one there.  It keeps
-going until it gets to the root folder.  The root folder *does*
-have a sub-object named "standard_html_header", which comes as a
-default object in every Zope. The 'standard_html_header' object is
-a DTML Method. So Zope *calls* the 'standard_html_header' method
-in the root folder and inserts the results into the page.  Note
-that once DTML *finds* a property or variable, if it is callable
-(as in the case of a DTML Method, an External Method, a SQL
-Method, or a Script (Python) object), it is called and the results
-of the call are inserted into the page.
-
-Next DTML looks for the name "title". Here, the search is 
-shorter.  On its first try, DTML finds the 'Feedbags' folder's
-'title' property and inserts it.  The 'title' property is not a
-method or a script, so DTML doesn't need to *call* it.  It just
-renders it into the output.
-
-Finally DTML looks for the name *standard_html_footer*. It has to
-search all the way up to the root folder to find it, just like it
-looked for *standard_html_header*.  It calls the
-*standard_html_footer* in the root and inserts the text result.
-
-The resulting page is fully assembled (rendered) at this point,
-and is sent to your browser.
-
-Understanding how DTML looks up variables is important.  We will
-explore the DTML name lookup mechanism further in the chapter
-entitled `Variables and Advanced DTML <AdvDTML.html>`_.
-It is also documented in `Appendix E <AppendixE.html>`_.
-
-Formatting and Displaying Sequences
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-It is common that people want to use DTML to format and display
-*sequences*.  A sequence is just a list of items, like "Fred, Joe,
-Jim".  Often, you want to create an HTML table or a bulleted list
-that contains elements in a sequence.  Let's use DTML to call out
-to an object which returns a sequence and render its result.
-
-Create a Script (Python) object named "actors" in your
-sandbox folder. Give the script the following body and
-save it::
-
-  ## Script (Python) "actors"
-  ##bind container=container
-  ##bind context=context
-  ##bind namespace=
-  ##bind script=script
-  ##bind subpath=traverse_subpath
-  ##parameters=
-  ##title=
-  ##
-  return ['Jack Lemmon', 'Ed Harris','Al Pacino', 'Kevin Spacey', 'Alan Arkin']
-
-Make sure that all of the lines of this script line up along the
-left-hand side of the textarea to avoid receiving an error when
-you attempt to save the script, since Python is sensitive to
-indentation.  Don't worry about the '##'s for now, we will
-explain these later.  
-
-This Script (Python) object returns a Python data
-structure which is a *list* of *strings*.  A list is a kind of
-*sequence*, which means that DTML can *iterate* over it using the
-*dtml-in* tag.  Now create a DTML Method named "showActors" in
-your sandbox, give it this body, and save it::
-
-  <html>
-  <body>
-  <h1>Actors in the movie Glengarry Glen Ross</h1>
-  <table border="1">
-    <th>Name</th>
-  <dtml-in actors>
-    <tr>
-    <td><dtml-var sequence-item></td>
-    </tr>
-  </dtml-in>
-  </table>
-  </body>
-  </html>
-
-The DTML *in* tag iterates over the results of the *actors* script
-and inserts a table row into a table for each of the actors
-mentioned in the script.  Note that inside the table cell, we use
-a special name *sequence-item*.  *sequence-item* is a special name
-that is meaningful within a *dtml-in* tag.  It refers to the
-"current item" (in this case, the actor name string) during
-processing.  The HTML source of the Workspace frame when you click
-the *View* tab on the 'showActors' method will look something
-like::
-
-  <html>
-  <body>
-  <h1>Actors in the movie Glengarry Glen Ross</h1>
-  <table border="1">
-    <th>Name</th>
-          <tr>
-    <td>Jack Lemmon</td>
-
-    </tr>
-          <tr>
-    <td>Ed Harris</td>
-    </tr>
-          <tr>
-    <td>Al Pacino</td>
-    </tr>
-          <tr>
-
-    <td>Kevin Spacey</td>
-    </tr>
-          <tr>
-    <td>Alan Arkin</td>
-    </tr>
-        </table>
-  </body>
-  </html>
-
-Note that you didn't have to specifically tell DTML that you are
-querying a Script (Python) object.  You just tell it the name of
-the object to call (in this case 'actors'), and it does the work
-of figuring out how to call the object and pass it appropriate
-arguments. If you replace the 'actors' Script with some other kind
-of object that does exactly the same thing, like another DTML
-Method, you won't have to change your 'showActors' DTML Method.
-It will "just work".
-
-Processing Input from Forms
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can use DTML to perform actions based on the information
-contained in the submission of an HTML form.
-
-Create a DTML Method named "infoForm" with the following body::
-
-  <dtml-var standard_html_header>
-
-  <p>Please send me information on your aardvark adoption
-  program.</p>
-
-  <form action="infoAction">
-  name: <input type="text" name="user_name"><br>
-  email: <input type="text" name="email_addr"><br>
-  <input type="submit" name="submit" value=" Submit ">
-  </form>
-
-  <dtml-var standard_html_footer>
-
-This is a web form that asks the user for information,
-specifically his user name and email address.  Note that you refer
-to the name "infoAction" as the *action* of the HTML form.  This
-really has nothing to do with DTML, it's an attribute of the HTML
-*form* tag.  But the name specified in the form action tag can
-name another Zope object which will receive and process the
-results of the form when it is submitted.
-
-Create a DTML Method named *infoAction* in the same folder as the
-'infoForm' method.  This is the *target* of the 'infoForm' form
-action.  This method will display a bland "thanks" message which
-includes the name and email information that was gathered from the
-web form.  Provide the *infoAction* method with the following body
-and save it::
-
-  <dtml-var standard_html_header>
-
-  <h1>Thanks <dtml-var user_name></h1>
-
-  <p>We received your request for information and will send you
-  email at <dtml-var email_addr> describing our aardvark adoption
-  program as soon as it receives final governmental approval.
-  </p>
-
-  <dtml-var standard_html_footer>
-
-Navigate back to the 'infoForm' method and use the *View* tab to
-execute it.  Fill out the form and click the *Submit* button. If
-all goes well you should see a thank you message that includes
-your name and email address, much like the figure below:
-
-.. figure:: ../Figures/aardvarkview.png
-
-   Result of submitting the infoForm method
-
-The Zope object named *REQUEST* contains information about the
-current web request.  This object is in the DTML name lookup path.
-The 'infoAction' method found the form information from the web
-request that happened when you clicked the submit button on the
-rendering of 'infoForm'.  DTML looks for variables in the current
-web request, so you can just refer to the form variable names in
-the target method by name.  In our case, we were able to display
-the values of the form elements *user_name* and *email_addr* in
-the 'infoAction' method just by referring to them by name in their
-respective *dtml-var* tags.  DTML used its `lookup
-rules <AppendixE.html>`_ to search for the variable names.  It found
-the names in the "REQUEST.form" namespace and displayed them.  If
-it had found an object with either name *email_addr* or
-*user_name* earlier in the lookup (if perhaps there was a Zope
-object in your acquisition path named 'user_name') it would have
-found this object first and rendered its results.  But, mostly by
-chance, it didn't, and found the name in REQUEST instead.
-
-Let's examine the contents of the Zope REQUEST object in order to
-shed more light on the situation.  Create a new DTML Method object
-named 'show_request' in your sandbox folder.  Give it the the
-following body::
-
-  <dtml-var REQUEST>
-
-The 'show_request' method will render a human-readable
-representation of Zope's REQUEST object when you click submit on
-the 'infoForm' rendering.  Visit the 'infoForm' method, and change
-it to the following::
-
-  <dtml-var standard_html_header>
-
-  <p>Please send me information on your aardvark adoption
-  program.</p>
-
-  <form action="show_request">
-  name: <input type="text" name="user_name"><br>
-  email: <input type="text" name="email_addr"><br>
-  <input type="submit" name="submit" value=" Submit ">
-  </form>
-
-  <dtml-var standard_html_footer>
-
-We changed the form action of the 'infoForm' method to
-*show_request*.  Now click the *View* tab of the new 'infoForm'
-method.  Fill in some information in the form elements, and click
-*Submit*.  You will see something like the following::
-
-  form
-   submit ' Submit '
-   email_addr 'chrism at zope.com'
-   user_name 'Chris'
-
-  cookies
-   tree-s 'eJzTiFZ3hANPW/VYHU0ALlYElA'
-
-  lazy items
-   SESSION <bound method SessionDataManager.getSessionData of <SessionDataManager instance at 897d020>
-
-  other
-   AUTHENTICATION_PATH ''
-   user_name 'Chris'
-   PUBLISHED <DTMLMethod instance at 8a62670>
-   submit ' Submit '
-   SERVER_URL 'http://localsaints:8084'
-   email_addr 'chrism at zope.com'
-   tree-s 'eJzTiFZ3hANPW/VYHU0ALlYElA'
-   URL 'http://localsaints:8084/DTML_Example/show_request'
-   AUTHENTICATED_USER admin
-   TraversalRequestNameStack []
-   URL0 http://localsaints:8084/DTML_Example/show_request
-   URL1 http://localsaints:8084/DTML_Example
-   URL2 http://localsaints:8084
-   BASE0 http://localsaints:8084
-   BASE1 http://localsaints:8084
-   BASE2 http://localsaints:8084/DTML_Example
-   BASE3 http://localsaints:8084/DTML_Example/show_request
-
-  environ
-   SCRIPT_NAME ''
-   HTTP_ACCEPT_ENCODING 'gzip, deflate, compress;q=0.9'
-   SERVER_PORT '8084'
-   PATH_TRANSLATED '/DTML_Example/show_request'
-   HTTP_ACCEPT 'text/xml...'
-   GATEWAY_INTERFACE 'CGI/1.1'
-   HTTP_COOKIE 'tree-s="eJzTiFZ3hANPW/VYHU0ALlYElA"'
-   HTTP_ACCEPT_LANGUAGE 'en-us, en;q=0.50'
-   REMOTE_ADDR '192.168.1.3'
-   SERVER_NAME 'saints'
-   HTTP_USER_AGENT 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1a+)'
-   HTTP_ACCEPT_CHARSET 'ISO-8859-1, utf-8;q=0.66, *;q=0.66'
-   CONNECTION_TYPE 'keep-alive'
-   channel.creation_time 1027876407
-   QUERY_STRING 'user_name=Chris&email_addr=chrism%40zope.com&submit=+Submit+'
-   SERVER_PROTOCOL 'HTTP/1.1'
-   HTTP_KEEP_ALIVE '300'
-   HTTP_HOST 'localsaints:8084'
-   REQUEST_METHOD 'GET'
-   PATH_INFO '/DTML_Example/show_request'
-   HTTP_REFERER 'http://localsaints:8084/DTML_Example/infoForm'
-
-You have instructed the 'show_request' method to render the
-contents of the web request initiated by the 'infoForm' method.
-Note that each section (form, cookies, lazy items, other, and
-environ) represents a *namespace* inside the REQUEST.  DTML
-searches all of these namespaces for the names you refer to in
-your 'infoForm' form.  Note that *email_addr* and *user_name* are
-in the "form" namespace of the REQUEST.  There is lots of
-information in the rendering of the REQUEST, but for us, this is
-the most pertinent.  For more information on the REQUEST object,
-visit the Zope Help system, and choose Zope Help -> API Reference
--> Request.
-
-Dealing With Errors
-~~~~~~~~~~~~~~~~~~~
-
-Let's perform an experiment. What happens if you try to view the
-'infoAction' method you created in the last section directly, as
-opposed to getting to it by submitting the 'infoForm' method?
-Click on the 'infoAction' method and then click the *View* tab.
-You will see results not unlike those in the figure below.
-
-.. figure:: ../Figures/infokeyerror.png
-
-   DTML error resulting from a failed variable lookup
-
-Zope couldn't find the *user_name* variable since it was not in
-the current object, its containers or the web request. This is an
-error that you're likely to see frequently as you learn
-Zope. Don't fear, it just means that you've tried to insert a
-variable that Zope can't find.  You can examine the error by
-visiting the *error_log* object in your root folder.  In this
-case, we know why the error occurred, so visiting the error in the
-*error_log* isn't really necessary.  In this example, you need to
-either insert a variable that Zope can find, or use the 'missing'
-attribute on the var tag as described above::
-
-  <h1>Thanks <dtml-var user_name missing="Anonymous User"></h1>
-
-Understanding where DTML looks for variables will help you figure
-out how to fix this kind of problem.  In this case, you have
-viewed a method that needs to be called from an HTML form like
-*infoForm* in order to provide variables to be inserted in the
-output.
-
-Dynamically Acquiring Content
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Zope looks for DTML variables in the current object's containers
-(its parent folders) if it can't find the variable first in the
-current object. This behavior allows your objects to find and use
-content and behavior defined in their parents.  Zope uses the term
-*acquisition* to refer to this dynamic use of content and
-behavior.
-
-An example of acquisition that you've already seen is how web
-pages use standard headers and footers. To acquire the standard
-header just ask Zope to insert it with the *var* tag::
-
-  <dtml-var standard_html_header>
-
-It doesn't matter where the 'standard_html_method' object or
-property is located. Zope will search upwards in the object
-database until it finds the 'standard_html_header' that is defined
-in the root folder.
-
-You can take advantage of how Zope looks up variables to customize
-your header in different parts of your site. Just create a new
-'standard_html_header' in a folder and it will override global
-header for all web pages in your folder and below it.
-
-Create a new folder in your "sandbox" folder with an id of
-"Green". Enter the 'Green' folder and create a DTML Method with an
-id of "welcome". Edit the 'welcome' DTML Method to have these
-contents::
-
-  <dtml-var standard_html_header>
-
-  <p>Welcome</p>
-
-  <dtml-var standard_html_footer>
-
-Now view the 'welcome' method. It should look like a simple web
-page with the word *welcome*, as shown in the figure below.
-
-.. figure:: ../Figures/welcomedtml.png
-
-   Welcome method
-
-Now let's customize the header for the *Green* folder. Create a
-DTML Method in the *Green* folder with an id of
-"standard_html_header". Give it the following body::
-
-  <html>
-  <head>
-    <style type="text/css">
-    body {color: #00FF00;}
-    p {font-family: sans-serif;}
-    </style>
-  </head>
-  <body>
-
-Notice that this is not a complete web page. For example, it does
-not have an ending '</html>' tag.  This is just a fragment of HTML
-that will be used as a header, meant to be included into other
-pages. This header uses `CSS <http://www.w3.org/Style/CSS>`_
-(Cascading Style Sheets) to make some changes to the look and feel
-of web pages.
-
-Now revisit the 'welcome' method and click its *View* tab again.
-You will see something like the figure below:
-
-.. figure:: ../Figures/welcomegreen.png
-
-   Welcome method with custom header
-
-The rendering now looks quite different. This is because it is now
-using the new header we introduced in the 'Green' folder. This
-header will be used by all web pages in the 'Green' folder and its
-sub-folders.
-
-You can continue this process of overriding default content by
-creating another folder inside the 'Green' folder and creating a
-'standard_html_header' DTML Method there. Now web pages in the
-sub-folder will use their local header rather than the 'Green'
-folder's header.  You can of course also create a
-'standard_html_footer', providing it with local content as well.
-
-Using this pattern you can quickly change the look and feel of
-different parts of your website. If you later decide that an area
-of the site needs a different header, just create one. You don't
-have to change the DTML in any of the web pages; they'll
-automatically find the closest header and use it.
-
-Using Python Expressions from DTML
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-So far we've looked at simple DTML tags. Here's an example::
-
-  <dtml-var getHippo>
-
-This will insert the value of the variable named *getHippo*,
-whatever that may be.  DTML will automatically take care of the
-details, like finding the object which represents the variable and
-calling it if necessary. We call this basic tag syntax *name*
-syntax to differentiate it from *expression* syntax.
-
-When you use DTML name syntax, DTML tries to do the right thing to
-insert the results of the object looked up by the variable name,
-no matter what that object may be. In general this means that if
-the variable is another DTML Method or DTML Document, it will be
-called with appropriate arguments.  However, if the variable is
-*not* another DTML Method or DTML Document, and it requires
-parameters, you need to explicitly pass the arguments along using
-an expression.
-
-*Expressions* used in DTML allow you to be more explicit about how
-to find and call variables. Expressions are tag attributes that
-contain small snippets of code in the Python programming language.
-These are typically referred to as *Python expressions*.
-
-A Python expression is essentially any bit of code that *is not* a
-Python *statement*.  For example, the Python statement 'a = 1'
-assigns "1" to the "a" variable. You cannot use this statement in
-DTML expressions.  Likewise, you cannot use the statement 'print
-"x"' in DTML.  It is not an expression.  Essentially, an
-expression must be a combination of values, variables, and Python
-*operators*.  To find out more about Python's expression syntax,
-see the `Python Tutorial <http://docs.python.org/tutorial/>`_
-at the Python.org website.
-
-An expression always results in a return value.  For example, the
-Python expression "a == 5" returns the integer 1 if "a" is equal
-to the integer 5 or the integer 0 if "a" is not equal to the
-integer 5.  The return value of an expression is used by DTML as
-the *target* of the DTML command.
-
-The primary difference in DTML between using *expressions* as
-targets and *names* as targets is that DTML does some magic after
-it locates a *named* targets that it does not do after it finds an
-expression targets.  For example, after finding object with the
-name 'standard_html_header' in the root folder via the name-syntax
-DTML command '<dtml-var standard_html_header>', DTML *calls* the
-'standard_html_header' object, inserting the results into the
-page.  However, when you use an expression-syntax DTML command,
-like '<dtml-var expr="standard_html_header">', DTML *will not*
-call the 'standard_html_header' object.  Instead it will return a
-representation of the object as a string.  In order to *call* the
-'standard_html_header' object in an expression-syntax DTML tag,
-you need to do it explicitly by passing along arguments.  When you
-delve into the realm of DTML expression syntax, DTML "magic" goes
-away, and you need to become aware of the arguments accepted by
-the target (if any) and pass them along.
-
-Let's create a Script (Python) object named 'getHippo' that *must*
-be called in DTML with expression syntax, because it takes a
-non-optional argument that *named* DTML syntax cannot provide.
-
-Create a Script (Python) in your sandbox folder named *getHippo*.
-Provide it with the following body::
-
-  ## Script (Python) "getHippo"
-  ##bind container=container
-  ##bind context=context
-  ##bind namespace=
-  ##bind script=script
-  ##bind subpath=traverse_subpath
-  ##parameters=trap
-  ##title=
-  ##
-  return 'The hippo was captured with a %s.' % trap
-
-Note that this Script (Python) object takes a single parameter
-named "trap".  It is not an optional parameter, so we need to pass
-a value in to this script for it to do anything useful.
-
-Now let's make a DTML method to call 'getHippo'.  Instead of
-letting DTML find and call *getHippo*, we can use an expression to
-explicitly pass arguments.  Create a DTML method named *showHippo*
-and give it the following body::
-
-  <dtml-var expr="getHippo('large net')">
-
-Here we've used a Python expression to explicitly call the
-'getHippo' method with the string argument, 'large net'.  View the
-'showHippo' DTML Method.  It will return a result not unlike the
-following::
-
-    The hippo was captured with a large net.
-
-To see why we need to use expression syntax to call this script,
-let's modify the 'showHippo' method to use DTML name syntax::
-
-  <dtml-var getHippo>
-
-View the method.  You will receive an error not unlike the
-following::
-
-  Error Type: TypeError
-  Error Value: getHippo() takes exactly 1 argument (0 given)
-
-The 'getHippo' method requires that you pass in an argument,
-'trap', that cannot be provided using DTML name syntax.  Thus, you
-receive an error when you try to view the 'showHippo' method.
-
-Expressions make DTML pretty powerful. For example, using Python
-expressions, you can easily test conditions::
-
-    <dtml-if expr="foo < bar">
-      Foo is less than bar.
-    </dtml-if>
-
-Without expressions, this very simple task would have to be broken
-out into a separate method and would add a lot of overhead for
-something this trivial.
-
-Before you get carried away with expressions, take
-care. Expressions can make your DTML hard to understand. Code that
-is hard to understand is more likely to contain errors and is
-harder to maintain. Expressions can also lead to mixing logic in
-your presentation. If you find yourself staring blankly at an
-expression for more than five seconds, stop. Rewrite the DTML
-without the expression and use a Script to do your logic. Just
-because you can do complex things with DTML doesn't mean you
-should.
-
-DTML Expression Gotchas
-%%%%%%%%%%%%%%%%%%%%%%%
-
-Using Python expressions can be tricky. One common mistake is
-to confuse expressions with basic tag syntax. For example::
-
-  <dtml-var objectValues>
-
-and::
-
-  <dtml-var expr="objectValues">
-
-These two examples if you are to put them in a DTML Method will
-end up giving you two completely different results. The first
-example of the DTML *var* tag will automatically *call* the
-object which is represented by *objectValues*. 
-
-In an expression, you have complete control over the variable
-rendering.  In the case of our example, *objectValues* is a
-method implemented in Python which returns the values of the
-objects in the current folder.  It has no required arguments.
-So::
-
-  <dtml-var objectValues>
-
-will call the method. However::
-
-  <dtml-var expr="objectValues">
-
-will *not* call the method, it will just try to insert
-it. The result will be not a list of objects but a string such
-as '<Python Method object at 8681298>'. If you ever see results
-like this, there is a good chance that you're returning a
-method, rather than calling it.
-
-To call a Python method which requires no arguments from an
-expression, you must use standard Python calling syntax by using
-parenthesis::
-
-  <dtml-var expr="objectValues()">
-
-The lesson is that if you use Python expressions you must know
-what kind of variable you are inserting and must use the proper
-Python syntax to appropriately render the variable.
-
-Before we leave the subject of variable expressions we should
-mention that there is a deprecated form of the expression
-syntax. You can leave out the "expr=" part on a variable
-expression tag.  But *please* don't do this.  It is far too easy
-to confuse::
-
-  <dtml-var aName>
-
-with::
-
-  <dtml-var "aName">
-
-and get two completely different results.  These "shortcuts" were
-built into DTML long ago, but we do not encourage you to use them now
-unless you are prepared to accept the confusion and debugging
-problems that come from this subtle difference in syntax.
-
-Common DTML Tags
-----------------
-
-Below, we discuss the most common DTML tags: the *var* tag, the
-*if* tag, the *else* tag, the *elif* tag, and the *in* tag,
-providing examples for the usage of each.
-
-The *Var* Tag
-~~~~~~~~~~~~~
-
-The *var* tag inserts variables into DTML Methods and Documents.  We've
-already seen many examples of how the *var* tag can be used to insert
-strings into web pages.
-
-As you've seen, the *var* tag looks up variables first in the
-current object, then in its containers and finally in the web
-request.
-
-The *var* tag can also use Python expressions to provide more
-control in locating and calling variables.
-
-*Var* Tag Attributes
-%%%%%%%%%%%%%%%%%%%%
-
-You can control the behavior of the *var* tag using its
-attributes. The *var* tag has many attributes that help you in
-common formatting situations. The attributes are summarized in
-Appendix A. Here's a sampling of *var* tag attributes.
-
-html_quote
-  This attribute causes the inserted values to be HTML quoted. This means that
-  '<', '>' and '&' are escaped. Note that all string values which are retrieved
-  from the REQUEST namespace are HTML-quoted by default. This helps to prevent
-  "cross-site scripting" security holes, where a user could insert some clever
-  JavaScript into a page in order to possibly make you divulge information to
-  him which could be private. For more information, see the `CERT advisory
-  <http://www.cert.org/advisories/CA-2000-02.html>`_ on the topic.
-
-missing
-  The missing attribute allows you to specify a default value to use in
-  case Zope can't find the variable. For example::
-
-    <dtml-var bananas missing="We have no bananas">
-
-fmt
-  The fmt attribute allows you to control the format of the *var* tags
-  output. There are many possible formats which are detailed in `Appendix
-  A <AppendixA.html>`_.
-
-  One use of the *fmt* attribute is to format monetary
-  values. For example, create a *float* property in your root
-  folder called *adult_rate*.  This property will represent
-  the cost for one adult to visit the Zoo.  Give this property
-  the value '2.2'.
-
-  You can display this cost in a DTML Document or Method like so::
-
-    One Adult pass: <dtml-var adult_rate fmt=dollars-and-cents>
-
-  This will correctly print "$2.20". It will round more
-  precise decimal numbers to the nearest penny.
-
-
-*Var* Tag Entity Syntax
-%%%%%%%%%%%%%%%%%%%%%%%
-
-Zope provides a shortcut DTML syntax just for the simple *var*
-tag.  Because the *var* tag is a singleton, it can be represented
-with an *HTML entity* like syntax::
-
-  &dtml-cockatiel;
-
-This is equivalent to::
-
-  <dtml-var name="cockatiel" html_quote>
-
-Entity-syntax-based DTML tags always "html quote" their
-renderings.  The main reason to use the entity syntax is to
-avoid putting DTML tags inside HTML tags. For example, instead
-of writing::
-
-  <input type="text" value="<dtml-var name="defaultValue" html_quote>">
-
-You can use the entity syntax to make things more readable for
-you and your text editor::
-
-  <input type="text" value="&dtml-defaultValue;">
-
-The *var* tag entity syntax is very limited. You can't use
-Python expressions within entity-based DTML syntax and many DTML
-attributes won't work with it. See `Appendix A`_
-for more information on *var* tag entity syntax.
-
-The *If* Tag
-~~~~~~~~~~~~
-
-One of DTML's important benefits is to let you customize your web
-pages. Often customization means testing conditions and responding
-appropriately.  This *if* tag lets you evaluate a condition and
-carry out different actions based on the result.
-
-What is a condition?  A condition is either a true or false
-value. In general all objects are considered true unless they are
-0, None, an empty sequence or an empty string.
-
-Here's an example condition:
-
-objectValues
-  True if the variable *objectValues* exists and
-  is true. That is to say, when found and rendered *objectValues*
-  is not 0, None, an empty sequence, or an empty string.
-
-As with the *var* tag, you can use both name syntax and expression
-syntax. Here are some conditions expressed as DTML expressions.
-
-expr="1"
-  Always true.
-
-expr="rhino"
-  True if the rhino variable is true.
-
-expr="x < 5"
-  True if x is less than 5.
-
-expr="objectValues('File')"
-  True if calling the *objectValues* method with an argument of *File*
-  returns a true value.  This method is explained in more detail in this
-  chapter.
-
-The *if* tag is a block tag. The block inside the *if* tag is executed
-if the condition is true.
-
-Here's how you might use a variable expression with the *if* tag to
-test a condition::
-
-  <p>How many monkeys are there?</p>
-
-  <dtml-if expr="monkeys > monkey_limit">
-    <p>There are too many monkeys!</p>
-  </dtml-if>
-
-In the above example, if the Python expression 'monkeys > monkey_limit'
-is true then you will see the first and the second paragraphs of
-HTML. If the condition is false, you will only see the first.
-
-*If* tags can be nested to any depth, for example, you
-could have::
-
-  <p>Are there too many blue monkeys?</p>
-
-  <dtml-if "monkeys.color == 'blue'">
-    <dtml-if expr="monkeys > monkey_limit">
-      <p>There are too many blue monkeys!</p>
-    </dtml-if>
-  </dtml-if>
-
-Nested *if* tags work by evaluating the first condition, and if that
-condition is true, then they evaluate the second
-condition.  In general, DTML *if* tags work very much like
-Python *if* statements...
-
-Name and Expression Syntax Differences
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-The name syntax checks for the *existence* of a name, as well as
-its value. For example::
-
-  <dtml-if monkey_house>
-    <p>There <em>is</em> a monkey house, Mom!</p>
-  </dtml-if>  
-
-If the *monkey_house* variable does not exist, then this condition
-is false. If there is a *monkey_house* variable but it is false,
-then this condition is also false. The condition is only true is
-there is a *monkey_house* variable and it is not 0, None, an empty
-sequence or an empty string.
-
-The Python expression syntax does not check for variable
-existence. This is because the expression must be valid
-Python. For example::
-
-  <dtml-if expr="monkey_house">
-    <p>There <em>is</em> a monkey house, Mom!</p>
-  </dtml-if>
-
-This will work as expected as long as *monkey_house* exists.  If
-the *monkey_house* variable does not exist, Zope will raise a
-*KeyError* exception when it tries to find the variable.
-
-*Else* and *Elif* Tags
-%%%%%%%%%%%%%%%%%%%%%%
-
-The *if* tag only lets you take an action if a condition is
-true. You may also want to take a different action if the
-condition is false.  This can be done with the DTML *else* tag.
-The *if* block can also contain an *else* singleton tag. For
-example::
-
-  <dtml-if expr="monkeys > monkey_limit">
-    <p>There are too many monkeys!</p>
-  <dtml-else>
-    <p>The monkeys are happy!</p>
-  </dtml-if>
-
-The *else* tag splits the *if* tag block into two blocks, the first
-is executed if the condition is true, the second is executed if
-the condition is not true.
-
-A *if* tag block can also contain a *elif* singleton tag. The *elif*
-tag specifies another condition just like an addition *if* tag.
-This lets you specify multiple conditions in one block::
-
-  <dtml-if expr="monkeys > monkey_limit">
-    <p>There are too many monkeys!</p>
-  <dtml-elif expr="monkeys < minimum_monkeys">
-    <p>There aren't enough monkeys!</p>
-  <dtml-else>
-    <p>There are just enough monkeys.</p>
-  </dtml-if>
-
-An *if* tag block can contain any number of *elif* tags but only
-one *else* tag. The *else* tag must always come after the *elif*
-tags.  *Elif* tags can test for condition using either the name
-or expression syntax.
-
-Using Cookies with the *If* Tag
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-Let's look at a more meaty *if* tag example.  Often when you have
-visitors to your site you want to give them a cookie to identify
-them with some kind of special value.  Cookies are used frequently
-all over the Internet, and when they are used properly they are
-quite useful.
-
-Suppose we want to differentiate new visitors from folks who have
-already been to our site. When a user visits the site we can set a
-cookie. Then we can test for the cookie when displaying pages. If
-the user has already been to the site they will have the
-cookie. If they don't have the cookie yet, it means that they're
-new.
-
-Suppose we're running a special. First time zoo visitors get in
-for half price. Here's a DTML fragment that tests for a cookie
-using the *hasVisitedZoo* variable and displays the price
-according to whether a user is new or a repeat visitor::
-
-  <dtml-if hasVisitedZoo>
-    <p>Zoo admission <dtml-var adult_rate fmt="dollars-and-cents">.</p>
-  <dtml-else>
-    <p>Zoo admission for first time visitors
-         <dtml-var expr="adult_rate/2" fmt="dollars-and-cents"></p>
-  </dtml-if>  
-
-This fragment tests for the *hasVisitedZoo* variable. If the user
-has visited the zoo before it displays the normal price for
-admission. If the visitor is here for the first time they get in
-for half-price.
-
-Just for completeness sake, here's an implementation of the
-*hasVisitedZoo* method as a Python-based Script that has no
-parameters.::
-
-  ## Script(Python) "hasVisitedZoo"
-  ##
-  """
-  Returns true if the user has previously visited
-  the Zoo. Uses cookies to keep track of zoo visits.
-  """
-  request = context.REQUEST
-  response = request.RESPONSE
-  if request.has_key('zooVisitCookie'):
-      return 1
-  else:
-      response.setCookie('zooVisitCookie', '1')
-      return 0
-
-In the chapter entitled `Advanced Zope Scripting <ScriptingZope.html>`_,
-we'll look more closely at how to script business logic with Python.  For
-now it is sufficient to see that the method looks for a cookie and returns
-a true or false value depending on whether the cookie is found or not.
-Notice how Python uses if and else statements just like DTML uses if and
-*else* tags. DTML's *if* and *else* tags are based on Python's. In fact
-Python also has an elif statement, just like DTML.
-
-The *In* Tag
-~~~~~~~~~~~~
-
-The DTML *in* tag iterates over a sequence of objects, carrying out
-one block of execution for each item in the sequence.  In
-programming, this is often called *iteration*, or *looping*.
-
-The *in* tag is a block tag like the *if* tag.  The content of the *in*
-tag block is executed once for every iteration in the *in* tag
-loop. For example::
-
-  <dtml-in todo_list>
-    <p><dtml-var description></p>
-  </dtml-in>
-
-This example loops over a list of objects named *todo_list*. For
-each item, it inserts an HTML paragraph with a description of
-the to do item.
-
-Iteration is very useful in many web tasks.  Consider a site that
-display houses for sale.  Users will search your site for houses
-that match certain criteria.  You will want to format all of those
-results in a consistent way on the page, therefore, you will need
-to iterate over each result one at a time and render a similar
-block of HTML for each result.
-
-In a way, the contents of an *in* tag block is a kind of *template*
-that is applied once for each item in a sequence.
-
-Iterating over Folder Contents
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-Here's an example of how to iterate over the contents of a
-folder. This DTML will loop over all the files in a folder and
-display a link to each one.  This example shows you how to
-display all the "File" objects in a folder, so in order to run
-this example you will need to upload some files into Zope as
-explained in the chapter entitled `Basic Zope Objects <BasicObject.rst>`_.
-Create a DTML Method with the following body::
-
-  <dtml-var standard_html_header>
-  <ul>
-  <dtml-in expr="objectValues('File')">
-    <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></li>
-  </dtml-in>
-  </ul>
-  <dtml-var standard_html_footer>
-
-This code displayed the following file listing, as shown in the
-figure below.
-
-.. figure:: ../Figures/4-4.png
-
-   Iterating over a list of files
-
-Let's look at this DTML example step by step.  First, the *var*
-tag is used to insert your common header into the method.  Next,
-to indicate that you want the browser to draw an HTML bulleted
-list, you have the *ul* HTML tag.
-
-Then there is the *in* tag.  The tag has an expression that is
-calling the Zope API method called *objectValues*.  This method
-returns a sequence of objects in the current folder that match a
-given criteria.  In this case, the objects must be files.  This
-method call will return a list of files in the current folder.
-
-The *in* tag will loop over every item in this sequence.  If there are
-four file objects in the current folder, then the *in* tag will execute
-the code in its block four times; once for each object in the
-sequence.
-
-During each iteration, the *in* tag looks for variables in the
-current object, first. In the chapter entitled `Variables and
-Advanced DTML`_ we'll look more closely at how DTML
-looks up variables.
-
-For example, this *in* tag iterates over a collection of File
-objects and uses the *var* tag to look up variables in each
-file::
-
-  <dtml-in expr="objectValues('File')">
-    <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></li>
-  </dtml-in>
-
-The first *var* tag is an entity and the second is a normal DTML
-*var* tag.  When the *in* tag loops over the first object its
-*absolute_url* and *title_or_id* variables will be inserted in
-the first bulleted list item::
-
-  <ul>
-    <li><a href="http://localhost:8080/FirstFile">FirstFile</a></li>
-
-During the second iteration the second object's *absolute_url*
-and *title_or_id* variables are inserted in the output::
-
-  <ul>
-    <li><a href="http://localhost:8080/FirstFile">FirstFile</a></li>
-    <li><a href="http://localhost:8080/SecondFile">SecondFile</a></li>
-
-This process will continue until the *in* tag has iterated over
-every file in the current folder.  After the *in* tag you
-finally close your HTML bulleted list with a closing *ul* HTML
-tag and the *standard_html_footer* is inserted.
-
-*In* Tag Special Variables
-%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-The *in* tag provides you with some useful information that
-lets you customize your HTML while you are iterating over a
-sequence.  For example, you can make your file library easier to
-read by putting it in an HTML table and making every other table
-row an alternating color, like this, as shown in the figure below.
-
-.. figure:: ../Figures/4-5.png
-
-   File listing with alternating row colors
-
-The *in* tag makes this easy.  Change your file library method a
-bit to look like this::
-
-  <dtml-var standard_html_header>
-
-  <table>
-  <dtml-in expr="objectValues('File')">
-    <dtml-if sequence-even>
-      <tr bgcolor="grey">
-    <dtml-else>
-      <tr>
-    </dtml-if>    
-    <td>
-    <a href="&dtml-absolute_url;"><dtml-var title_or_id></a>
-    </td></tr>
-  </dtml-in>
-  </table>
-
-  <dtml-var standard_html_footer>
-
-Here an *if* tag is used to test for a special variable called
-'sequence-even'.  The *in* tag sets this variable to a true or false
-value each time through the loop.  If the current iteration number is
-even, then the value is true, if the iteration number is odd, it is
-false.
-
-The result of this test is that a *tr* tag with either a gray
-background or no background is inserted for every other object in
-the sequence.  As you might expect, there is a 'sequence-odd' that
-always has the opposite value of 'sequence-even'.
-
-There are many special variables that the *in* tag defines for you.  Here
-are the most common and useful:
-
-sequence-item
-  This special variable is the current item in the
-  iteration.
-
-  In the case of the file library example, each time through the loop
-  the current file of the iteration is assigned to sequence-item.  It
-  is often useful to have a reference to the current object in the
-  iteration.
-
-sequence-index
-  the current number, starting from 0, of iterations
-  completed so far.  If this number is even, 'sequence-even' is true and
-  'sequence-odd' is false.
-
-sequence-number
-  The current number, starting from 1, of iterations
-  completed so far.  This can be thought of as the cardinal position
-  (first, second, third, etc.) of the current object in the loop.
-  If this number is even, 'sequence-even' is false and 'sequence-odd'
-  is true.
-
-sequence-start
-  This variable is true for the very first iteration.
-
-sequence-end
-  This variable is true for the very last iteration.
-
-These special variables are detailed more thoroughly in `Appendix A`_.
-
-Summary
--------
-
-DTML is a powerful tool for creating dynamic content. It allows you to
-perform fairly complex calculations. In the chapter entitled `Variables and
-Advanced DTML`_, you'll find out about many more DTML tags, and more
-powerful ways to use the tags you already have seen. Despite its power, you
-should resist the temptation to use DTML for complex scripting. In the
-chapter entitled `Advanced Zope Scripting`_ you'll find out about how to
-use Python for scripting business logic.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/ExternalTools.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/ExternalTools.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/ExternalTools.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,480 +0,0 @@
-Managing Zope Objects Using External Tools
-##########################################
-
-So far, you've been working with Zope objects in your web browser via the Zope
-Management Interface. This chapter details how to use common non-browser-based
-common to access and modify your Zope content.
-
-Editing Zope content and code in the Zope Management Interface is sometimes
-painful, especially when dealing with Python code, DTML, ZPT, or even just
-HTML. The standard TEXTAREA text manipulation widget provided by most browsers
-has an extremely limited feature set: no syntax highlighting, no auto-indent, no
-key re-bindings, no WYSIWYG HTML editing, and sometimes not even a search and
-replace function!
-
-In short, people want to use their own tools, or at least more feature-rich
-tools, to work with Zope content.
-
-It is possible under most operating systems to use the text "cut and paste"
-facility (Ctrl-C, Ctrl-V under Windows, for example) to move text between
-traditional text/HTML editors and your browser, copying data back and forth
-between the Zope Management interface and your other tools. This is, at best,
-cumbersome.
-
-Luckily, Zope provides features that may allow you to interface Zope directly
-with your existing tools. This chapter describes these features, as well as the
-caveats for working with them.
-
-General Caveats
-===============
-
-Most external tools expect to deal with "file-like" content. Zope objects are
-not really files in the strict sense of the word so there are caveats to using
-external tools with Zope:
-
-- Zope data is not stored in files in the filesystem. Thus, tools which only
-  work on files will not work with Zope without providing a "bridge" between
-  the tool and Zope's file-like representation of its object database. This
-  "bridge" is typically accomplished using Zope's FTP or WebDAV features.
-
-- Zope doesn't enforce any file extension rules when creating objects. Some
-  tools don't deal well with objects that don't have file extensions in their
-  names (notably Macromedia Dreamweaver). To avoid this issue, you may name
-  your objects with file extensions according to their type (e.g. name all of
-  your ZPT objects with an `.html` file extension), or use a tool that
-  understands extension-less "files". However, this approach has numerous
-  drawbacks.
-
-- Creating new objects can sometimes be problematic. Because Zope doesn't have
-  a default object-type-to-file-extension policy, new content will often be
-  created as the wrong "kind" of object. For example, if you upload an HTML
-  file "foo.html" via FTP to a place where "foo.html" did not previously exist,
-  it will be created (by default) as a DTML Document object, whereas you may
-  want it to be created as a Zope Page Template. Zope provides a facility to
-  specify the object type created on a per-folder and per-request basis
-  (PUT_factory) that is detailed in this chapter.
-
-- External tools don't know about Zope object properties. If you modify an
-  object in an external tool, it may forget its property list.
-
-- Some external tools have semantics that can drive Zope crazy. For instance,
-  some like to create backup files with an id that is invalid for Zope. Also,
-  some tools will do a move-then-copy when saving, which creates a new Zope
-  object that is divorced from the history of the original object.
-
-- There is nowhere to send meaningful error messages. These integration
-  features expect a finite set of errors defined by the protocol. Thus, the
-  actual problem reported by Zope, such as a syntax error in a page template,
-  cannot be displayed to the user.
-
-- The interactions between the tools and Zope can vary widely. On the client
-  side, different versions of software have different bugs and features. For
-  instance, using FTP under Emacs will sometimes work by default, but sometimes
-  it needs to be configured. Also, Microsoft has many different implementations
-  of DAV in Windows and Office, each with changes that make life difficult.
-
-- Finally, the semantics of Zope can interfere with the experience. The same
-  file on your hard drive, when copied into www.zope.org and your local copy of
-  Zope, will have different results. In the case of the CMF, Zope will actually
-  alter what you saved (to add metadata).
-
-These caveats aside, you may use traditional file manipulation tools to manage
-most kinds of Zope objects.
-
-FTP and WebDAV
-==============
-
-Most Zope "file-like" objects like DTML Methods, DTML Documents, Zope Page
-Templates, Script (Python) objects and others can be edited with FTP and
-WebDAV. Many HTML and text editors support these protocols for editing
-documents on remote servers. Each of these protocols has advantages and
-disadvantages:
-
-- FTP
-
-  FTP is the File Transfer Protocol. FTP is used to transfer files from one
-  computer to another. Many text editors and HTML editors support FTP.
-
-  Some examples of editors and applications that support FTP are Homesite,
-  KDE suite of applications (Kate, Quanta, Kwrite, Konqueror), Bluefish, and
-  Dreamweaver.
-
-- WebDAV
-
-  `WebDAV <http://www.webdav.org/>`_ is a new Internet protocol based on the
-  Web's underlying protocol, HTTP. DAV stands for Distributed Authoring and
-  Versioning. Because DAV is new, it may not be supported by as many text and
-  HTML editors as FTP.
-
-Using FTP to Manage Zope Content
-================================
-
-There are many popular FTP clients, and many web browsers like Netscape and
-Microsoft Internet Explorer come with FTP clients. Many text and HTML editors
-also directly support FTP. You can make use of these clients to manipulate Zope
-objects via FTP.
-
-Determining Your Zope's FTP Port
-++++++++++++++++++++++++++++++++
-
-In the chapter entitled "Using the Zope Management Interface", you determined
-the HTTP port of your Zope system by looking at Zope's start-up output. You can
-find your Zope's FTP port by following the same process::
-
-  ------
-  2000-08-07T23:00:53 INFO(0) ZServer Medusa (V1.18) started at Mon Aug  7 
-  16:00:53 2000
-  Hostname: peanut
-  Port:8080
-
-  ------
-  2000-08-07T23:00:53 INFO(0) ZServer FTP server started at Mon Aug  7   16:00:53 2000
-  Authorizer:None
-  Hostname: peanut
-  Port: 8021
-  ------
-  2000-08-07T23:00:53 INFO(0) ZServer Monitor Server (V1.9) started on port 8099  
-
-The startup log says that the Zope FTP server is listening to port 8021 on the
-machine named *peanut*>. If Zope doesn't report an "FTP server started", it
-likely means that you need to turn Zope's FTP server on by editing the
-necessary incantation in your INSTANCE_HOME/etc/zope.conf as detailed in the
-chapter entitled `Installing and Starting Zope <InstallingZope.stx>`_.
-
-Transferring Files with WS_FTP
-++++++++++++++++++++++++++++++
-
-*WS_FTP* is a popular FTP client for Windows that you can use to transfer
-documents and files between Zope and your local computer. WS_FTP can be
-downloaded from the `Ipswitch Home Page <http://www.ipswitch.com/>`_.
-
-Too transfer objects between your Zope server and local computer:
-
-- start WS_FTP and enter the Zope IP address or machine name and port
-  information.
-
-- Click the "Connect" button.
-
-- Enter your management username and password for the Zope management
-  interface.
-
-If you type in your username and password correctly, WS_FTP shows you what your
-Zope site looks like through FTP. There are folders and documents that
-correspond exactly to what your root Zope folder looks like through the web, as
-shown in the figure below.
-
-`Viewing the Zope object hierarchy through FTP <img:5-1:Figures/3-3.png>`_
-
-Transferring files to and from Zope is straightforward when using WS_FTP. On
-the left-hand side of the WS_FTP window is a file selection box that represents
-files on your local machine.
-
-The file selection box on the right-hand side of the WS_FTP window represents
-objects in your Zope system. Transferring files from your computer to Zope or
-back again is a matter of selecting the file you want to transfer and clicking
-either the left arrow (download) or the right arrow (upload).
-
-You may transfer Zope objects to your local computer as files using WS_FTP. You
-may then edit them and upload them to Zope again when you're finished.
-
-Transferring files with KDE's Konqueror
-+++++++++++++++++++++++++++++++++++++++
-
-KDE is one of the many popular window manager for Unix. KDE comes with many
-applications that is FTP enabled. One such application is Konqueror. Konqueror
-is a file manager, and also works as a browser.
-
-To use Konqueror to transfer files to your zope site:
-
-- enter ftp://username@your.server.com:port
-
-- Enter your username and password when prompted.
-
-Once the correct password is presented, you can now transfer files to and from
-your zope site.
-
-With Konqueror, you can split the Konqueror view, and make it to mimic WS_FTP,
-or Midnight Commander (a popular menu based file manager), as shown in the
-figure below.
-
-`Viewing the Zope object hierarchy with Konqueror <img:5-2:Figures/konq.png>`_
-
-We can also edit, create or delete some known Zope objects like folder or ZPT.
-For instance, to edit a file-like object, right click > Open With > Choose
-Application > Kate. You can start editing away. Kate will do the necessary when
-you save your edits.
-
-Transferring files with MS Internet Explorer 6+
-+++++++++++++++++++++++++++++++++++++++++++++++
-
-MS Internet Explorer version 6 and above can also do FTP. To use MS Internet
-Explorer to move files between your desktop and Zope:
-
-- enter ftp://your.server.com:port
-
-- click "File" > "Login as".
-
-- Enter your username and password when prompted.
-
-You can then create new Folders and transfer files between Zope and your
-desktop, as shown in the figure below.
-
-`Viewing the Zope object hierarchy with IE <img:5-3:Figures/ie.png>`_
-
-Remote Editing with FTP/DAV-Aware Editors
-+++++++++++++++++++++++++++++++++++++++++
-
-Editing Zope Objects with Emacs FTP Modes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Emacs is a very popular text editor. Emacs comes in two major "flavors", GNU
-Emacs and XEmacs. Both of these flavors of Emacs can work directly over FTP to
-manipulate Zope documents and other textual content.
-
-Emacs will let you treat any remote FTP system like any other local filesystem,
-making remote management of Zope content a fairly straightforward matter. More
-importantly, you need not leave Emacs in order to edit content that lives
-inside your Zope.
-
-To log into Zope, run Emacs. The file you visit to open an FTP connection
-depends on which text editor you are running: XEmacs or Emacs:
-
-Xemacs
-  To visit a remote directory in XEmacs, press Ctrl-X D and enter a directory
-  specification in the form: `/user at server#port:/` This will open a "dired"
-  window to the / folder of the FTP server running on *server* and listening on
-  port *port*.
-
-Emacs
-  To visit a remote directory in Emacs, press Ctrl-X D and enter a directory
-  specification in the form: `/user at server port:/` The literal space is
-  inserted by holding down the Control key and the Q key, and then pressing the
-  space "C-Q".
-
-For the typical Zope installation with XEmacs, the filename to open up an FTP
-session with Zope is */user at localhost#8021:/*.
-
-Emacs will ask you for a password before displaying the directory contents. The
-directory contents of the root folder will look a little like the picture
-below:
-
-`Viewing the Zope Root Folder via ange-ftp <img:5-2:Figures/emacsftp.png>`_
-
-You can visit any of these "files" (which are really Zope objects) by selecting
-them in the usual Emacs way: enter to select, modify the file, Ctrl-X S to
-save, etc. You can even create new "files" by visiting a file via "Ctrl-X
-Ctrl-F". New files will be created as DTML Document objects unless you have a
-PUT_factory (described below) installed to specify a different kind of initial
-object.
-
-The ftp program that ships with Microsoft Windows is incompatible with NTEmacs
-(the Windows NT version of GNU Emacs). To edit Zope objects via "ange-ftp"
-under NTEmacs, it requires that you have a special FTP program. This program
-ships with "Cygwin", a UNIX implementation for Windows. To use NTEmacs download
-and install `Cygwin <http://www.cygwin.org>`_ and add the following to your
-`.emacs` configuration file::
-
-  (setq ange-ftp-ftp-program-name "/cygwin/bin/ftp.exe")
-  (setq ange-ftp-try-passive-mode t)
-  (setq ange-ftp-ftp-program-args '("-i" "-n" "-g" "-v" "--prompt" ""))
-
-Caveats With FTP
-~~~~~~~~~~~~~~~~
-
-In addition to the general caveats listed above, using FTP with Zope has some
-unique caveats:
-
-- You need to be aware of passive mode for connecting to Zope.
-
-- The "move-then-copy" problem is most apparent when using Emacs' ange-ftp.
-
-Editing Zope objects with KDE Desktop
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-KDE comes with many applications that is FTP aware. For example, Kate, Kwrite,
-Quanta, Konqueror, and many more.
-
-To start editing objects with Kate:
-
-- Click "File" > "Open".
-
-- Enter the location "ftp://user@server:port/"
-
-- Browse and select the zope object you want to edit.
-
-Once selected, you can edit to your heart's content, and click "File" > "Save"
-when done. Kate will save your edit to your zope server.
-
-`Viewing the Zope Root Folder via Kate/KDE desktop <img:5-2:Figures/kateftp.png>`_
-
-With KDE, you can also mount zope onto your dialog box. To do that:
-
-- click "File" > "Open".
-
-- Right click on the listed locations in the "Open" dialog box
-
-- Click "Add Entry".
-
-- Fill in "Zope ftp" or any other description in the description field.
-
-- Enter the URL "ftp://user@server:port/" in the location field.
-
-- Select your icon.
-
-Now, you can edit zope objects in a single click.
-
-`Zope root exposed to KDE desktop <img:5-2:Figures/kdeopen.png>`_
-
-
-Editing Zope Objects with WebDAV
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-WebDAV is an extension to the HTTP protocol that provides features that allow
-users to concurrently author and edit content on websites. WebDAV offers
-features like locking, revision control, and the tagging of objects with
-properties. Because WebDAV's goals of through the web editing match some of the
-goals of Zope, Zope has supported the WebDAV protocol for a fairly long time.
-
-WebDAV is a newer Internet protocol compared to HTTP or FTP, so there are fewer
-clients that support it. There is, however, growing momentum behind the WebDAV
-movement and more clients are being developed rapidly.
-
-The WebDAV protocol is evolving quickly, and new features are being added all
-the time. You can use any WebDAV client to edit your Zope objects by simply
-pointing the client at your object's URL and editing it. For most clients,
-however, this will cause them to try to edit the *result* of rendering the
-document, not the *source*>. For DTML or ZPT objects, this can be a problem.
-
-Until clients catch up to the latest WebDAV standard and understand the
-difference between the source of a document and its result, Zope offers a
-special HTTP server you can enable. To enable Zope's WebDAV source server,
-enter the following in zope.conf::
-
-  <webdav-source-server>
-    # valid keys are "address" and "force-connection-close"
-    address 8022
-    force-connection-close off
-  </webdav-source-server>
-
-This server listens on a different port than your normal HTTP server and
-returns different, special source content for WebDAV requests that come in on
-that port.
-
-For more information about starting Zope with a WebDAV source port turned on,
-see the chapter entitled `Installing and Starting Zope <InstallingZope.stx>`_.
-The "standard" WebDAV source port number (according to IANA) is 9800.
-
-Unfortunately, this entire discussion of source vs. rendered requests is too
-esoteric for most users, who will try the regular port. Instead of breaking, it
-will work in very unexpected ways, leading to confusion. Until DAV clients
-support the standard's provision for discovering the source URL, this
-distinction will have to be confronted.
-
-Note
-----
-
-Zope has optional support for returning the source version of a resource on the
-normal HTTP port. It does this by inspecting the user agent header of the HTTP
-request. If the user agent matches a string you have configured into your
-server settings, the source is returned.
-
-This is quite useful, as there are few cases in which authoring tools such as
-cadaver or Dreamweaver will want the rendered version. For more information on
-this optional support, read the section "Environment Variables That Affect Zope
-At Runtime" in `Installing and Starting Zope <InstallingZope.stx>`_.
-
-Editing Zope objects with cadaver
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-One program that supports WebDAV is a command-line tool named `cadaver`. It is
-available for most UNIX systems (and Cygwin under Windows) from `WebDAV.org
-<http://www.webdav.org/cadaver/>`_.
-
-It is typically invoked from a command-line using the command `cadaver` against
-Zope's WebDAV "source port"::
-
-  $ cadaver
-  dav:!> open http://saints.homeunix.com:9800/
-  Looking up hostname... Connecting to server... connected.
-  Connecting to server... connected.
-  dav:/> ls
-  Listing collection `/': (reconnecting...done) succeeded.
-  Coll:  Control_Panel                           0  Jun  14:03
-  Coll:  ZopeBook                                0  Jul  22:57
-  Coll:  temp_folder                             0  Jul  19:47
-  Coll:  tutorial                                0  Jun  00:42
-  acl_users                               0  Dec   2009
-  browser_id_manager                      0  Jun  14:01
-  index_html                             93  Jul  01:01
-  session_data_manager                    0  Jun  14:01
-  standard_error_message               1365  Jan   2009
-  dav:/>
-
-Cadaver allows you to invoke an editor against files while inside the
-command-line facility::
-
-  dav:/> edit index_html
-  Connecting to server... connected.
-  Locking `index_html': Authentication required for Zope on server `saints.homeunix.com':
-  Username: admin
-  Password:
-  Retrying: succeeded.
-  Downloading `/index_html' to /tmp/cadaver-edit-001320
-  Progress: [=============================>] 100.0% of 93 bytes succeeded.
-  Running editor: `vi /tmp/cadaver-edit-001320'...
-
-In this case, the `index_html` object was pulled up for editing inside of the
-`vi` text editor. You can specify your editor of choice on most UNIX-like
-systems by changing the EDITOR environment variable.
-
-You can also use cadaver to transfer files between your local directory and
-remote Zope, as described above for WS_FTP. For more advanced synchronization
-of data, the `sitecopy` program can inspect your local and remote data and only
-transfer the changes, using FTP or DAV.
-
-Editing Zope objects with KDE applications
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-KDE applications are WebDAV aware. Therefore, we can actually edit Zope objects
-from any of the KDE applications, such as konqueror, quanta, kate, et cetera.
-
-Using konqueror:
-
-- enter::
-
-    webdav://your.server:port/ in the konqueror location.
-
-- enter the username and password when prompted.
-
-- start editing when konqueror presents the Zope workspace.
-
-`Viewing the Zope object hierarchy with konquerorWebDAV <img:Figures/webdavkonq.png>`_
-
-
-Using Kate:
-
-- Open Kate
-
-- Click File > Open
-
-- Enter::
-
-    webdav://your.server:port/
-
-  in "Open File dialog" "Location"
-
-- Browse for your file or start editing.
-
-`Kate Open File dialog box WebDAV <img:Figures/webdavkate.png>`_
-
-
-Other Integration Facilities
-============================
-
-This chapter focused on FTP and DAV. These are the most popular and mature
-approaches for integration. However, other choices are available.
-
-For instance, Zope has long supported the use of HTTP PUT, originally
-implemented by Netscape as "Netscape Publishing". This allows Netscape
-Composer, Mozilla Composer, and Amaya to edit and create new pages, along with
-associated elements such as images and stylesheets.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/InstallingZope.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/InstallingZope.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/InstallingZope.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,619 +0,0 @@
-Installing and Starting Zope
-============================
-
-By the end of this chapter, you should be able to install and start
-Zope.  It is fairly easy to install Zope on most platforms, and it
-typically takes no longer than ten minutes to complete an installation.
-
-Downloading Zope
-----------------
-
-There are typically two types of Zope releases: a "stable" release
-and a "development" release.  If you are new to Zope, you almost
-certainly want to use the "stable" Zope release.
-
-You may download Zope from the `Zope.org <http://www.zope.org/>`_ web
-site, from which the most recent stable and development versions are always
-available in the `Download <http://www.zope.org/Products/>`_
-area.
-
-Zope comes as a "binary" release for the Windows platform, and in source
-format for UNIX-like operating systems. Zope may be compiled on almost any
-UNIX-like operating system.  Zope has reportedly been successfully compiled
-on Linux, FreeBSD, NetBSD, OpenBSD, Mac OS X, HPUX, IRIX, DEC OFS/1, and
-even Cygwin (the UNIX emulation platform for Windows).
-
-As a general rule of thumb: if `Python <http://www.python.org/>`_ is
-available for your operating system, and if you have a C compiler and
-associated development utilities, then it is highly likely that you will be
-able to compile Zope.  A notable exception is Mac OS between versions 7
-through 9, as Zope does not run at all on these platforms.
-
-Installing Zope
----------------
-
-Zope's installation steps vary somewhat, depending on your operating system
-platform.  The sections below detail installing the binary version of Zope
-on Windows on Intel platforms, and a source installation on Linux.
-
-Installing Zope for Windows With Binaries from Zope.org
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The "Win32" version of Zope works under Windows 95, Windows 98, Windows ME,
-Windows NT, Windows 2000, Windows XP, and Windows Server 2003.  Zope for
-Windows comes as a self-installing *.exe* file.  To install Zope, first,
-download the Win32 executable installer from the
-`Download`_ area on Zope.org.  It is
-typically named something like "Zope-2.X.X-win32-x86.exe" where the "X"'s
-refer to the current Zope version number.
-
-.. figure:: ../Figures/download-zope.png
-
-   Current stable Zope release for Windows
-
-Download the current stable release installer for Windows from
-Zope.org using your web browser.  Place the file in a temporary
-directory on your hard disk or on your Desktop.  Once the
-installer file has been downloaded, navigate to the folder into
-which you downloaded the file, and double-click on the file's
-icon.  The installer then begins to walk you through the
-installation process.
-
-.. figure:: ../Figures/installer-package-icon.png
-
-   Zope installer
-
-.. figure:: ../Figures/installer-first-screen.png
-
-   Beginning the installer
-
-Click *Next*. The installer asks for an installation path. The default is
-usually acceptable, though you are, of course, free to choose another path.
-Then click *Next*. You then can choose which components to install.
-
-.. figure:: ../Figures/component-selection.png
-
-   Select components
-
-You should select "Full installation" unless you have previously installed
-Zope and know what you are doing. On the next screen, you may customize the
-entry placed in your *Start Menu* folder. Click *Next* again. The installer
-now asks you whether you would like to run Zope as a *service*, unless you
-are running Windows 98 or ME, on which such services are not available. If
-you are only running Zope for personal use, there is no need to run it as a
-service.
-
-.. figure:: ../Figures/start-as-service.png
-
-   Server options
-
-Upon clicking *Next*, the installer takes you to the "Instance Setup"
-Screen.
-
-.. figure:: ../Figures/instance-path.png
-
-   Instance setup
-
-You can have more than one Zope running on your PC, but each has to have
-its own *Instance Home*, which is the path to specify here.  This path is
-where Zope will later place its database files. Make sure that you have
-enough disk space left on the specified drive and that you can make backups
-easily.
-
-The *Next* screen asks you for a password for an initial administrative
-account. You use this account to log in for the first time and create more
-users. Note that the installer does not ask you to verify your password, so
-be careful not to mis-type it.
-
-.. figure:: ../Figures/instance-passwd.png
-
-   Administrative password
-
-Click *Next* after entering a password. The installer presents an overview,
-form which you can commence installation by clicking *Install*. After a few
-moments, the Zope installer will present you with a "Completion" screen.
-
-.. figure:: ../Figures/installer-complete.png
-
-   Installation completion
-
-Let the installer start Zope for you, or start Zope manually by navigating
-to the Zope folder in the Start Menu and selecting "Run Zope in Console".
-See the section below entitled `Starting Zope`_.
-
-Compiling and Installing Zope from Source Code
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If binaries aren't available for your platform, chances are good that you
-will be able to compile Zope from its source code.  To do this, however,
-you first must:
-
-- ensure that you have a "C" compiler on your system (*GNU gcc* is
-  preferred);
-
-- ensure that you have a recent "make" on your system (*GNU make* is
-  preferred);
-
-- install the `Python <http://www.python.org/>`_ language on your
-  system from source, or install a binary Python package, including
-  development headers.
-
-Zope is written primarily in the Python language, and Zope requires Python
-in order to be able to run at all.  While binary versions of Zope ship with
-a recent Python version, the source Zope distribution does not.  Zope
-developers try to use the most recent Python for Zope, but often the latest
-Python version is more recent than the officially-supported Zope version.
-Zope 2.12 requires Python 2.5.4 or later, and Zope versions 2.11 and 2.10
-require a Python 2.4.*x* version equal to or greater than 2.4.3.  For the
-most recent information on which version of Python is required for
-compiling Zope, see the release notes on the release Web page.
-
-You can obtain detailed instructions for downloading, compiling, and
-installing Python from source at the `Python.org <http://www.python.org/>`_
-website.  Most Linux distributions ship with a pre-installed Python 2.5,
-but care is required when attempting to use a vendor-installed Python to
-compile Zope: some of these vendor-supplied Python distributions do not
-ship the necessary Python development files needed to compile Zope from
-source.  Sometimes these development files are included in a separate
-"python-devel" package that may be installed separately, but sometimes they
-are not.  The binary packages that ship with Debian have been used with
-some level of success, but it is generally advisable to compile and install
-Python from source if you wish to also compile and install Zope from
-source.
-
-After downloading, compiling, and installing Python from source, download
-the current Zope source distribution.  See the Zope.org `Downloads
-<http://www.zope.org/Products>`_ area for the latest Zope source release.
-
-Download the source to your home, or some other directory, 'cd' to that
-directory, and unpack it with something similar to::
-
-  $ mkdir ~/myzope
-  $ cd ~/myzope
-  $ gunzip -c /tmp/Zope-*.tgz | tar xvf -
-
-where * represents the Zope release version of the source tarball.
-
-Zope now uses the conventional UNIX build sequence:
-``configure``, ``make``, ``make install``.
-
-To configure Zope, 'cd' to the Zope directory and issue the configure
-command::
-
-  $ cd Zope-*
-  $ ./configure --prefix=/where/to/install/zope
-
-Replace */where/to/install/zope* above with an appropriate path, such as
-``~/myzope/zope2``.  This path is referred to as the *ZOPE_HOME*.  If you
-want to install Zope in a system directory instead of your user home,
-replace ``~/myzope/zope2`` with an appropriate path, e.g.,
-``/usr/local/zope2``, and make sure that you have suitable privileges for
-installing and starting Zope ('sudo' or 'root').
-
-If the configure script is unable to find your Python installation, it will
-report an error not unlike this one::
-
-  $ ./configure --prefix=~/myzope/zope2
-
-  Configuring Zope installation
-  Testing for an acceptable Python interpreter...
-
-  No suitable Python version found. You should install
-  Python version 2.5.4 before continuing. Versions
-  2.6.1 2.6.0 also work, but not as optimally.
-
-In this case, you must point the installer to your Python interpreter,
-which you should have installed previously, either from a binary package or
-compiled from source.
-
-Use the ``--with-python`` option to the configure script, e.g,. for a python
-living under ``/usr/local`` ::
-
-  $ ./configure --prefix=~/myzope/zope2 \
-  --with-python=/usr/local/bin/python
-
-Replace ``/usr/local/bin/python`` with the path to your Python executable.
-
-Zope is now ready to be built. From within the source directory, issue::
-
-  $ make
-  [ lots of output snipped ]
-  Zope built. Next, do 'make install' (or 'make instance'
-  to run a Zope instance directly from the build directory).
-
-You are now ready to install Zope. To do this, you will have to execute
-'make install' ::
-
-  $ make install
-  [ lots of output snipped ]
-  Zope binaries installed successfully.
-  Now run '~/myzope/zope2/bin/mkzopeinstance.py'
-
-With the Zope binaries installed, you are now ready to create a *Zope
-instance*, which holds configuration and runtime data for a single Zope
-server process.  This helps keep your own or third-party software separate
-from the main Zope source.
-
-Assuming that you want to install a Zope instance in the directory
-``~/myzope/instance``, in order to create a Zope instance, you would run
-the following command::
-
-  $ ~/myzope/zope2/bin/mkzopeinstance.py
-
-You will need to provide the following values:
-
-- The directory where your instance should be located, or the *INSTANCE_HOME*.
-  The instance home will hold your database files, log files, configuration
-  files, and scripts to start and stop the instance. For our example, we assume
-  the instance home to be located at ``~/myzope/instance``.
-
-- Username and Password for an initial Zope user. You will log in with
-  this username and password to create your own Zope users.  To change the
-  username or password for your initial Zope user, run::
-
-  $ cd ~/myzope/instance
-  $ ~/myzope/zope2/bin/zpasswd.py inituser
-
-You will have to provide the username and password you wish to set;
-optionally, you can specify the hashing method and an additional domain
-restriction.
-
-Zope installation is now complete. Read on to see how to
-start your brand-new Zope.
-
-
-Starting Zope
--------------
-
-Zope is managed via a web browser, and Zope contains its own web server
-(called ``ZServer``).  A successful Zope startup implies that Zope's web
-server starts, which allows you to access the Zope management interface
-(ZMI) via your web browser.  You can access the ZMI from the same machine
-on which Zope runs, or you can access it from a remote machine that is
-connected to the same network as your Zope server.
-
-Zope's ZServer will "listen" for HTTP requests on TCP port 8080.  If your
-Zope instance fails to start, make sure that another application isn't
-already running on the same TCP port (8080).
-
-Zope also has the capability to listen on other TCP ports.  Zope supports
-separate TCP ports for FTP (File Transfer Protocol), "monitor" (internal
-debugging), WebDAV (Web Distributed Authoring and Versioning), and ICP
-(Internet Cache Protocol) access.  If you see messages that indicate that
-Zope is listening on ports other than the default 8080 HTTP, don't panic:
-it's likely just one of these additional ports.
-
-Using Zope With an Existing Web Server
---------------------------------------
-
-If you wish, you can configure your existing web server to serve Zope
-content.  Zope interfaces with Microsoft IIS, Apache, and other popular
-webservers.
-
-The `Virtual Hosting Services <VirtualHosting.html>` chapter of this book
-provides rudimentary setup information for configuring Zope behind Apache.
-However, configuring Zope for use behind an existing web server can be a
-complicated task, and there is more than one way to get it done.  Here are
-some additional resources that should get you started:
-
-- IIS: see `brianh's HowTo
-  <http://www.zope.org/Members/brianh/iis_howto>`_ on using IIS with Zope.
-  Also of interest may be the ``WEBSERVER.txt`` file in your Zope
-  installation's ``doc`` directory, and hiperlogica's `Connecting IIS to
-  Zope <http://www.zope.org/Members/hiperlogica/ASP404>`_ article.
-
-If you are just getting started with Zope, note that it is not necessary to
-configure Apache, IIS, or any other web server to serve your Zope pages, as
-Zope comes with its own web server.  You typically only need to configure
-your existing web server if you want to use it to serve Zope pages in a
-production environment.
-
-Starting Zope on Windows
-------------------------
-
-If you've installed Zope to "run manually" (as opposed to installing Zope
-as a "service"), navigate to the Zope folder in your Start Menu and click
-on *Run Zope in Console*. A console window with process startup information
-will be displayed.
-
-If you chose to run Zope as a "service" on Windows NT/2000/XP, you can
-start Zope via the standard Windows "Services" control panel application.
-A Zope instance started as a service writes events to the standard Windows
-Event Log; you can keep track of the Zope service's start and stop events
-by reviewing the Event Log.  A Zope instance which has been installed as a
-"service" can also be run manually by invoking the *Run Zope in Console*
-menu entry as described earlier. Take care not to run Zope manually *and*
-as a service at one time: make sure to stop the Zope service first before
-starting it manually.
-
-Starting Zope on UNIX
----------------------
-
-.. Important:
-   If you installed Zope from an RPM or a another "vendor distribution"
-   instead of installing a Zope Foundation-distributed source release,
-   the instructions below may be not be applicable.  Under these
-   circumstances, please read the documentation supplied by the vendor to
-   determine how to start your Zope instance instead of relying on these
-   instructions.
-
-To start your Zope instance (which we assume lives in ``~/myzope/instance``),
-issue the command::
-
-  $ ~/myzope/instance/bin/zopectl start
-
-This will start the instance in the background. Alternatively, you can
-start it in the foreground and watch its progress by issuing the command::
-
-  $ ~/myzope/instance/bin/zopectl fg
-
-Run the ``zopectl`` script with a parameter of ``help`` to get a
-list of additional commands::
-
-  $ ~/myzope/instance/bin/zopectl help
-
-
-Starting Zope as the Root User
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-``ZServer`` (Zope's server) supports ``setuid()`` on POSIX systems in order
-to be able to listen on low-numbered ports, such as 21 (FTP) and 80 (HTTP),
-but drop root privileges when running; on most POSIX systems, only the
-``root`` user can do this.
-
-The most important thing to remember about this support is that you don't
-*have* to start ZServer as root, unless you want to listen for requests on
-"low" ports.  In fact, if you don't have this need, you are much better off
-just starting ZServer as a user account dedicated to running Zope.
-'nobody' is not a good idea for this user account, because if any other
-daemon on a system that ran as ``nobody`` were to be compromised, this would
-open up your Zope object data to vulnerability.
-
-If you do need to have ZServer listening on low ports, you will need to
-start ``zopectl`` as the ``root`` user, and to specify what user ZServer
-should ``setuid()`` to.  This can be done by setting the *effective-user*
-parameter in your Zope instances configuration file, residing in
-``$INSTANCE_HOME/etc/zope.conf``, and by making sure that the log and
-database files are writeable by this user.
-
-
-Your Zope Installation
-----------------------
-
-To use and manage Zope, you will need a web browser. Start a web browser on the
-same machine on which you installed Zope, and browse to the URL
-`http://localhost:8080/ <http://localhost:8080/>`_.
-
-If your Zope instance has been properly installed, and you're visiting the
-correct URL, you will be presented with the Zope "QuickStart" screen.
-
-.. figure:: ../Figures/quickstart.png
-
-   Zope QuickStart
-
-If you see this screen, congratulations!  You've installed Zope
-successfully.  If you don't, see the `Troubleshooting and Caveats`_ section
-below.
-
-Logging In
-----------
-
-For some of the tasks you want to do with Zope, you need to use its management
-interface: the *ZMI*. To log into the ZMI, use your web browser to navigate to
-Zope's management URL. Assuming you have Zope installed on the same machine
-from which you are running your web browser, the Zope management URL will be
-`http://localhost:8080/manage <http://localhost:8080/manage>`_.
-
-Successful contact with Zope via this URL will result in an authentication
-dialog, into which you can enter the "initial" username and password you
-chose when you installed Zope.  You will then be presented with the ZMI.
-
-.. figure:: ../Figures/zmi.png
-
-   The Zope Management Interface (ZMI)
-
-If you do not see an authentication dialog and the ZMI, refer to the
-`Troubleshooting and Caveats`_ section of this chapter.
-
-Controlling the Zope Process with the Control Panel
----------------------------------------------------
-
-When you are using the ZMI, you can use the Zope *Control Panel* to control
-the Zope process.  Find and click the **Control_Panel** object in ZMI.
-
-.. figure:: ../Figures/controlpanel.jpg
-
-   The Control Panel
-
-The Control Panel displays information about your Zope, such as the Zope
-version you are running, the Python version that Zope is using, the system
-platform, the INSTANCE_HOME, the CLIENT_HOME, Zope's process id, the network
-services that have been started, how long Zope has been running for, and
-other installation specifics.  Several buttons and links will also be
-shown.
-
-If you are running Zope on UNIX or as a service on Windows, you will see a
-*Restart* button in the Control Panel.  Clicking *Restart* will cause Zope
-to shut down and then immediately start back up again.  It may take Zope a
-few seconds to come back up and start handling requests.  You don't need to
-shut your web browser down and restart it to resume using Zope after
-pressing *Restart*, as the page refreshes automatically; just wait for the
-Control Panel display to reappear.
-
-To shut Zope down from the ZMI, click *Shutdown*.  Shutting Zope down will
-cause the server to stop handling requests and exit. You will have to
-manually start Zope to resume using it. Shut Zope down only if you are
-finished using it and you have the ability to access the server on which
-Zope is running, so that you can manually restart it later as needed.
-
-
-Controlling the Zope Process from the Command Line
---------------------------------------------------
-
-- If you started Zope in the foreground, press "Ctrl+C" in the terminal
-  window from which you started Zope.
-
-* If you started Zope in the background, use the ``zopectl`` script::
-
-  $ ~/myzope/instance/bin/zopectl stop
-
-* On Unix use the "kill" command against the process id in the
-  "var/Z2.pid" file inside the Zope instance directory::
-
-  $ kill `cat var/Z2.pid`
-
-
-Customizing your Zope instance
-------------------------------
-
-Zope's configuration is done via the file '$INSTANCE_HOME/etc/zope.conf'.
-This contains numerous configuration directives for customization.
-
-The ``zope.conf`` file features extensive inline documentation, which we
-will not reproduce here.  Instead, we will give an overview and some
-additional hints for the most-widely used directives:
-
-Server stanzas and ``port-base``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The ``port-base`` directive, together with stanzas for the individual
-servers, determine the ports on which specific servers listen for incoming
-Zope requests. The stanzas are formed with XML-like constructs::
-
- <http-server>
-   # valid keys are "address" and "force-connection-close"
-   address 8080
- </http-server>
- <ftp-server>
-   ...
- </ftp-server>
- <webdav-source-server>
-   ...
- </webdav-source-server>
-
-The ``address`` directive determines the port on which the respective server
-listens.  The HTTP Server in this example listens on port 8080.
-
-The ``port-base`` directive comes in handy if you want to run several Zope
-instances on one machine.  ``port-base`` specifies an offset to the port on
-which **all** servers listen.  Let us assume that our HTTP Server's
-'address' directive is set to 8080, as in our example above, and
-'port-base' is specified as 1000. The port on which the HTTP server will
-listen, will be the ``address`` value of 8080, plus the ``port-base`` offset
-value of 1000, or 9080.  Assuming the FTP server's ``address`` directive is
-set to 8021, the FTP Server will then listen on port 9021, and so on.
-
-The ``debug-mode`` directive
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This directive is a switch, specified as either ``on`` or ``off``.  When
-set to ``on`` (the default), Zope runs in *debug mode*, which causes Zope
-to reload file system-based templates, and several other settings suitable
-for development, in real time.  In a production environment, to reduce
-unnecessary overhead, you should ensure that this directive is set to
-``off`` unless you are actively troubleshooting a problem.
-
-Switch the User the Zope process runs as: ``effective-user``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This directive causes Zope to ``setuid(2)`` to the specified user when run
-as root on a UNIX system.  This method boosts system security, as a
-compromised Zope instance would not enable a compromised user to damage
-easily an entire system.  One motivation for running Zope as root in the
-first place is to be able to bind to *privileged* ports, or ports with
-values below 1024.
-
-Logging
-~~~~~~~
-
-Three log facilities are provided:
-
-- *Access logging* logs individual HTTP Requests in a common format,
-  by default to the file ``log/Z2.log`` in your instance home.
-
-- *Event logging* logs Zope events, such as start and stop
-  information and debugging messages.
-
-- *Trace logging* logs detailed Zope debugging information.
-
-Each log message has an associated severity level, ranging from
-``CRITICAL``, ``ERROR``, ``WARN``, and ``INFO``, to ``DEBUG`` and ``ALL``.
-You can specify a filter for log messages with the ``level`` directive
-inside a logger stanza.  Set the level to ``ALL`` to get all log messages,
-or to ``ERROR`` or ``CRITICAL`` to see only the most serious messages.
-
-Although the default is to write the messages to a log file, you can
-instead arrange for log messages to be mailed to you, or to go to
-``syslog(3)`` (on UNIX) or the event log (on MS Windows)
-
-For further documentation, see the inline comments in ``zope.conf``.
-
-
-Troubleshooting and Caveats
----------------------------
-
-Browser cannot connect to port 8080
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If your browser fails to connect with anything on TCP port 8080, your Zope
-instance may be running on a non-standard TCP port (for example, some
-versions of Debian Linux ship with Zope's default TCP port as 9673).  To
-find out exactly which URL to use, look at the logging information Zope
-prints as it starts up when started in the foreground, i.e., when started
-with ``./runzope`` or ``./zopectl fg``. For example::
-
- ...
- ------
- 2009-01-21T21:48:27 INFO(0) ZServer HTTP server started at Wed Jan 21 21:48:27 2009
- Hostname: arod
- Port: 9673
- ------
- 2009-01-21T21:48:27 INFO(0) ZServer FTP server started at Wed Jan 21 21:48:27 2009
- Hostname: arod
- Port: 8021
- ...
-
-The first log entry indicates that Zope's web server is listening on port
-9673 on host ``arod``. This means that the management URL is
-http://arod:9673/manage.
-
-As mentioned previously, Zope only prints to the console when started in
-the foreground, with ``./runzope`` or ``runzope.bat``. This logging
-information can be found in the ``log/event.log`` file in your
-``INSTANCE_HOME`` directory.
-
-Forgot administrative password
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you forget or lose your initial Zope user name and password, shut Zope
-down, change the initial user password with the *zpasswd.py* script, and
-restart Zope. See the chapter entitled `Users and Security
-<Security.html>`_ for more information about configuring the initial user
-account.
-
-When All Else Fails
-~~~~~~~~~~~~~~~~~~~
-
-If there's a problem with your installation that you just cannot solve, do
-not despair.  You have many places to turn for help, including the Zope
-mailing lists and the ``#zope`` IRC channel.
-
-If you are new to open-source software, please realize that, for the most
-part, participants in the various "free" Zope support forums are
-volunteers.  Though they are typically friendly and helpful, they are not
-obligated to answer your questions.  Therefore, it's in your own
-self-interest to exercise your best manners in these forums in order to get
-your problem resolved quickly.
-
-The most reliable way to get installation help is to send a message to the
-general Zope mailing list detailing your installation problem.  For more
-information on the available Zope mailing lists, see the
-`Resources <http://www.zope.org/Resources>`_ section of Zope.org.  Typically,
-someone on the "zope at zope.org" list will be willing and able to help you
-solve the problem.
-
-For even more immediate help, you may choose to visit the 
-`#zope <irc://irc.freenode.net/#zope>`_ channel on
-the  IRC (Internet Relay Chat) network.  See the `Freenode
-website <http://freenode.net>`_ for more information on how to connect
-to the FreeNode IRC network.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/IntroducingZope.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/IntroducingZope.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/IntroducingZope.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,463 +0,0 @@
-Introducing Zope
-================
-
-Zope is family of related Python packages focussed on web technologies. The
-first version of Zope has originated from a company called
-`Zope Corporation <http://www.zope.com/>`_.
-
-Today the `Zope Foundation <http://foundation.zope.org/>`_ holds the copyright
-of the Zope source code and supervises a diverse community of open-source
-contributers working on a variety of related projects.
-
-This book is about the original Zope project, today known as Zope2. When we
-refer to Zope in this book without a narrower specification we speak of Zope2.
-
-Other projects include the `Zope3 <http://wiki.zope.org/zope3/Zope3Wiki/>`_ web
-application framework, many individual packages located in the
-`Zope Subversion Repository <http://svn.zope.org/>`_ and projects being based
-or related to these packages like `Grok <http://grok.zope.org/>`_ and
-`Repoze <http://repoze.org/>`_. One of the more widely known applications
-based on top of Zope2 is a content management system called
-`Plone <http://plone.org/>`_.
-
-Zope2 itself is a web framework that allows developers of varying skill
-levels to build *web applications*. This chapter explains Zope's purpose,
-what problems it solves and what audience it targets in greater detail.
-It also describes what makes Zope different and more powerful than
-similar applications.
-
-*NOTE*: The moniker "Zope" stands for the *Z Object Publishing
-Environment* (the "Z" doesn't really mean anything in particular).
-
-The Static Web Site Dilemma
----------------------------
-
-When a company or organization goes through the process of developing and
-eventually deploying a website, one of its most important goals is to
-present timely and up-to-date information to its website visitors.
-
-Let us consider two examples of such time-dependent sites:
-
-- a stock market information site that needs to be updated with
-  new information continually, maybe as often as every five or 10
-  minutes. It will also present information tailored to each
-  visitor's preferred settings (portfolios, stocks to follow, etc.)
-
-- a commercial website that helps its visitors sell and buy used
-  automobiles. It is usually required that such a site run
-  advertisements only for cars that have not yet been sold.  It is
-  also important that new ads be posted immediately after
-  they've been placed by a seller.
-
-These two examples describe two very different sites that
-nevertheless have one basic requirement in common: automated and
-periodic updates of the information presented. If this single
-requirement is not met, these sites will likely be
-unsuccessful.
-
-So, how does Zope work to fulfill such a requirement? To understand
-this, we need to consider how websites are perceived by their
-visitors and the basic ways in which websites can be constructed.
-
-In general, many website visitors think about navigation in terms
-of moving "from page-to-page" within a website.  When they click
-a hyperlink, their browser transports them to a new page.  When they
-hit their browser's *back* button, they are returned to the last page
-they visited, and so on.
-
-Some websites are *static*. A static website stores its
-information in files on a web server. Each file then represents a
-complete page on the website. This may seem like a simple and
-efficient way of creating a website; however, *updating the
-information* within those pages becomes a problem when the site consists of
-more than a few pages, and the pages, or parts of the pages, need to be updated 
-frequently.
-
-The layout of text and images that are displayed in a user's web browser
-when the user visits a website are commonly composed in a simple
-language known as Hyper Text Markup Language (HTML). When a user
-visits a typical website, a chunk of text that is "marked-up"
-with formatting in HTML is transferred between the website and the user's
-browser. The browser interprets the chunk of text and displays text
-and images to the user.  The chunk of text which is transferred is
-typically referred to as a *page*.
-
-To achieve this, the static website requires a person with a
-privileged level of access (sometimes termed the *webmaster*) to
-manually create and update the site's content.
-
-Typically, this is done by editing a set of text-based files on the *web
-server* (the machine that runs the website), where each file
-represents a single page. In some cases, a site-wide change to the "look-and-feel"
-of a static website requires that the webmaster visit and update
-each and every file that comprises the website.
-
-The webmaster responsible for our automobile advertising website
-has the additional responsibility of keeping the ads themselves
-fresh.  If each page in the website represents an ad for a
-particular automobile, he needs to delete the pages representing
-ads that have expired and create new pages for ads that have been
-recently sold.  He then needs to make sure that no hyperlinks on
-other pages point to any of these deleted pages.
-
-Obviously, this quickly becomes a lot of work.  With any more than a 
-few pages to update each day, this type of repetitive work 
-can become pretty dull.  In addition, being a human being, the webmaster 
-may also make mistakes, such as forgetting to update or remove
-critical pages.  While updating a static website with only 10 to 20
-pages might be dull, it's perfectly manageable.  However, websites
-can typically grow to encompass thousands of files, making the
-process of "timely updates" a non-trivial (and sometimes
-impossible) task.
-
-Somewhere down the line, smart webmasters begin to think to
-themselves, "Wow, this is a lot of work.  It's tedious and
-complicated, and I seem to be making a lot of mistakes.  Computers
-are really good at doing tedious and complicated tasks, and they
-don't make very many mistakes.  I bet my web server computer could
-automatically do a lot of the work I now do manually."  And he would 
-be right.
-
-At this point, the webmaster is ready to be introduced to *web
-applications*. It is in this area where Zope's strength and power
-becomes clear.
-
-
-What Is A Web Application?
---------------------------
-
-A *web application* is a computer program that users invoke by
-using a web browser to contact a web server via the Internet. Users
-and browsers are typically unaware of the difference between
-a web server that fronts a statically-built website
-and one that fronts a web application.  But unlike a
-static website, a web application creates its "pages"
-*dynamically*, or on-the-fly, upon request.  A website that is dynamically-
-constructed uses an a computer program to provide its content.
-These kinds of dynamic applications can be written in any number of
-computer languages.
-
-Web applications are everywhere.  Common examples of web
-applications are those that let you search the web, like *Google*;
-collaborate on projects, like *SourceForge*; buy
-items at an auction, like *eBay*; communicate with other people over
-e-mail, like *Gmail*; or view the latest news ala *CNN.com*.
-
-In a dynamically-constructed website, the webmaster is not
-required to visit the site "page-by-page" in order to update its
-content or style.  Instead, he is able to instruct the web server
-to *generate the site's HTML pages dynamically*, where each page is
-made up of different bits of content. While each bit of content is
-unique, each can nevertheless appear in several pages if so 
-instructed by the web server. In this way, the webmaster is able to create
-a common "look and feel" for the set of pages that make up his
-site. The software on the web server that generates these
-pages is the web application.
-
-If our auto-classifieds webmaster chose to construct a web
-application to maintain his classifieds system, he could maintain a
-list of "current" ads separate from the HTML pages, perhaps stored
-in a database of some kind.  He could then instruct his web
-application to query this database and generate a particular chunk
-of HTML that represented an ad, or an index of ads, when a user
-visited a page in his website.
-
-A framework that allows people to construct a web application is often called a
-*web application server*, or sometimes just an *application server*. Zope is a
-web application server, as are competing products like `WebSphere
-<http://www.ibm.com/websphere/>`_, `JBoss <http://www.jboss.org/jbossas/>`_,
-and (to some extent) `SAP NetWeaver <http://www.sap.com/>`_.
-
-Zope is a web application server, which is not
-a web application in itself; rather it is *framework that allows
-people to construct web applications*. Sometimes this framework is
-called an *application server*.
-
-Using some common computer programming language, an application
-server typically allows a developer to create a web application,
-but it also provides services *beyond* the basic capabilities of
-the programming language used. Examples of such services are web
-page template creation facilities, a common security model, data
-persistence, sessions, and other features that people find useful
-when constructing a typical web application.
-
-
-How You Can Benefit From Using An Application Server
-----------------------------------------------------
-
-If you are considering writing even a moderately-sized web
-application, it is typically a good idea to start your project
-using an application server framework, unless your application
-requirements are extremely specialized.  By starting a web
-application project with an application server framework (as
-opposed to a "raw" computer language, such as Java, Perl, Python, or
-C), you are able to utilize the services of the framework that have
-already been written and proven to work, and you avoid the need to
-write the functionality yourself "from scratch" in a "raw"
-language.
-
-Many application servers allow you to perform some of the following tasks:
-
-Present Dynamic Content -- You may tailor your web site's
-presentation to its users and provide users with search features.
-Application servers allow you to serve dynamic content and typically
-come with facilities for personalization, database integration,
-content indexing, and searching.
-
-Manage Your Web Site -- A small web site is easy to manage, but a
-web site that serves thousands of documents, images, and files
-requires heavy-duty management tools. It is useful to be able to
-manage your site's data, business logic, and presentation from a
-single place.  An application server can typically help manage
-your content and presentation in this way.
-
-Build a Content Management System -- A *content management system* allows
-non-technical editors to create and manage content for your website.
-Application servers provide the tools with which you can build a
-content management system.
-
-Build an E-Commerce Application -- Application servers provide a
-framework in which sophisticated e-commerce applications can be
-created.
-
-Securely Manage Contributor Responsibility -- When you deal with
-more than a handful of web users, security becomes very important.
-You must be able to safely delegate tasks to different
-classes of system users. For example, folks in your engineering
-department may need to be able to manage their web pages and
-business logic, designers may need to update site templates, and
-database administrators need to manage database queries.
-Application servers typically provide a mechanism for access
-control and delegation.
-
-Provide Network Services -- You may want to produce or consume
-*network services*.  A network service-enabled web site must
-to be able to accept requests from other computer programs.  For
-example, if you're building a news site, you may wish to share
-your news stories with another site; you can do this by making
-the news feed a network service.  Or perhaps you want to make
-products for sale on your site automatically searchable from a
-product comparison site.  Application servers 
-offer methods for enabling these kinds of network services.
-
-Integrate Diverse Systems -- Your existing content may be
-contained in many places: relational databases, files, separate
-web sites, and so on.  Application servers typically allow you
-to present a unified view of your existing data by integrating
-diverse, third-party systems.
-
-Provide Scalability -- Application servers allow your web
-applications to scale across as many systems as necessary to
-handle the load demands of your sites.
-
-The Zope application server allows you to perform all of these
-tasks.
-
-
-Why Use Zope Instead of Another Application Server
---------------------------------------------------
-
-If you're in the business of creating web applications, Zope can
-potentially help you create them at less cost and at a faster rate
-than you could by using another competing web application server.
-This claim is backed by a number of Zope features:
-
-- Zope is free of cost and distributed under an open-source
-  license.  There are many non-free commercial application servers
-  that are relatively expensive.
-
-- Zope itself is an inclusive platform.  It ships with all the
-  necessary components to begin developing an application.  You
-  don't need to license extra software to support Zope (e.g., a
-  relational database) in order to develop your application.  This
-  also makes Zope very easy to install.  Many other application
-  servers have "hidden" costs by requiring that you license
-  expensive software or configure complex, third-party
-  infrastructure software before you can begin to develop your
-  application.
-
-- Zope allows and encourages third-party developers to package and
-  distribute ready-made applications.  Due to this, Zope has a
-  wide variety of integrated services and add-on packages
-  available for immediate use.  Most of these components, like
-  Zope itself, are free and open-source.  Zope's popularity has
-  bred a large community of application developers.
-
-- Applications created in Zope can scale almost linearly using
-  Zope's built-in "Zope Enterprise Objects" (ZEO) clustering
-  solution.  Using ZEO, you can deploy a Zope application across
-  many physical computers without needing to change much (if any)
-  of your application code.  Many application servers don't scale
-  quite as transparently or as predictably.
-
-- Zope provides a granular and extensible security framework.  You
-  can easily integrate Zope with diverse authentication and
-  authorization systems, such as LDAP, Kerberos, and RADIUS,
-  simultaneously and using pre-built modules.  Many other application
-  servers lack support for important authentication and
-  authorization systems.
-
-- Zope runs on most popular microcomputer operating system
-  platforms: Linux, Windows, Solaris, FreeBSD, NetBSD,
-  OpenBSD, and Mac OS X.  Many
-  other application server platforms require that you run an
-  operating system of their licensor's choosing.
-
-- Zope can be extended using the interpreted `Python <http://www.python.org/>`_
-  scripting language. Python is popular and easy to learn, and it promotes
-  rapid development. Many libraries are available for Python that can be used
-  when creating your own application. Many other application servers must be
-  extended using compiled languages, such as Java, which cuts down on
-  development speed. Many other application servers use less popular languages
-  for which there are not as many ready-to-use library features.
-
-
-Zope Audiences and What Zope Isn't
-----------------------------------
-
-Managing the development process of a large-scale site can be a
-difficult task. It often takes many people working together to
-create, deploy, and manage a web application.
-
-*Information Architects*
-  make platform decisions and keep track of the "big picture".
-
-*Component Developers*
-  create software intended for reuse and distribution.
-
-*Integrators*
-  integrate the software written by component developers and native
-  application server services, building an application in the process.
-
-*Web Designers*
-  create the site's look and feel.
-
-*Content Managers*
-  create and manage the site's content.
-
-*Administrators*
-  keep the software and environment running.
-
-*Consumers*
-  use the site to locate and work with useful content.
-
-Of the parties listed above, Zope is most useful for *component
-developers*, *integrators*, and *web designers*.  These three
-groups can collaborate to produce an application using
-Zope's native services and third-party Zope *Plugins*.  They 
-typically produce applications useful to *content managers* and
-*consumers* under the guide of the *information architect*.
-*Administrators* deploy the application and tend to the
-application after it is has been created.
-
-Note that Zope is a web application construction framework that
-programmers of varying skill levels may use to create web-based
-applications.  It *is not* itself an application that is ready to
-use "out of the box" for any given application.  For example, Zope
-itself is not a blog, a content management system, or a
-"e-shop-in-a-box" application.
-
-However, freely available *Plugins* built on top of Zope offer these kinds of
-services. At the time of this writing, the `Python Package Index
-<http://pypi.python.org/pypi/>`_ lists roughly 400 `Plugins that you can browse
-<http://pypi.python.org/pypi?:action=browse&c=514>`_ and even reuse in your own
-applications. These include Plugins for blogging, content management,
-internationalization, and e-commerce.
-
-Zope is not a visual design tool.  Tools like Macromedia
-Dreamweaver and Adobe GoLive allow designers to create "look and
-feel".  You may use these tools to successfully manage Zope-based
-web sites, but Zope itself does not replace them.  You can edit
-content "through the web" using Zope, but it does not try to replace the
-features offered by these kind of tools.
-
-
-Introduction to Zope Maintenance and The Zope Community
--------------------------------------------------------
-
-A community of developers is responsible for maintaining and
-extending the Zope application server.  Many community members are
-professional consultants, developers, and webmasters who develop
-applications using Zope for their own gain.  Others are students
-and curious amateur site developers.  Zope Corporation is a member
-of this community.
-
-The Zope Foundation controls the distribution of the defacto,
-"canonical", official Zope version, and permits its developers, as
-well as other selected developers, to modify the distribution's
-source code.
-
-The Zope community gets together occasionally at conferences, but it
-commonly discusses all things Zope on the many Zope mailing
-lists and web sites. You can find out more about Zope-related
-mailing lists at `Zope.org's mailing list page <http://mail.zope.org/mailman/listinfo>`_.
-
-Zope Corporation makes its revenue by using Zope to create web
-applications for its paying customers, by training prospective
-Zope developers, by selling support contracts to companies who use
-Zope, and by hosting Zope-powered websites; it does not make any
-direct revenues from the distribution of the Zope application
-server itself.
-
-
-Zope's Terms of Use and License
--------------------------------
-
-Zope is free of cost. You are permitted to use Zope to create and run your web
-applications without paying licensing or usage fees. You may also include Zope
-in your own products and applications without paying royalty fees to Zope's
-licensor, *Zope Foundation*.
-
-Zope is distributed under an open source license, the `Zope Public License or
-'ZPL' <http://www.zope.org/Resources/License>`_. The terms of the ZPL license
-stipulate that you will be able to obtain and modify the source code for Zope.
-
-The ZPL is different than another popular open source license, the `GNU Public
-License <http://www.gnu.org>`_. The licensing terms of the GPL require that if
-you intend to redistribute a GPL-licensed application, and you modify or extend
-the application in a meaningful way, when you `redistribute
-<http://www.gnu.org/licenses/gpl-faq.html#GPLRequireSourcePostedPublic>`_ a
-GPL-licensed application, you must distribute it under the terms of the GPL,
-including licensing any modifications or extensions you make under the GPL. You
-must also provide the full source code, including source for your
-modifications.
-
-However, this is *not* required for ZPL-licensed applications. You may modify
-and redistribute Zope without contributing your modifications back to Zope
-Corporation, as long as you follow the other terms of the license faithfully.
-
-Note that the ZPL has been `certified`_ as `OSD`_ compliant by the
-`Open Source Initiative`_ and is listed as `GPL compliant`_ by the
-`Free Software Foundation`_.
-
-.. _certified: http://www.opensource.org/licenses/zpl.php
-.. _OSD: http://www.opensource.org/docs/definition.html
-.. _Open Source Initiative: http://www.opensource.org/
-.. _GPL compliant: http://www.gnu.org/philosophy/license-list.html#GPLCompatibleLicenses
-.. _Free Software Foundation: http://www.fsf.org/
-
-
-Zope History
-------------
-
-In 1996, Jim Fulton (the current CTO of Zope Corporation, the orginators of
-Zope) was drafted to teach a class on CGI programming, despite not knowing very
-much about the subject. CGI, or *common gateway interface*, programming is a
-commonly-used web development model that allows developers to construct dynamic
-websites. Jim studied all of the existing documentation on CGI on his way to
-the class. On the way back from the class, Jim considered what he didn't like
-about traditional, CGI-based programming environments. From these initial
-musings, the core of Zope was written on the plane flight back from the class.
-
-Zope Corporation (then known as Digital Creations) went on to release three
-open-source software packages to support web publishing: *Bobo*, *Document
-Template*, and *BoboPOS*. These packages were written in a language called
-Python, and respectively provided a web publishing facility, text templating,
-and an object database. Digital Creations developed a commercial application
-server based on their three open-source components. This product was called
-*Principia*. In November of 1998, investor Hadar Pedhazur convinced Digital
-Creations to open source Principia. These packages have evolved into what today
-are the core components of Zope.
-
-Most of Zope is written in the `Python <http://www.python.org/>`_ scripting
-language, with performance-critical pieces written in C.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/MaintainingZope.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/MaintainingZope.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/MaintainingZope.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,716 +0,0 @@
-Maintaining Zope
-################
-
-Keeping a Zope site running smoothly involves a number of administrative tasks.
-This chapter covers some of these tasks, such as:
-
-  - Starting Zope automatically at boot time
-  - Installing new products
-  - Setting parameters in the Control Panel
-  - Monitoring
-  - Cleaning up log files
-  - Packing and backing up the database
-  - Database recovery tools
-
-Maintenance often is a very platform-specific task, and Zope runs on many
-platforms, so you will find instructions for several different operating
-systems here. It is not possible to provide specifics for every system;
-instead, we will supply general instructions which should be modified according
-to your specific needs and platform.
-
-Starting Zope Automatically at Boot Time
-========================================
-
-For testing and developing purposes you will start Zope manually most of the
-time, but for production systems it is necessary to start Zope automatically at
-boot time. Also, we will want to shut down Zope in an orderly fashion when the
-system goes down. We will describe the necessary steps for Microsoft Windows
-and some Linux distributions. Take a look at the Linux section for other
-Unix-like operating systems. Much of the information presented here also
-applies to System V like Unices.
-
-Debug Mode and Automatic Startup
-++++++++++++++++++++++++++++++++
-
-If you are planning to run Zope on a Unix production system you should also
-disable *debug mode*. This means removing the `-D` option in startup scripts
-(e.g. the `start` script created by Zope at installation time which calls z2.py
-with the `-D` switch) and if you've manually set it, unsetting the
-`Z_DEBUG_MODE` environment variable. In debug mode, Zope does not detach itself
-from the terminal, which could cause startup scripts to malfunction.
-
-On Windows, running Zope as a service disables debug mode by default. You still
-can run Zope in debug mode by setting the `Z_DEBUG_MODE` environment variable
-or running Zope manually from a startup script with the `-D` option. Again,
-this is not recommended for production systems, since debug mode causes
-performance loss.
-
-Automatic Startup for Custom-Built Zopes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Even if you do not want to use the prepackaged Zope that comes with your
-distribution it should be possible to re-use those startup scripts, eg. by
-installing the prepackaged Zope and editing the appropriate files and symlinks
-in `/etc/rc.d` or by extracting them with a tool like `rpm2cpio`.
-
-In the following examples we assume you installed your custom Zope to a
-system-wide directory, eg. `/usr/local/zope`. If this is not the case please
-replace every occurence of `/usr/local/zope` below with your Zope installation
-directory. There should also be a separate Zope system user present. Below we
-assume that there is a user `zope`, group `nogroup` present on your system. The
-user `zope` should of course have read access to the `$ZOPE_HOME` directory
-(the directory which contains the "top-level" Zope software and the "z2.py"
-script) and its descendants, and write access to the contents of the `var`
-directory.
-
-If you start Zope as root, which is usually the case when starting Zope
-automatically on system boot, it is required that the `var` directory belongs
-to root. Set the ownership by executing the command::
-
-  chown root var
-
-as root.
-
-To set up a Zope binary package with built-in python situated in::
-/usr/local/zope running as user `zope` , with a "WebDAV Source port" set to
-8081, you would set::
-
-  ZOPE_HOME=/usr/local/zope
-  PYTHON_BIN=$ZOPE_HOME/bin/python
-  COMMON_PARAMS="-u zope -z $ZOPE_HOME -Z /var/run/zope.pid -l /var/log/Z2.log -W 8081"
-
-You can also set up a file `/etc/sysconfig/zope` with variables ZOPE_FTP_PORT,
-ZOPE_HTTP_PORT::
-
-  ZOPE_HTTP_PORT=80
-  ZOPE_FTP_PORT=21
-
-to set the HTTP and FTP ports. The default is to start them at port 8080 and
-8021.
-
-Unfortunately, all Linux distributions start and stop services a little
-differently, so it is not possible to write a startup script that integrates
-well with every distribution. We will try to outline a crude version of a
-generic startup script which you can refine according to your needs.
-
-To do this some shell scripting knowledge and root system access is required.
-
-Linux startup scripts usually reside in::
-
-  /etc/init.d
-
-or in::
-
-  /etc/rc.d/init.d
-
-For our examples we assume the startup scripts to be in::
-
-  /etc/rc.d/init.d
-
-adjust if necessary.
-
-To let the boot process call a startup script, you also have to place a
-symbolic link to the startup script in the::
-
-  /etc/rc.d/rc?.d
-
-directories, where `?` is a number from 0-6 which stands for the SystemV run
-levels. You usually will want to start Zope in run levels 3 and 5 (3 is full
-multi-user mode, 5 is multiuser mode with X started, according to the "Linux
-Standard Base":http://www.linuxbase.org), so you would place two links in the
-/etc/rc.d' directories. Be warned that some systems (such as Debian) assume
-that runlevel 2 is full multiuser mode. As stated above, we assume the main
-startup script to located in::
-
-  /etc/rc.d/init.d/zope
-
-if your system puts the::
-
-  init.d
-
-directory somewhere else, you should accomodate the paths below::
-
-  # cd /etc/rc.d/rc3.d
-  # ln -s /etc/rc.d/init.d/zope S99zope
-  # cd /etc/rc.d/rc5.d
-  # ln -s /etc/rc.d/init.d/zope S99zope
-
-The scripts are called by the boot process with an argument::
-
-  start
-
-when starting up and::
-
-  stop
-
-on shutdown.
-
-A simple generic startup script structure could be something like this::
-
-  #!/bin/sh
-
-  # set paths and startup options
-  ZOPE_HOME=/usr/local/zope
-  PYTHON_BIN=$ZOPE_HOME/bin/python
-  ZOPE_OPTS=" -u zope -P 8000"
-  EVENT_LOG_FILE=$ZOPE_HOME/var/event.log
-  EVENT_LOG_SEVERITY=-300
-  # define more environment variables ...
-
-  export EVENT_LOG_FILE  EVENT_LOG_SEVERITY
-  # export more environment variables ...
-
-  umask 077
-  cd $ZOPE_HOME
-
-  case "$1" in 
-
-  start)
-  # start service
-  exec $PYTHON_BIN $ZOPE_HOME/z2.py $ZOPE_OPTS
-
-  # if you want to start in debug mode (not recommended for
-  # production systems):
-  # exec $PYTHON_BIN $ZOPE_HOME/z2.py $ZOPE_OPTS -D &
-  ;;
-  stop)
-  # stop service
-  kill `cat $ZOPE_HOME/var/Z2.pid`
-  ;;
-  restart)
-  # stop service and restart
-  $0 stop
-  $0 start
-  ;;            
-  *)
-  echo "Usage: $0 {start|stop|restart}"
-  exit 1
-  ;;
-  esac
-
-This script lets you perform start / stop / restart operations:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-start
-  Start Zope (and the zdaemon management process)
-
-stop
-  Stop Zope. Kill Zope and the zdaemon management process
-
-restart
-  Stop then start Zope
-
-MS Windows
-++++++++++
-
-The prevalent way to autostart Zope on MS Windows is to install
-Zope as a service.
-
-If you installed Zope on Windows NT/2000/XP to be started manually and later on
-want it started as a service, perform these steps from the command line to
-register Zope as a Windows service:::
-
-  > cd c:\Program Files\zope
-  > bin\lib\win32\PythonService.exe /register 
-  > bin\python.exe ZServer\ZService.py --startup auto install
-
-Replace::
-
-  c:\Program Files\zope
-
-with the path to your Zope installation. Zope should now be installed as a
-service which starts automatically on system boot. To start and stop Zope
-manually, go to the Windows service administration tool, right-click the Zope
-service and select the corresponding entry.
-
-Installing New Products
-=======================
-
-Zope is a framework for building websites from new and existing software, known
-as Zope *products*. A product is a Python package with special conventions that
-register with the Zope framework. The primary purpose of a Zope product is to
-create new kinds of objects that appear in the add list. This extensibility
-through products has spawned a broad market of add-on software for Zope.
-
-The guidelines for packaging a product are given in the "Packaging Products"
-section in the `Zope Products chapter of the Zope Developer Guide
-<http://www.zope.org/Products>`_. However, since these guidelines are not
-enforced, many Zope products adhere to different conventions. This section will
-discuss the different approaches to installing Zope packages.
-
-To install a Zope product, you first download an archive file from a website,
-such as the `Downloads section <http://www.zope.org/Products>`_ of zope.org.
-These archive files come in several varieties, such as tgz (gzipped tar files)
-zip (the popular ZIP format common on Windows), and others.
-
-In general, unpacking these archives will create a subdirectory containing the
-Product itself. For instance, the::
-
-  Poll-1.0.tgz
-
-archive file in the "Packaging Products" section mentioned above contains a
-subdirectory of `Poll`. All the software is contained in this directory.
-
-To install the product, you unarchive the file in the::
-
-  lib/python/Products
-
-directory. In the Poll example, this will create a directory::
-
-  lib/python/Products/Poll
-
-Unfortunately not all Zope developers adhere to this convention. Often the
-archive file will have the::
-
-  lib/python/Products
-
-part of the path included. Worse, the archive might contain no directory, and
-instead have all the files in the top-level of the archive. Thus, it is advised
-to inspect the contents of the archive first.
-
-Once you have the new directory in::
-
-  lib/python/Products
-
-you need to tell Zope that a new product has been added. You can do this by
-restarting your Zope server through the Control Panel of the Zope Management
-Interface (ZMI), or, on POSIX systems, by sending the Zope process a::
-
-  -HUP
-
-signal. For instance, from the Zope directory:::
-
-  kill -HUP `cat var/Z2.pid`
-
-If your Zope server is running in debug mode, a log message will appear
-indicating a new product has been discovered and registered.
-
-To confirm that your product is installed, log into your Zope site and visit
-the Control Panel's Products section. You should see the new product appear in
-the list of installed products.
-
-If there was a problem with the installation, the Control Panel will list it as
-a "Broken Product". Usually this is because Python had a problem importing a
-package, or the software had a syntax error. You can visit the broken product
-in the Control Panel and click on its *Traceback* tab. You will see the Python
-traceback generated when the package was imported.
-
-A traceback generally will tell you what went wrong with the import. For
-instance, a package the software depends on could be missing. To illustrate
-this take a look at the traceback below - a result of trying to install
-CMFOODocument:http://www.zope.org/Members/longsleep/CMFOODocument without the
-(required) CMF package:::
-
-  Traceback (most recent call last):
-  File "/usr/share/zope/2.6.0/lib/python/OFS/Application.py", line 541, in import_product
-  product=__import__(pname, global_dict, global_dict, silly)
-  File "/usr/share/zope/2.6.0/lib/python/Products/CMFOODocument/__init__.py", line 19, in ?
-  import OODocument
-  File "/usr/share/zope/2.6.0/lib/python/Products/CMFOODocument/OODocument.py", line 31, in ?
-  from Products.CMFCore.PortalContent import NoWL, ResourceLockedError
-  ImportError: No module named CMFCore.PortalContent
-
-Server Settings
-===============
-
-The Zope server has a number of settings that can be adjusted for performance.
-Unfortunately, performance tuning is not an exact science, that is, there is no
-recipe for setting parameters. Rather, you have to test every change. To load
-test a site, you should run a test setup with easily reproducible results. Load
-test a few significant spots in your application. The trick is to identify
-typical situations while still permitting automated testing. There are several
-tools to load test websites. One of the simple yet surprisingly useful tools
-is::
-
-  ab
-
-which comes with Apache distributions. With `ab` you can test individual URLs,
-optionally providing cookies and POST data. Other tools often allow one to
-create or record a user session and playing it back multiple times. See eg. the
-`Open System Testing Architecture <http://www.opensta.org>`_, `JMeter
-<http://jakarta.apache.org/jmeter>`_, or Microsoft's `Web Application Stress
-Tool
-<http://www.microsoft.com/technet/treeview/default.asp?url=/technet/itsolutions/intranet/downloads/webstres.asp>`_.
-
-Database Cache
-++++++++++++++
-
-The most important is the database cache setting. To adjust these settings,
-visit the Control Panel and click on the *Database* link.`Database Cache
-settings <img:23-1:Figures/dbcache.png>`_
-
-There are usually seven database connections to the internal Zope database (see
-*Database Connections* below for information about how to change the number of
-connections). Each connection gets its own database cache. The "Target number
-of objects in memory per cache" setting controls just that - the system will
-try not to put more than this number of persistent Zope objects into RAM per
-database connection. So if this number is set to 400 and there are seven
-database connections configured, there should not be more than 2800 objects
-sitting in memory. Obviously, this does not say much about memory consumption,
-since the objects might be anything in size - from a few hundred bytes upwards.
-The cache favors commonly used objects - it wholly depends on your application
-and the kind of objects which memory consumption will result from the number
-set here. As a rule, Zope objects are about as big as the data they contain.
-There is only little overhead in wrapping data into Zope objects.
-
-ZServer Threads
-+++++++++++++++
-
-This number determines how many ZServer threads Zope starts to service
-requests. The default number is four (4). You may try to increase this number
-if you are running a heavily loaded website. If you want to increase this to
-more than seven (7) threads, you also should increase the number of database
-connections (see the next section).
-
-Database Connections
-++++++++++++++++++++
-
-We briefly mentioned Zope's internal database connections in the *Database
-Cache* section above. Out of the box, the number of database connections is
-hardwired to seven (7); but this can be changed. There is no "knob" to change
-this number so in order to change the number of database connections, you will
-need to enter quite deep into the systems' bowels. It is probably a wise idea
-to back up your Zope installation before following any of the instructions
-below.
-
-Each database connection maintains its own cache (see above, "Database Cache"),
-so bumping the number of connections up increases memory requirements. Only
-change this setting if you're sure you have the memory to spare.
-
-To change this setting, create a file called "custom_zodb.py" in your Zope
-installation directory. In this file, put the following code::
-
-  import ZODB.FileStorage
-  import ZODB.DB
-
-  filename = os.path.join(INSTANCE_HOME, 'var', 'Data.fs')
-  Storage = ZODB.FileStorage.FileStorage(filename)
-  DB = ZODB.DB(Storage, pool_size=25, cache_size=2000)
-
-This only applies if you are using the standard Zope FileStorage storage.
-
-The "pool_size" parameter is the number of database connections. Note that the
-number of database connections should always be higher than the number of
-ZServer threads by a few (it doesn't make sense to have fewer database
-connections than threads). See above on how to change the number of ZServer
-threads.
-
-Signals (POSIX only)
-====================
-
-Signals are a POSIX inter-process communications mechanism. If you are using
-Windows then this documentation does not apply.
-
-Zope responds to signals which are sent to the process id specified in the file
-'$ZOPE_HOME/var/Z2.pid':
-
-SIGHUP
-  close open database connections, then restart the server process. The common
-  idiom for restarting a Zope server is::
-
-    kill -HUP `cat $ZOPE_HOME/var/Z2.pid`
-
-SIGTERM
-  close open database connections then shut down. The common idiom for shutting
-  down Zope is::
-
-    kill -TERM `cat $ZOPE_HOME/var/Z2.pid`
-
-SIGINT
-  same as SIGTERM
-
-SIGUSR2
-  close and re-open all Zope log files (z2.log, event log, detailed log.) The
-  common idiom after rotating Zope log files is::
-
-    kill -USR2 `cat $ZOPE_HOME/var/Z2.pid`
-
-The process id written to the::
-
-  Z2.pid
-
-file depends on whether Zope is run under the::
-
-  zdaemon
-
-management process. If Zope is run under a management process (as it is by
-default) then the pid of the management process is recorded here. Relevant
-signals sent to the management process are forwarded on to the server process.
-Specifically, it forwards all those signals listed above, plus SIGQUIT and
-SIGUSR1. If Zope is not using a management process (-Z0 on the z2.py command
-line), the server process records its own pid into `z2.pid`, but all signals
-work the same way.
-
-Monitoring
-==========
-
-To detect problems (both present and future) when running Zope on production
-systems, it is wise to watch a few parameters.
-
-Monitor the Event Log and the Access Log
-++++++++++++++++++++++++++++++++++++++++
-
-If you set the EVENT_LOG_FILE (formerly known as the STUPID_LOG_FILE) as an
-environment variable or a parameter to the startup script, you can find
-potential problems logged to the file set there. Each log entry is tagged with
-a severity level, ranging from TRACE (lowest) to PANIC (highest). You can set
-the verbosity of the event log with the environment variable
-EVENT_LOG_SEVERITY. You have to set this to an integer value - see below::
-
-  TRACE=-300   -- Trace messages
-
-  DEBUG=-200   -- Debugging messages
-
-  BLATHER=-100 -- Somebody shut this app up.
-
-  INFO=0       -- For things like startup and shutdown.
-
-  PROBLEM=100  -- This isn't causing any immediate problems, but deserves
-                  attention.
-
-  WARNING=100  -- A wishy-washy alias for PROBLEM.
-
-  ERROR=200    -- This is going to have adverse effects.
-
-  PANIC=300    -- We're dead!
-
-So, for example setting EVENT_LOG_SEVERITY=-300 should give you all log
-messages for Zope and Zope applications that use Zopes' logging system.
-
-You also should look at your access log (usually placed in
-$ZOPE_HOME/var/Z2.log). The Z2.log file is recorded in the `Common Log Format
-<http://www.w3.org/Daemon/User/Config/Logging.html#common-logfile-format>`_.
-The sixth field of each line contains the HTTP status code. Look out for status
-codes of 5xx, server error. Server errors often point to performance problems.
-
-Monitor the HTTP Service
-++++++++++++++++++++++++
-
-You can find several tools on the net which facilitate monitoring of remote
-services, for example `Nagios <http://www.nagios.org/>`_ or `VisualPulse
-<http://www.visualware.com/visualpulse>`_.
-
-For a simple "ping" type of HTTP monitoring, you could also try to put a small
-DTML Method with a known value on your server, for instance only containing the
-character "1". Then, using something along the line of the shell script below,
-you could periodically request the URL of this DTML Method, and mail an error
-report if we are getting some other value (note the script below requires a
-Un*x-like operating system)::
-
-  #!/bin/sh
-
-  # configure the values below
-  URL="http://localhost/ping"
-  EXPECTED_ANSWER="1"
-  MAILTO="your.mailaddress at domain.name"
-  SUBJECT="There seems to be a problem with your website"
-  MAIL_BIN="/bin/mail"
-
-  resp=`wget -O - -q -t 1 -T 1 $URL`
-  if [ "$resp" != "$EXPECTED_ANSWER" ]; then
-  $MAIL_BIN -s "$SUBJECT" $MAILTO <<EOF
-  The URL 
-  ----------------------------------------------
-  $URL 
-  ----------------------------------------------
-  did not respond with the expected value of $EXPECTED_ANSWER. 
-  EOF
-  fi;
-
-Run this script eg. every 10 minutes from cron and you should be set for simple
-tasks. Be aware though that we do not handle connections timeouts well here. If
-the connection hangs, for instance because of firewall misconfiguration `wget`
-will likely wait for quite a while (around 15 minutes) before it reports an
-error.
-
-Log Files
-=========
-
-There are two main sources of log information in Zope, the access log and the
-event log.
-
-Access Log
-++++++++++
-
-The access log records every request made to the HTTP server. It is recorded in
-the `Common Log Format
-<http://www.w3.org/Daemon/User/Config/Logging.html#common-logfile-format>`_.
-
-The default target of the access log is the file $ZOPE_HOME/var/Z2.log. Under
-Unix it is however possible to direct this to the syslog by setting the
-environment variable ZSYSLOG_ACCESS to the desired domain socket (usually
-`/dev/log`)
-
-If you are using syslog, you can also set a facility name by setting the
-environment variable ZSYSLOG_FACILITY. It is also possible to log to a remote
-machine. This is also controlled, you might have guessed it, by an environment
-variable. The variable is called ZSYSLOG_SERVER and should be set to a string
-of the form "host:port" where host is the remote logging machine name or IP
-address and port is the port number the syslog daemon is listening on (usually
-514).
-
-Event Log
-+++++++++
-
-The event log (formerly also called "stupid log") logs Zope and third-party
-application message. The ordinary log method is to log to a file specified by
-the EVENT_LOG_FILE, eg. `EVENT_LOG_FILE=$ZOPE_HOME/var/event.log`.
-
-On Unix it is also possible to use the syslog daemon by setting the environment
-variable ZSYSLOG to the desired Unix domain socket, usually `/dev/log` . Like
-with access logs (see above), it is possible to set a facility name by setting
-the ZSYSLOG_FACILITY environment variable, and to log to a remote logging
-machine by setting the ZSYSLOG_SERVER variable to a string of the form
-"host:port", where port usually should be 514.
-
-You can coarsely control how much logging information you want to get by
-setting the variable EVENT_LOG_SEVERITY to an integer number - see the section
-"Monitor the Event Log and the Access Log" above.
-
-Log Rotation
-++++++++++++
-
-Log files always grow, so it is customary to periodically rotate logs. This
-means logfiles are closed, renamed (and optionally compressed) and new logfiles
-get created. On Unix, there is the `logrotate` package which traditionally
-handles this. A sample configuration might look like this::
-
-  compress 
-  /usr/local/zope/var/Z2.log {
-  rotate 25
-  weekly
-  postrotate
-  /sbin/kill -USR2 `cat /usr/local/zope/var/Z2.pid`
-  endscript
-  }
-
-This would tell logrotate to compress all log files (not just Zope's!), handle
-Zopes access log file, keep 25 rotated log files, do a log rotation every week,
-and send the SIGUSR2 signal to Zope after rotation. This will cause Zope to
-close the logfile and start a new one. See the documentation to `logrotate` for
-further details.
-
-On Windows there are no widespread tools for log rotation. You might try the
-`KiWi Syslog Daemon <http://www.kiwisyslog.com>`_ and configure Zope to log to
-it. Also see the sections "Access Log" and "Event Log" above.
-
-Packing and Backing Up the FileStorage Database
-===============================================
-
-The storage used by default by Zope's built-in object database, FileStorage, is
-an undoable storage. This essentially means changes to Zope objects do not
-overwrite the old object data, rather the new object gets appended to the
-database. This makes it possible to recreate an objects previous state, but it
-also means that the file the objects are kept in (which usually resides in
-$ZOPE_HOME/var/Data.fs) always keeps growing.
-
-To get rid of obsolete objects, you need to:: `pack` the ZODB. This can be done
-manually by opening Zopes Control_Panel and clicking on the "Database
-Management" link. Zope offers you the option of removing only object version
-older than an adjustable amount of days.
-
-If you want to automatically pack the ZODB you could tickle the appropriate URL
-with a small python script (the traditional filesystem based kind, not Zopes
-"Script (Python)")::
-
-  #!/usr/bin/python
-  import sys, urllib
-  host = sys.argv[1]
-  days = sys.argv[2]
-  url = "%s/Control_Panel/Database/manage_pack?days:float=%s" % (host, days)
-  try: 
-      f = urllib.urlopen(url).read()
-  except IOError:
-      print "Cannot open URL %s, aborting" % url
-      print "Successfully packed ZODB on host %s" % host
-
-The script takes two arguments, the URL of your server (eg.
-http://mymachine.com) and the number of days old an object version has to be to
-get discarded.
-
-On Unix, put this in eg. the file::
-
-  /usr/local/sbin/zope_pack
-
-and make it executable with::
-
-  chmod +x zope_pack
-
-Then you can put in into your crontab with eg.::
-
-  5 4 * * sun     /usr/local/sbin/zope_pack http://localhost 7
-
-This would instruct your system to pack the ZODB on 4:05 every sunday. It would
-connect to the local machine, and leave object versions younger than 7 days in
-the ZODB.
-
-Under Windows, you should use the scheduler to periodically start the script.
-Put the above script in eg.::
-
-  c:\Program Files\zope_pack.py
-
-or whereever you keep custom scripts, and create a batch file::
-
-  zope_pack.bat
-
-with contents similar to the following:::
-
-  "C:\Program Files\zope\bin\python.exe" "C:\Program Files\zope_pack.py" "http://localhost" 7
-
-The first parameter to python is the path to the python script we just created.
-The second is the root URL of the machine you want to pack, and the third is
-the maximum age of object versions you want to keep. Now instruct the scheduler
-to run this `.bat` file every week.
-
-Zope backup is quite straightforward. If you are using the default storage
-(FileStorage), all you need to do is to save the file::
-
-  $ZOPE_HOME/var/Data.fs
-
-This can be done online, because Zope only appends to the `Data.fs` file - and
-if a few bytes are missing at the end of the file due to a copy while the file
-is being written to, ZODB is usually capable of repairing that upon startup.
-The only thing to worry about would be if someone were to be using the *Undo*
-feature during backup. If you cannot ensure that this does not happen, you
-should take one of two routes. The first is be to shutdown Zope prior to a
-backup, and the second is to do a packing operation in combination with backup.
-Packing the ZODB leaves a file `Data.fs.old` with the previous contents of the
-ZODB. Since Zope does not write to that file anymore after packing, it is safe
-to backup this file even if undo operations are performed on the live ZODB.
-
-To backup `Data.fs` on Linux, you should not `tar` it directly, because `tar`
-will exit with an error if files change in the middle of a `tar` operation.
-Simply copying it over first will do the trick.
-
-Database Recovery Tools
-=======================
-
-To recover data from corrupted ZODB database file (typically located in
-`$ZOPE_HOME/var/Data.fs` ) there is a script `fsrecover.py` located in
-$ZOPE_HOME/lib/python/ZODB.
-
-fsrecover.py has the following help output::
-
-  python fsrecover.py [ <options> ] inputfile outputfile
-
-  Options:
-
-  -f -- force output even if output file exists
-
-  -v level -- Set the 
-  verbosity level:
-
-  0 -- Show progress indicator (default)
-
-  1 -- Show transaction times and sizes
-
-  2 -- Show transaction times and sizes, and
-  show object (record) ids, versions, and sizes.
-
-  -p -- Copy partial transactions. If a data record in the middle of a
-  transaction is bad, the data up to the bad data are packed. The
-  output record is marked as packed. If this option is not used,
-  transaction with any bad data are skipped.
-
-  -P t -- Pack data to t seconds in the past. Note that is the "-p"
-  option is used, then t should be 0.        

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/ObjectOrientation.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/ObjectOrientation.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/ObjectOrientation.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,278 +0,0 @@
-Object Orientation
-==================
-
-To make the best use of Zope, you will need a grasp on the concept of *object
-orientation*, which is a software development pattern used in many programming
-languages (C++, Java, Python and others) and computer systems that simulate
-"real-world" behavior. It stipulates that you should design an application in
-terms of *objects*. This chapter provides a broad overview of the fundamentals
-of object orientation from the perspective of a Zope developer.
-
-Objects
--------
-
-In Zope, as in other object-oriented systems, your application is designed
-around *objects*, or self-contained "bundles" of data and logic.  It is
-easiest to describe these bundles by comparing them to other programming
-concepts.
-
-In a typical, non-object-oriented application, you will have two things:
-
-- Code.  For example, a typical CGI-based web application may have a bit of
-  logic in the form of a PHP script, which retrieves employee data from a
-  database and displays tabular data to a user.
-
-- Data.  For example, you may have employee data stored in a database, such
-  as MySQL or Oracle, on which some code performs read or change
-  operations.  This data exists almost solely for the purpose of the code
-  that operates upon it; without this code, the data holds little to no
-  value.
-
-In a typical object-oriented application, however, you will have one thing, and
-one thing only:
-
-- Objects.  Simply stated, these objects are collections of code and data
-  wrapped up together.  For example, you may have an "Employee" object that
-  represents an employee.  It will contain data about the employee, such as
-  a phone number, name, and address, much like the information that would
-  be stored in a database.  However, the object will also contain "logic,"
-  or code, that can manipulate and display its data.
-
-In a non-object-oriented application, your data is kept separate from your
-code. But in an object-oriented application, both your data and your code are
-stored in one or more objects, each of which represents a particular "thing".
-These objects can represent just about anything. In Zope, the *Control_Panel*
-is an object, Folders that you create are objects, and even the Zope "root
-folder" is an object. When you use the Zope "add list" to create a new item in
-the Zope Management Interface, you are creating an object. People who extend
-Zope by creating add-ons define their own types of objects, which are then
-entered in to the Zope "add list" so that you can create objects based on them.
-An add-on author might define a "Form" object or a "Weblog" object. Basically,
-anything that can be defined using a noun can be modeled as a Zope object.
-
-As a programming methodology, object orientation allows software developers
-to design and create programs in terms of "real-world" things, such as
-Folders, Control_Panels, Forms, and Employees, instead of designing
-programs based around more "computerish" concepts like bits, streams, and
-integers.  Instead of teaching the computer about our problem by descending
-to its basic vocabulary (bits and bytes), we use an abstraction to teach
-the computer about the problem in terms of a vocabulary that is more
-natural to humans.  The core purpose of object orientation is to allow
-developers to create, to the largest extent possible, a system based on
-abstractions of the natural language of a computer (bits and bytes) into
-the real-world objects, like Employees and Forms, that we can understand
-more readily and quickly.
-
-The concept of abstraction also encourages programmers to break up a larger
-problem by addressing the problem as smaller, more independent
-"sub-problems," which allows developers to define and address solutions in
-much smaller, more feasible terms.  When you design an application in terms
-of objects, they become the pieces that eventually define the solution to
-all the "sub-problems" of a particular "big" problem.
-
-Attributes
-----------
-
-An object's data is defined by its *attributes*, or pieces of data that
-describe aspects of the object.  For example, an attribute of an Employee
-object might be called "phone_number," which might contain a series of
-characters that represent the employee's phone number.  Other attributes of
-an Employee object might be "first_name," "last_name", and "job_title," all
-of which give additional, detailed information about each Employee.
-
-It may help to think of the set of attributes belonging to an object as a
-sort of "mini-database" that contains information representing the
-"real-world thing" that the object is attempting to describe.  The complete
-collection of attributes assigned to an object defines that object's
-*state*.  When one or more of an object's attributes are modified, the
-object is said to have *changed its state*.
-
-Methods
--------
-
-The set of actions that an object may perform is defined by its *methods*.
-Methods are code definitions attached to an object that perform actions
-based on the object's attributes.  For example, a method of an Employee
-object named "getFirstName" may return the value of the object's
-"first_name" attribute, while a method of an Employee object named
-"setFirstName" might *change* the value of the object's "first_name"
-attribute.  The "getTitle" method of an Employee object may return a value
-of "Vice President" or "Janitor, depending on which Employee object is
-being queried.
-
-Methods are similar to *functions* in procedural languages like 'C'.  The
-key difference between a method and a function is that a method is "bound"
-to, or attached to, an object: instead of operating solely on "external"
-data that is passed to it via arguments, it may also operate on the
-attributes of the object to which it is bound.
-
-Messages
---------
-
-In an object-oriented system, to do any useful work, an object is required
-to communicate with other objects in the same system. For example, it
-wouldn't be particularly useful to have a single Employee object just
-sitting around in "object-land" with no way to communicate with it.  It
-would then just be as "dumb" as a regular old relational database row, just
-storing some data without the ability to do much else.  We want the
-capability to ask the object to do something useful, or more precisely: we
-want the capability for *other* objects to ask our Employee object to do
-something useful.  For instance, if we create an object named
-"EmployeeSummary," which is responsible for collecting the names of all of
-our employees for later display, we want the EmployeeSummary object to be
-able to ask a set of Employee objects for their first and last names.
-
-When one object communicates with another, it is said to send a *message*
-to another object.  Messages are sent to objects by way of the object's
-*methods*.  For example, our EmployeeSummary object may send a message to
-our Employee object by way of "calling" its "getFirstName" method.  Our
-Employee object would receive the message and return the value of its
-"first_name" attribute.  Messages are sent from one object to another when
-a "sender" object calls a method of a "receiver" object.
-
-When you access a URL that "points to" a Zope object, you are almost always
-sending that Zope object a message.  When you request a response from Zope
-by way of invoking a Zope URL with a web browser, the Zope `object
-publisher <http://www.zope.org/Documentation/Books/ZDG/current/ObjectPublishing.stx>`_
-receives the request from your browser.  It then sends a Zope object a
-message on your browser's behalf by "calling a method" on the Zope object
-specified in the URL.  The Zope object responds to the object publisher
-with a return value, and the object publisher returns the value to your
-browser.
-
-Classes and Instances
----------------------
-
-A *class* defines an object's behavior and acts as a *constructor* for an
-object.  When we talk about a "kind" of object, like an "Employee" object,
-we actually mean "objects constructed using the Employee class" or, more
-likely, just "objects of the Employee class."  Most objects are members of
-a class.
-
-It is typical to find many objects in a system that are essentially similar
-to one another, save for the values of their attributes.  For instance, you
-may have many Employee objects in your system, each with "first_name" and
-"last_name" attributes. The only difference between these Employee objects
-is the values contained within their attributes.  For example, the
-"first_name" of one Employee object might be "Fred" while another might be
-"Jim".  It is likely that each of these objects would be *members of the
-same class*.
-
-A class is to an object as a set of blueprints is to a house: as many
-houses can be constructed using the same set of blueprints, many objects
-can be constructed using the same class. Objects that share a class
-typically behave identically to one other.  If you visit two houses that
-share the same set of blueprints, you will likely notice striking
-similarities: the layout will be the same, the light switches will be in the
-same places, and the fireplace will almost certainly be in the same
-location.  The shower curtains might be different in each house, but this
-is an *attribute* of each particular house that doesn't change its
-essential similarity with the other.  It is much the same with instances of
-a class: if you "visit" two instances of a class, you would interact with
-both instances in essentially the same way: by calling the same set of
-methods on each.  The data kept in the instance (by way of its attributes)
-might be different, but these instances *behave* in exactly the same way.
-
-The behavior of two objects constructed from the same class is similar
-because they both share the same *methods*, which are not typically defined
-by an object itself, but are instead defined by an object's *class*.  For
-instance, if the Employee class defines the 'getFirstName' method, all
-objects that are members of the Employee class share that method
-definition.  The set of methods assigned to an object's class define the
-*behavior* of that object.
-
-The objects constructed by a class are called *instances of the class*, or
-(more often) just *instances*.  For example, the Zope 'index' page is
-an *instance of* the 'Page Template' class. The 'index' page has an 'id'
-attribute of 'index', while another page may have an 'id' attribute of
-'my_page'.  However, while they have different attribute values, since
-they are both instances of the same class, they both behave identically.
-All the objects that can be administered using the ZMI are instances of a
-class.  Typically, the classes from which these objects are constructed are
-defined in the add-ons created by Zope developers and community members.
-
-Inheritance
------------
-
-It is sometimes desirable for objects to share the same essential behavior,
-except for small deviations.  For example, you may want to create a
-ContractedEmployee object that has all the behavior of a "normal" Employee
-object, except that you must keep track of a tax identification number on
-instances of the ContractedEmployee class that is irrelevant for "normal"
-instances of the Employee class.
-
-*Inheritance* is the mechanism that allows you to share essential behavior
-between two objects, while customizing one with a slightly modified set of
-behaviors that differ from or extend the other.
-
-Inheritance is specified at the *class level*.  Since *classes define
-behavior*, if we want to change an object's behavior, we almost always need
-to change its class.
-
-If we base our new "ContractedEmployee" class on the Employee class, but
-add a method to it named "getTaxIdNumber" and an attribute named
-"tax_id_number," the ContractedEmployee class would be said to *inherit
-from* the Employee class.  In the jargon of object orientation, the
-ContractedEmployee class would be said to *subclass from* the Employee
-class, and the *Employee* class would be said to be a *superclass of* the
-ContractedEmployee class.
-
-When a subclass inherits behavior from another class, it doesn't need to
-sit idly by and accept all the method definitions of its superclass if they
-don't suit its needs: if necessary, the subclass can *override* the method
-definitions of its superclass.  For instance, we may want our
-ContractedEmployee class to return a different "title" than instances of
-our Employee class.  In our ContractedEmployee class, we might cause the
-'getTitle' method of the Employee class to be *overridden* by creating a
-method within ContractedEmployee with a different implementation.  For
-example, it may always return "Contractor" instead of a job-specific title.
-
-Inheritance is used extensively in Zope objects.  For example, the Zope
-"Image" class inherits its behavior from the Zope "File" class, since
-images are really just another kind of file, and both classes share many
-behavior requirements.  But the "Image" class adds a bit of behavior that
-allows it to "render itself inline" by printing its content within HTML
-tags, instead of causing a file download.  It does this by *overriding* the
-'index_html' method of the File class.
-
-Object Lifetimes
-----------------
-
-Object instances have a specific *lifetime*, which is typically controlled
-by either a programmer or a user of the system in which the objects "live".
-
-Instances of web-manageable objects in Zope, such as Files, Folders, and
-Page Templates, span from the time the user creates them until they are
-deleted. You will often hear these kinds of objects described as
-*persistent* objects.  These objects are stored in Zope's object database
-(the ZODB).
-
-Other Zope object instances have different lifetimes: some object instances
-last for a "programmer-controlled" period of time.  For instance, the
-object that represents a web request in Zope (often called REQUEST) has a
-well-defined lifetime, which lasts from the moment the object publisher
-receives the request from a remote browser, until a response is sent back
-to that browser, after which it is destroyed automatically.  Zope "session
-data" objects have another well-defined lifetime, which spans from the time
-a programmer creates one on behalf of the user via code, until such time
-that the system (on behalf of the programmer or site administrator) deems
-it necessary to throw away the object in order to conserve space, or to
-indicate an "end" to the user's session.  This is defined by default as 20
-minutes of "inactivity" by the user for whom the object was created.
-
-Summary
--------
-
-Zope is an object-oriented development environment.  Understanding Zope
-fully requires a grasp of the basic concepts of object orientation,
-including attributes, methods, classes, and inheritance, before setting out
-on a "for-production" Zope development project.
-
-For a more comprehensive treatment on the subject of object orientation,
-buy and read `The Object
-Primer <http://www.ambysoft.com/theObjectPrimer.html>`_ by Scott Ambler.
-There are also excellent object orientation tutorials available on the
-Internet.  See `The Essence of Objects
-chapter <http://www.objectcentral.com/oobook/Chapter2.html>`_ of the book 
-"The Essence of Object Oriented Programming with Java and UML," or the extensive
-`Object FAQ <http://www.objectfaq.com/oofaq2/>`_.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/Preface.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/Preface.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/Preface.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,214 +0,0 @@
-Preface
-=======
-
-Welcome to *The Zope2 Book*.  This book is designed to introduce you
-to ``Zope2``, an open-source web application server.
-
-To make effective use of the book, you should know how to use a web
-browser and have a basic understanding of the ``Hyper
-Text Markup Language`` (HTML) and ``Uniform Resource Locators`` (URLs).
-
-You don't need to be a highly-skilled programmer in order to use Zope2,
-but you may find the understanding of some programming concepts (particularly
-in object-oriented programming) to be extremely helpful.
-
-Preface to the 2.12 edition
----------------------------
-
-This book has originally been written for Zope 2.6 back in 2002. It has been
-available in an almost unmodified form for the last seven years. During those
-many years quite a bit has happened in Zope itself and the general web market.
-
-The 2.12 edition of this book does not try to write a new book on how-to do
-Zope development today. Instead it tries to update the original books content
-to be true and helpful again. Many of the underlying principles of Zope2 have
-not changed in the last years. The ZMI, security machinery, page templates and
-how-to use the ZCatalog are still there in an almost unmodified fashion.
-The general ideas behind object orientation, being Python based and the
-general architecture are still the same.
-
-If you want to understand Zope2 you still need to understand how Acquisition
-works, even though it has been discouraged as a way to design your application
-logic.
-
-One of the most notable differences between the original Zope2 approach and
-todays best-practices is in the way you develop applications with Zope2. The
-original Zope2 approach has focussed on a Through-The-Web (TTW) development
-model. You would create your entire application and manage your data through
-the same browser interface and store everything transparently in the same
-database. This model has worked very well in the beginning of "the web" as
-many dynamic websites have been rather simple and specialized projects.
-
-Over the years websites have grown their requirements and often turned into
-development projects of a considerable size. Today websites are understood
-as applications in themselves and need an approach which is no longer
-compatible with the TTW approach of the early Zope2.
-
-In this book you will still read about using the TTW approach for many of
-the examples. Please understand this as a way to quickly and easily learn
-about the underlying technologies. If you want to built an application based
-on top of Zope2, you are almost always better of approaching the project from
-the so called "file-system based approach" or using Python packages to extend
-Zope in a predictable way.
-
-
-How the Book Is Organized
--------------------------
-
-This book is laid out in the following chapters:
-
-- Introducing Zope
-
-    This chapter explains what Zope is and what it can do for you. You'll also
-    learn about the differences between Zope and other web application servers.
-
-- Zope Concepts and Architecture
-
-    This chapter explains fundamental Zope concepts and describes the basics
-    about Zope's architecture.
-
-- Installing and Starting Zope
-
-    This chapter explains how to install and start Zope for the first time. By
-    the end of this chapter, you will have Zope installed and working.
-
-- Object Orientation
-
-    This chapter explains the concept of *object orientation*, which is the
-    development methodology most often used to create Zope applications.
-
-- Using the Zope Management Interface
-
-    This chapter explains how to use Zope's web-based management interface. By
-    the end of this chapter, you will be able to navigate around the Zope
-    object space, copy and move objects, and use other basic Zope features.
-
-- Using Basic Zope Objects
-
-    This chapter introduces *objects*, which are the most important elements of
-    Zope. You'll learn the basic Zope objects: content objects, presentation
-    objects, and logic objects, and you'll build a simple application using
-    these objects.
-
-- Acquisition
-
-    This chapter introduces *Acquisition*, which is Zope's mechanism for
-    sharing site behavior and content.
-
-- Basic Zope Scripting
-
-    This chapter will introduce you to the basics of scripting.
-
-- Using Zope Page Templates
-
-    This chapter introduces *Zope Page Templates*, another Zope tool used to
-    create dynamic web pages. You will learn about basic template statements
-    that let you insert dynamic content, and how to create and edit page
-    templates.
-
-- Creating Basic Zope Applications  
-
-    This chapter presents several real-world examples of building a Zope
-    application. You'll learn how to use basic Zope objects and how they can
-    work together to form basic applications.
-
-- Users and Security
-
-    This chapter looks at how Zope handles users, authentication,
-    authorization, and other security-related matters.
-
-- Advanced Page Templates
-
-    This chapter goes into more depth with Zope Page Templates. You will learn
-    all about template statements, expression types, and macros, which let you
-    reuse presentation elements.
-
-- Advanced Zope Scripting
-
-    This chapter covers scripting Zope with Python. You will learn how to write
-    business logic in Zope using tools more powerful than TAL, about the idea
-    of *scripts* in Zope, and about Scripts (Python).
-
-- Zope Services
-
-    This chapter covers Zope objects that are considered "services," which
-    don't readily fit into any of the basic "content," "presentation," or
-    "logic" object groups.
-
-- Basic DTML
-
-    This chapter introduces DTML, the second tag-based scripting language.
-    You'll learn DTML syntax, its basic tags, and how to use DTML templates and
-    scripting facilities. After reading this chapter, you'll be able to create
-    dynamic web pages with DTML.
-
-- Advanced DTML
-
-    This chapter takes a closer look at DTML. You'll learn about DTML security,
-    the tricky issue of how variables are looked up in DTML, advanced use of
-    basic tags, and the myriad of special purpose tags.
-
-- Searching and Categorizing Content
-
-    This chapter shows you how to index and search objects with Zope's built-in
-    search engine: the *Catalog*. You'll learn about indexing concepts,
-    different patterns for indexing and searching, metadata, and search
-    results.
-
-- Relational Database Connectivity
-
-    This chapter describes how Zope connects to external relational databases.
-    You'll learn about features that allow you to treat relational data as
-    though it were Zope objects, and security and performance considerations.
-
-- Virtual Hosting Services
-
-    This chapter explains how to set up Zope in a "virtual hosting"
-    environment, in which Zope sub-folders can be served as "top-level" host
-    names. It includes examples that allow virtual hosting to be performed
-    either "natively" or using Apache's 'mod_rewrite' facility.
-
-- Sessions
-
-    This chapter describes Zope's "sessioning" services, which allow Zope
-    developers to "keep state" between HTTP requests.
-
-- Scalability and ZEO
-
-    This chapter covers issues and solutions for building and maintaining large
-    web applications, and focuses on issues of management and scalability. In
-    particular, the Zope Enterprise Option (ZEO) is covered in detail. You'll
-    learn about the tools and techniques needed to turn a small site into a
-    large-scale site, servicing many simultaneous visitors.
-
-- Managing Zope Objects Using External Tools
-
-    This chapter explains how to use tools outside of your web browser to
-    manipulate Zope objects.
-
-- Maintaining Zope
-
-    This chapter covers Zope maintenance and administration tasks, such as
-    database "packing" and package installation.
-
-- Appendix A: DTML Reference
-
-    Reference of DTML syntax and commands.
-
-- Appendix B: API Reference
-
-    Reference of Zope object APIs.
-
-- Appendix C: Page Template Reference
-
-    Reference of Zope Page Template syntax and commands.
-
-- Appendix D: Zope Resources
-
-    Reference of "resources" which can be used to further enhance your Zope
-    learning experience.
-
-- Appendix E:
-
-    DTML Name Lookup Rules Describes DTML's name lookup rules.
-

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/RelationalDatabases.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/RelationalDatabases.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/RelationalDatabases.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,1382 +0,0 @@
-Relational Database Connectivity
-================================
-
-
-.. note::
-
-    This chapter explains you how to access a relational databases directly through
-    SQL. The alternative and modern way integrating a RDBMS with Zope is using an
-    Object-Relational-Mapper (ORM). An ORM abstracts the SQL layer and allows you
-    to deal with database tables, rows etc. like standard Python objects.
-
-    The most common and most flexible ORM in the
-    Python world is `SQLAlchemy <http://www.sqlalchemy.org>`_ . You can not use
-    SQLAlchemy directly within Zope because the transaction system of the RDBMS
-    must participate with Zope transaction. This integration layer is implemented
-    through the `zope.sqlalchemy <http://pypi.python.org/pypi/zope.sqlalchemy>`_
-    module.
-
-
-The Zope Object Database (ZODB) is used to store all the pages,
-files and other objects you create. It is fast and requires almost
-no setting up or maintenance.  Like a filesystem, it is especially
-good at storing moderately-sized binary objects such as graphics.
-
-Relational Databases work in a very different way. They are based on
-tables of data such as this::
-
-  Row   First Name   Last Name  Age
-  ===   ==========   =========  ===
-  1     Bob          McBob      42
-  2     John         Johnson    24
-  3     Steve        Smith      38
-
-Information in the table is stored in rows. The table's column
-layout is called the *schema*.  A standard language, called the
-Structured Query Language (SQL) is used to query and change tables
-in relational databases. This chapter assumes a basic knowledge of SQL,
-if you do not know SQL there are many books and tutorials on the web.
-
-Relational databases and object databases are very different and
-each possesses its own strengths and weaknesses. Zope allows you to
-use either, providing the flexibility to choose the storage
-mechanism which is best for your data. The most common reasons to
-use relational databases are to access an existing database or to
-share data with other applications.  Most programming languages and
-thousands of software products work with relational
-databases. Although it is possible to access the ZODB from other
-applications and languages, it will often require more effort than
-using a relational database.
-
-By using your relational data with Zope you retain all of Zope's
-benefits including security, dynamic presentation, and
-networking. You can use Zope to dynamically tailor your data access,
-data presentation and data management.
-
-Common Relational Databases
----------------------------
-
-There are many relational database systems. The following is a brief
-list of some of the more popular database systems:
-
-Oracle
-  Oracle is arguably the most powerful and popular
-  commercial relational database. It is, however, relatively
-  expensive and complex. Oracle can be purchased or evaluated from
-  the `Oracle Website <http://www.oracle.com/index.html>`_.
-
-PostgreSQL
-  PostgreSQL is a leading open source relational
-  database with good support for SQL standards.  You can
-  find more information about PostgreSQL at the `PostgreSQL web
-  site <http://www.postgresql.org/>`_.
-
-MySQL
-  MySQL is a fast open source relational database. You
-  can find more information about MySQL at the `MySQL web
-  site <http://www.mysql.com/>`_. 
-
-SQL Server
-  Microsoft's full featured SQL Server for the
-  Windows operating systems. For any serious use on Windows, it is
-  preferable to Microsoft Access. Information from
-  http://www.microsoft.com/sql/
-
-The mechanics of setting up relational database is different for
-each database and is thus beyond the scope of this book.  All of the
-relational databases mentioned have their own installation and
-configuration documentation that you should consult for specific
-details.
-
-Zope can connect to all the above-listed database systems; however,
-you should be satisfied that the database is running and operating
-in a satisfactory way on its own before attempting to connect it to
-Zope.  An exception to this policy is Gadfly, which is included with
-Zope and requires no setup.
-
-
-Database Adapters
------------------
-
-A database can only be used if a Zope Database Adapter is available,
-though a Database Adapter is fairly easy to write if the database has
-Python support. Database adapters can be found in the
-`Zope Framework category of the Python Package Index <http://pypi.python.org/pypi?:action=browse&c=514>`_.
-
-At the time of writing the following adapters were available, but this
-list constantly changes as more adapters are added.
-
-Oracle
-  `DCOracle2 <http://www.zope.org/Members/matt/dco2>`_ package
-  from Zope Corporation includes the ZoracleDA
-
-PostgreSQL
-  The newest and prefered DA is ZPsycopgDA included in 
-  `psycopg <http://initd.org/software/psycopg package>`_. The older
-  `ZpopyDA <http://sourceforge.net/projects/zpopyda/>`_ is also
-  available.
-
-MySQL
-  `ZMySQLDA <http://www.zope.org/Members/adustman/Products/ZMySQLDA>`_
-  Available as source and a Linux binary package.
-
-SQLServer
-  `mxODBC <http://www.egenix.com>`_ is written by Egenix
-  and very well maintained. There is also
-  `ZODBC DA <http://www.zope.org/Products/DA/ZODBCDA>`_ is
-  written by Zope Corporation. Available
-  for the Windows platform only. This DA is no longer actively
-  maintainted.
-
-If you will need to connect to more than one database or wish to connect
-as to the same database as different users then you may use multiple
-database connection objects.
-
-Setting up a Database Connection
---------------------------------
-
-Once the database adapter has been downloaded and installed you may
-create a new *Database Connection* from the *Add* menu on the Zope
-management pages. All database connection management interfaces are
-fairly similar.
-
-The database connection object is used to establish and manage the
-connection to the database. Because the database runs externally to
-Zope, they may require you to specify information necessary to
-connect successfully to the database. This specification, called a
-*connection string*, is different for each kind of database. For
-example, the figure below shows the PostgreSQL database connection
-add form.
-
-.. figure:: ../Figures/psycopg.png
-
-   PostgreSQL Database Connection
-
-We'll be using the Gadfly database for the examples in this chapter,
-as it requires the least amount of configuration.  If you happen to
-be using a different database while "playing along", note that
-Database Connections work slightly differently depending on which
-database is being used, however most have a "Test" tab for issuing a
-test SQL query to the database and a "Browse" tab which will show
-the table structure. It is good practice to use these tabs to test
-the database connection before going any further.
-
-Select the *Z Gadfly Database Connection* from the add list.  This
-will take you to the add form for a Gadfly database connection.
-Select and add a Gadlfy connection to Zope. Note that because Gadfly
-runs inside Zope you do not need to specify a "connection string".
-
-Select the *Demo* data source, specify *Gadfly_database_connection* for
-the id, and click the *Add* button.  This will create a new Gadfly
-Database Connection. Select the new connection by clicking on it.
-
-You are looking at the *Status* view of the Gadfly Database
-Connection.  This view tells you if you are connected to the
-database, and it exposes a button to connect or disconnect from the
-database.  In general Zope will manage the connection to your
-database for you, so in practice there is little reason to manually
-control the connection.  For Gadfly, the action of connecting and
-disconnecting is meaningless, but for external databases you may
-wish to connect or disconnect manually to do database maintenance.
-
-The next view is the *Properties* view.  This view shows you the data
-source and other properties of the Database Connection.  This is useful
-if you want to move your Database Connection from one data source to
-another. The figure below shows the *Properties* view.
-
-.. figure:: ../Figures/10-3.png
-
-   The Properties view
-
-You can test your connection to a database by going to the *Test*
-view.  This view lets you type SQL code directly and run it on your
-database.  This view is used for testing your database and issuing
-"one-time" SQL commands (like statements for creating tables).  This
-is *not* the place where you will enter most of your SQL code. SQL
-commands typically reside in *Z SQL Methods* which will be discussed
-in detail later in this chapter.
-
-Let's create a table in your database for use in this chapter's
-examples.  The *Test* view of the Database Connection allows you to
-send SQL statements directly to your database. You can create tables
-by typing SQL code directly into the *Test* view; there is no need
-to use a SQL Method to create tables.  Create a table called
-*employees* with the following SQL code by entering it into the
-*Test* tab::
-
-  CREATE TABLE employees
-  (
-  emp_id integer,
-  first varchar,
-  last varchar,
-  salary float
-  )
-
-Click the *Submit Query* button of the *Test* tab to run the SQL
-command. Zope should return a confirmation screen that confirms that
-the SQL code was run.  It will additionally display the results, if
-any.
-
-The SQL used here works under Gadfly but may differ depending on
-your database.  For the exact details of creating tables with your
-database, check the user documentation from your specific database
-vendor.
-
-This SQL will create a new table in your Gadfly database called
-*employees*.  This table will have four columns, *emp_id*, *first*,
-*last* and *salary*.  The first column is the "employee id", which
-is a unique number that identifies the employee.  The next two
-columns have the type *varchar* which is similar to a string.  The
-*salary* column has the type *float* which holds a floating point
-number.  Every database supports different kinds of types, so you
-will need to consult your documentation to find out what kind of
-types your database supports.
-
-To examine your table, go to the *Browse* view.  This lets you view
-your database's tables and the schema of each table. Here, you can
-see that there is an *employees* table, and if you click on the
-*plus symbol*, the table expands to show four columns, *emp_id*,
-*first*, *last* and *salary* as shown in [10-3].
-
-.. figure:: ../Figures/10-4.png
-
-   Browsing the Database Connection
-
-This information is very useful when creating complex SQL
-applications with lots of large tables, as it lets you discover the
-schemas of your tables. However, not all databases support browsing
-of tables.
-
-Now that you've created a database connection and have defined a
-table, you can create Z SQL Methods to operate on your database.
-
-Z SQL Methods
--------------
-
-*Z SQL Methods* are Zope objects that execute SQL code through a
-Database Connection.  All Z SQL Methods must be associated with a
-Database Connection. Z SQL Methods can both query and change
-database data.  Z SQL Methods can also contain more than one SQL
-command. In detail a Z SQL method may contain multiple INSERT
-or UPDATE statements but at most one SELECT statement.
-
-A ZSQL Method has two functions: it generates SQL to send to the
-database and it converts the response from the database into an
-object. This has the following benefits:
-
-- Generated SQL will take care of special characters that may need to be
-  quoted or removed from the query. This speeds up code development.
-
-- If the underlying database is changed (for example, from Postgres
-  to Oracle), then the generated SQL will, in some cases,
-  automatically change too, making the application more portable.
-
-- Results from the query are packaged into an easy to use object which
-  will make display or processing of the response very simple.
-
-- Transactions are mediated. Transactions are discussed in more
-  detail later in this chapter.
-
-Examples of ZSQL Methods
--------------------------
-
-Create a new Z SQL Method called *hire_employee* that inserts a new
-employee in the *employees* table.  When a new employee is hired,
-this method is called and a new record is inserted in the
-*employees* table that contains the information about the new
-employee.  Select *Z SQL Method* from the *Add List*.  This will
-take you to the add form for Z SQL Methods, as shown in the figure
-below.
-
-.. figure:: ../Figures/10-5.png
-
-   The Add form for Z SQL Methods
-
-As usual, you must specify an *id* and *title* for the Z SQL Method. In
-addition you need to select a Database Connection to use with this Z SQL
-Methods. Give this new method the id *hire_employee* and select the
-*Gadfly_database_connection* that you created in the last section.
-
-Next, you can specify *arguments* to the Z SQL Method. Just like
-Scripts, Z SQL Methods can take arguments. Arguments are used to
-construct SQL statements.  In this case your method needs four
-arguments, the employee id number, the first name, the last name and
-the employee's salary. Type "emp_id first last salary" into the
-*Arguments* field. You can put each argument on its own line, or you
-can put more than one argument on the same line separated by
-spaces. You can also provide default values for argument just like
-with Python Scripts. For example, 'emp_id=100' gives the 'emp_id'
-argument a default value of 100.
-
-The last form field is the *Query template*.  This field contains
-the SQL code that is executed when the Z SQL Method is called.  In
-this field, enter the following code::
-
-  insert into employees (emp_id, first, last, salary) values
-  (<dtml-sqlvar emp_id type="int">, 
-   <dtml-sqlvar first type="string">, 
-   <dtml-sqlvar last type="string">,
-   <dtml-sqlvar salary type="float">
-  )
-
-Notice that this SQL code also contains DTML.  The DTML code in this
-template is used to insert the values of the arguments into the SQL
-code that gets executed on your database.  If the *emp_id* argument
-had the value *42*, the *first* argument had the value *Bob* your
-*last* argument had the value *Uncle* and the *salary* argument had
-the value *50000.00* then the query template would create the
-following SQL code::
-
-  insert into employees (emp_id, first, last, salary) values
-  (42,
-   'Bob',
-   'Uncle',
-   50000.00
-  )
-
-The query template and SQL-specific DTML tags are explained further
-in the next section of this chapter.
-
-You have your choice of three buttons to click to add your new Z SQL
-Method.  The *Add* button will create the method and take you back
-to the folder containing the new method.  The *Add and Edit* button
-will create the method and make it the currently selected object in
-the *Workspace*.  The *Add and Test* button will create the method
-and take you to the method's *Test* view so you can test the new
-method.  To add your new Z SQL Method, click the *Add* button.
-
-Now you have a Z SQL Method that inserts new employees in the
-*employees* table.  You'll need another Z SQL Method to query the
-table for employees.  Create a new Z SQL Method with the id
-*list_all_employees*.  It should have no arguments and contain the
-following SQL code::
-
-  select * from employees
-
-This simple SQL code selects all the rows from the *employees*
-table.  Now you have two Z SQL Methods, one to insert new employees
-and one to view all of the employees in the database.  Let's test
-your two new methods by inserting some new employees in the
-*employees* table and then listing them.  To do this, click on the
-*hire_employee* Method and click the *Test* tab.  This will take you
-to the *Test* view of the Method, as shown in the figure below.
-
-.. figure:: ../Figures/10-6.png
-
-   The hire_employee Test view
-
-Here, you see a form with four input boxes, one for each argument to
-the *hire_employee* Z SQL Method.  Zope automatically generates this
-form for you based on the arguments of your Z SQL Method.  Because
-the *hire_employee* Method has four arguments, Zope creates this
-form with four input boxes. You can test the method by entering an
-employee number, a first name, a last name, and a salary for your
-new employee.  Enter the employee id "42", "Bob" for the first name,
-"McBob" for the last name and a salary of "50000.00". Then click the
-*Submit Query* button. You will then see the results of your test.
-
-The screen says *This statement returned no results*.  This is
-because the *hire_employee* method only inserts new information in
-the table, it does not select any information out of the table, so
-no records were returned.  The screen also shows you how the query
-template get rendered into SQL.  As expected, the *sqlvar* DTML tags
-rendered the four arguments into valid SQL code that your database
-executed.  You can add as many employees as you'd like by repeatedly
-testing this method.
-
-To verify that the information you added is being inserted into the
-table, select the *list_all_employees* Z SQL Method and click on its
-*Test* tab.  
-
-This view says *This query requires no input*, indicating the
-*list_all_employees* does not have any argument and thus, requires
-no input to execute.  Click on the *Submit Query* button to test the
-method.
-
-The *list_all_employees* method returns the contents of your
-*employees* table.  You can see all the new employees that you
-added. Zope automatically generates this tabular report screen for
-you. Next we'll show how you can create your own user interface to
-your Z SQL Methods to integrate them into your website.
-
-Displaying Results from Z SQL Methods
--------------------------------------
-
-Querying a relational database returns a sequence of results. The items
-in the sequence are called *result rows*.  SQL query results are always a
-sequence. Even if the SQL query returns only one row, that row is the
-only item contained in a list of results.
-
-Somewhat predictably, as Zope is `object oriented
-<ObjectOrientation.html>`_, a Z SQL method returns a *Result object*. All
-the result rows are packaged up into one object. For all practical
-purposes, the result object can be thought of as rows in the database table
-that have been turned into Zope objects.  These objects have attributes
-that match the schema of the database result.
-
-Result objects can be used from DTML to display the results of calling
-a Z SQL Method.  For example, add a new DTML Method to your site called
-*listEmployees* with the following DTML content::
-
-  <dtml-var standard_html_header>
-
-    <ul>
-    <dtml-in list_all_employees>
-      <li><dtml-var emp_id>: <dtml-var last>, <dtml-var first> 
-        makes <dtml-var salary> Euro a year.
-      </li>
-    </dtml-in>
-    </ul>
-
-  <dtml-var standard_html_footer>
-
-and the ZPT version::
-
-  <div>
-    <ul>
-      <li tal:repeat="row context/list_all_employees">
-        <span tal:content="string:${row/id}: ${row/last} ${row/first} 
-              makes ${row/salary} Euro a year.
-      </li>
-    </ul>
-  </div>
-
-This method calls the *list_all_employees* Z SQL Method from
-DTML. The *in* tag is used to iterate over each Result object
-returned by the *list_all_employees* Z SQL Method.  Z SQL Methods
-always return a list of objects, so you will almost certainly use
-them from the DTML *in* tag unless you are not interested in the
-results or if the SQL code will never return any results, like
-*hire_employee*.
-
-The body of the *in* tag is a template that defines what gets rendered
-for each Result object in the sequence returned by *list_all_employees*.
-In the case of a table with three employees in it, *listEmployees* might
-return HTML that looks like this::
-
-  <html>
-    <body>
-
-    <ul>
-      <li>42: Roberts, Bob 
-        makes $50,000 a year.
-      </li>
-      <li>101: leCat, Cheeta 
-        makes $100,000 a year.
-      </li>
-      <li>99: Junglewoman, Jane 
-        makes $100,001 a year.
-      </li>
-    </ul>
-
-    </body>
-  </html>
-
-The *in* tag rendered an HTML list item for each Result object returned
-by *list_all_employees*.
-
-Zope Database Adapters behave slightly differently regarding how
-they handle different types of data. However the more modern ones
-will return the Python type that is closest to the SQL type - as
-there are far more types in SQL than in Python there cannot be a
-complete match. For example, a date will usually be returned as a
-Zope DateTime object; char, varchar and text will all be returned as
-strings.
-
-An important difference between result objects and other Zope
-objects is that result objects do not get created and permanently
-added to Zope.  Result objects are not persistent. They exist for
-only a short period of time; just long enough for you to use them in
-a result page or to use their data for some other purpose.  As soon
-as you are done with a request that uses result objects they go
-away, and the next time you call a Z SQL Method you get a new set of
-fresh result objects.
-
-Next we'll look at how to create user interfaces in order to
-collect data and pass it to Z SQL Methods.
-
-Providing Arguments to Z SQL Methods
-------------------------------------
-
-So far, you have the ability to display employees with the
-*listEmployees* DTML Method which calls the *list_all_employees* Z
-SQL Method.  Now let's look at how to build a user interface for the
-*hire_employee* Z SQL Method. Recall that the *hire_employee*
-accepts four arguments, *emp_id*, *first*, *last*, and *salary*.
-The *Test* tab on the *hire_employee* method lets you call this
-method, but this is not very useful for integrating into a web
-application. You need to create your own input form for your Z SQL
-Method or call it manually from your application.
-
-The Z Search Interface can create an input form for you
-automatically.  In the chapter entitled `Searching and Categorizing
-Content <SearchingZCatalog.html>`_, you used the Z Search Interface to
-build a form/action pair of methods that automatically generated an
-HTML search form and report screen that queried the Catalog and
-returned results.  The Z Search Interface also works with Z SQL
-Methods to build a similar set of search/result screens.
-
-Select *Z Search Interface* from the add list and specify
-*hire_employee* as the *Searchable object*. Enter the value
-"hireEmployeeReport" for the *Report Id*, "hireEmployeeForm" for the
-*Search Id* and check the "Generate DTML Methods" button then click
-*Add*.
-
-Click on the newly created *hireEmployeeForm* and click the *View*
-tab.  Enter an employee_id, a first name, a last name, and salary
-for a new employee and click *Submit*.  Zope returns a screen that
-says "There was no data matching this query".  Because the report
-form generated by the Z Search Interface is meant to display the
-result of a Z SQL Method, and the *hire_employee* Z SQL Method does
-not return any results; it just inserts a new row in the table.
-Edit the *hireEmployeeReport* DTML Method a little to make it more
-informative.  Select the *hireEmployeeReport* Method.  It should
-contain the following long stretch of DTML::
-
-  <dtml-var standard_html_header>
-
-  <dtml-in hire_employee size=50 start=query_start>
-
-     <dtml-if sequence-start>
-
-        <dtml-if previous-sequence>
-
-          <a href="<dtml-var URL><dtml-var sequence-query
-                   >query_start=<dtml-var
-                   previous-sequence-start-number>">
-          (Previous <dtml-var previous-sequence-size> results)
-          </a>
-
-        </dtml-if previous-sequence>
-
-        <table border>
-          <tr>
-          </tr>
-
-     </dtml-if sequence-start>
-
-          <tr>
-          </tr>
-
-     <dtml-if sequence-end>
-
-        </table>
-        <dtml-if next-sequence>
-
-           <a href="<dtml-var URL><dtml-var sequence-query
-             >query_start=<dtml-var
-              next-sequence-start-number>">
-           (Next <dtml-var next-sequence-size> results)
-           </a>
-
-        </dtml-if next-sequence>
-
-     </dtml-if sequence-end>
-
-  <dtml-else>
-
-    There was no data matching this <dtml-var title_or_id> query.
-
-  </dtml-in>
-
-  <dtml-var standard_html_footer>
-
-This is a pretty big piece of DTML!  All of this DTML is meant to
-dynamically build a batch-oriented tabular result form.  Since we
-don't need this, let's change the generated *hireEmployeeReport*
-method to be much simpler::
-
-  <dtml-var standard_html_header>
-
-  <dtml-call hire_employee>
-
-  <h1>Employee <dtml-var first> <dtml-var last> was Hired!</h1>
-
-  <p><a href="listEmployees">List Employees</a></p>
-
-  <p><a href="hireEmployeeForm">Back to hiring</a></p>
-
-  <dtml-var standard_html_footer>
-
-Now view *hireEmployeeForm* and hire another new employee.  Notice
-how the *hire_employee* method is called from the DTML *call* tag.
-This is because we know there is no output from the *hire_employee*
-method. Since there are no results to iterate over, the method does not
-need to be called with the *in* tag. It can be called simply with the
-*call* tag.  
-
-You now have a complete user interface for hiring new employees.
-Using Zope's security system, you can now restrict access to this
-method to only a certain group of users whom you want to have
-permission to hire new employees.  Keep in mind, the search and
-report screens generated by the Z Search Interface are just
-guidelines that you can easily customize to suite your needs.
-
-Next we'll take a closer look at precisely controlling SQL queries.
-You've already seen how Z SQL Methods allow you to create basic SQL
-query templates. In the next section you'll learn how to make the
-most of your query templates.
-
-Dynamic SQL Queries
--------------------
-
-A Z SQL Method query template can contain DTML that is evaluated when the
-method is called.  This DTML can be used to modify the SQL code that is
-executed by the relational database.  Several SQL specific DTML tags
-exist to assist you in the construction of complex SQL queries. In the
-next sections you'll learn about the *sqlvar*, *sqltest* and *sqlgroup*
-tags.
-
-Inserting Arguments with the *Sqlvar* Tag
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-It's pretty important to make sure you insert the right kind of data
-into a column in a database.  You database will complain if you try to
-use the string "12" where the integer 12 is expected. SQL requires that
-different types be quoted differently. To make matters worse, different
-databases have different quoting rules.
-
-In addition to avoiding errors, SQL quoting is important for security.
-Suppose you had a query that makes a select::
-
-  select * from employees 
-    where emp_id=<dtml-var emp_id>
-
-This query is unsafe since someone could slip SQL code into your
-query by entering something like *12; drop table employees* as
-an *emp_id*. To avoid this problem you need to make sure that your
-variables are properly quoted. The *sqlvar* tag does this for you. Here
-is a safe version of the above query that uses *sqlvar*::
-
-    select * from employees 
-      where emp_id=<dtml-sqlvar emp_id type=int>
-
-The *sqlvar* tag operates similarly to the regular DTML *var* tag in
-that it inserts values. However it has some tag attributes targeted at
-SQL type quoting, and dealing with null values. The *sqlvar* tag
-accepts a number of arguments:
-
-*name*
-  The *name* argument is identical to the name argument for
-  the *var* tag.  This is the name of a Zope variable or Z SQL Method
-  argument. The value of the variable or argument is inserted into the
-  SQL Query Template.  A *name* argument is required, but the
-  "name=" prefix may be omitted.
-
-*type*
-  The *type* argument determines the way the *sqlvar*
-  tag should format the value of the variable or argument being
-  inserted in the query template.  Valid values for type are
-  *string*, *int*, *float*, or *nb*.  *nb* stands for non-blank
-  and means a string with at least one character in it. The *sqlvar*
-  tag *type* argument is required.
-
-*optional*
-  The *optional* argument tells the *sqlvar* tag
-  that the variable or argument can be absent or be a null
-  value.  If the variable or argument does not exist or is a
-  null value, the *sqlvar* tag does not try to render it.  The
-  *sqlvar* tag *optional* argument is optional.
-
-The *type* argument is the key feature of the *sqlvar* tag. It
-is responsible for correctly quoting the inserted variable.  See
-Appendix A for complete coverage of the *sqlvar* tag.
-
-You should always use the *sqlvar* tag instead of the *var* tag
-when inserting variables into a SQL code since it correctly
-quotes variables and keeps your SQL safe.
-
-Equality Comparisons with the *sqltest* Tag
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Many SQL queries involve equality comparison operations.  These
-are queries that ask for all values from the table that are in
-some kind of equality relationship with the input.  For example,
-you may wish to query the *employees* table for all employees
-with a salary *greater than* a certain value.
-
-To see how this is done, create a new Z SQL Method named
-*employees_paid_more_than*.  Give it one argument, *salary*,
-and the following SQL template::
-
-  select * from employees 
-    where <dtml-sqltest salary op=gt type=float>
-
-Now click *Add and Test*.  The *op* tag attribute is set to *gt*,
-which stands for *greater than*.  This Z SQL Method will only return
-records of employees that have a higher salary than what you enter in
-this input form.  The *sqltest* builds the SQL syntax necessary to
-safely compare the input to the table column. Type "10000" into the
-*salary* input and click the *Test* button. As you can see the
-*sqltest* tag renders this SQL code::
-
-  select * from employees
-    where salary > 10000
-
-The *sqltest* tag renders these comparisons to SQL taking into
-account the type of the variable and the particularities of the
-database.  The *sqltest* tag accepts the following tag parameters:
-
-*name*
-  The name of the variable to insert.
-
-*type*
-  The data type of the value to be inserted. This
-  attribute is required and may be one of *string*, *int*,
-  *float*, or *nb*. The nb data type stands for "not blank" and
-  indicates a string that must have a length that is greater
-  than 0. When using the nb type, the *sqltest* tag will not
-  render if the variable is an empty string.
-
-*column*
-  The name of the SQL column, if different than the *name*
-  attribute.
-
-*multiple*
-  A flag indicating whether multiple values may be
-  provided. This lets you test if a column is in a set of
-  variables. For example when *name* is a list of strings "Bob" ,
-  "Billy" , '<dtml-sqltest name type="string" multiple>' renders to
-  this SQL: 'name in ("Bob", "Billy")'.
-
-*optional*
-  A flag indicating if the test is optional. If
-  the test is optional and no value is provided for a variable
-  then no text is inserted. If the value is an empty string,
-  then no text will be inserted only if the type is *nb*.
-
-*op*
-  A parameter used to choose the comparison operator
-  that is rendered. The comparisons are: *eq* (equal to), *gt*
-  (greater than), *lt* (less than), *ge* (greater than or equal
-  to), *le* (less than or equal to), and  *ne* (not equal to).
-
-See `Appendix A <AppendixA.html>`_ for more information on the
-*sqltest* tag.  If your database supports additional comparison
-operators such as *like* you can use them with *sqlvar*. For
-example if *name* is the string "Mc%", the SQL code::
-
-  <dtml-sqltest name type="string" op="like">
-
-would render to::
-
-  name like 'Mc%'
-
-The *sqltest* tag helps you build correct SQL queries. In
-general your queries will be more flexible and work better with
-different types of input and different database if you use
-*sqltest* rather than hand coding comparisons.
-
-Creating Complex Queries with the *sqlgroup* Tag
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The *sqlgroup* tag lets you create SQL queries that support a
-variable number of arguments.  Based on the arguments specified, SQL
-queries can be made more specific by providing more arguments, or
-less specific by providing less or no arguments.
-
-Here is an example of an unqualified SQL query::
-
-  select * from employees
-
-Here is an example of a SQL query qualified by salary::
-
-  select * from employees
-  where(
-    salary > 100000.00
-  )
-
-Here is an example of a SQL query qualified by salary and first name::
-
-  select * from employees 
-  where(
-    salary > 100000.00
-    and
-    first in ('Jane', 'Cheetah', 'Guido')    
-  )
-
-Here is an example of a SQL query qualified by a first and a
-last name::
-
-  select * from employees 
-  where(
-    first = 'Old'
-    and
-    last = 'McDonald'     
-  )
-
-All three of these queries can be accomplished with one Z SQL
-Method that creates more specific SQL queries as more arguments
-are specified.  The following SQL template can build all three
-of the above queries::
-
-  select * from employees 
-  <dtml-sqlgroup where>
-    <dtml-sqltest salary op=gt type=float optional>
-  <dtml-and>
-    <dtml-sqltest first op="eq" type="nb" multiple optional>
-  <dtml-and>
-    <dtml-sqltest last  op="eq" type="nb" multiple optional>
-  </dtml-sqlgroup>  
-
-The *sqlgroup* tag renders the string *where* if the contents of
-the tag body contain any text and builds the qualifying
-statements into the query.  This *sqlgroup* tag will not render
-the *where* clause if no arguments are present.
-
-The *sqlgroup* tag consists of three blocks separated by *and*
-tags.  These tags insert the string *and* if the enclosing
-blocks render a value.  This way the correct number of *ands*
-are included in the query.  As more arguments are specified,
-more qualifying statements are added to the query.  In this
-example, qualifying statements restricted the search with *and*
-tags, but *or* tags can also be used to expand the search.
-
-This example also illustrates *multiple* attribute on *sqltest*
-tags.  If the value for *first* or *last* is a list, then the
-right SQL is rendered to specify a group of values instead of a
-single value.
-
-You can also nest *sqlgroup* tags.
-For example::
-
-  select * from employees
-  <dtml-sqlgroup where>
-    <dtml-sqlgroup>
-       <dtml-sqltest first op="like" type="nb">
-    <dtml-and>
-       <dtml-sqltest last op="like" type="nb">
-    </dtml-sqlgroup>
-  <dtml-or>
-    <dtml-sqltest salary op="gt" type="float">
-  </dtml-sqlgroup>
-
-Given sample arguments, this template renders to SQL like so::
-
-  select * from employees
-  where
-  ( (first like 'A%'
-     and
-     last like 'Smith'
-    )
-    or
-    salary > 20000.0
-  )
-
-You can construct very complex SQL statements with the
-*sqlgroup* tag. For simple SQL code you won't need to use the
-*sqlgroup* tag. However, if you find yourself creating a number
-of different but related Z SQL Methods you should see if you
-can't accomplish the same thing with one method that uses the
-*sqlgroup* tag.
-
-Advanced Techniques
--------------------
-
-So far you've seen how to connect to a relational database, send
-it queries and commands, and create a user interface. These are
-the basics of relational database connectivity in Zope.
-
-In the following sections you'll see how to integrate your relational
-queries more closely with Zope and enhance performance. We'll start by
-looking at how to pass arguments to Z SQL Methods both explicitly and
-by acquisition.  Then you'll find out how you can call Z SQL Methods
-directly from URLs using traversal to result objects. Next you'll find
-out how to make results objects more powerful by binding them to 
-classes. Finally we'll look at caching to improve performance and how
-Zope handles database transactions.
-
-Calling Z SQL Methods with Explicit Arguments
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you call a Z SQL Method without argument from DTML, the arguments
-are automatically collected from the REQUEST. This is the technique 
-that we have used so far in this chapter. It works well when you want
-to query a database from a search form, but sometimes you want to 
-manually or programmatically query a database. Z SQL Methods can be
-called with explicit arguments from DTML or Python.  For example, to
-query the *employee_by_id* Z SQL Method manually, the following DTML
-can be used::
-
-  <dtml-var standard_html_header>
-
-    <dtml-in expr="employee_by_id(emp_id=42)">
-      <h1><dtml-var last>, <dtml-var first></h1>
-
-      <p><dtml-var first>'s employee id is <dtml-var emp_id>.  <dtml-var
-      first> makes <dtml-var salary> Euro per year.</p>
-    </dtml-in>
-
-  <dtml-var standard_html_footer>
-
-and the ZPT version::
-
-  <div>
-    <tal:div  tal:repeat="row python: context.employee_by_id(emp_id=42)">
-      <h1 tal:content="string: ${row/last}, ${row/first}" />
-      <p>
-       <span tal:content="string:${row/first}s employee id is ${row/emp_id}. 
-             ${row/first} makes ${row/salary} Euro per year.
-    </tal:div>
-  </div>
-
-Remember, the *employee_by_id* method returns only one record, so the
-body of the *in* tag in this method will execute only once. In the
-example you were calling the Z SQL Method like any other method and
-passing it a keyword argument for *emp_id*.  The same can be done
-easily from Python::
-
-  ## Script (Python) "join_name"
-  ##parameters=id
-  ##
-  for result in context.employee_by_id(emp_id=id):
-      return result.last + ', ' + result.first
-
-This script accepts an *id* argument and passes it to *employee_by_id*
-as the *emp_id* argument.  It then iterates over the single result and
-joins the last name and the first name with a comma.
-
-You can provide more control over your relational data by calling Z SQL
-Methods with explicit arguments. It's also worth noting that from DTML
-and Python Z SQL Methods can be called with explicit arguments just
-like you call other Zope methods.
-
-Acquiring Arguments from other Objects
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Z SQL can acquire information from other objects and be used to
-modify the SQL query.  Consider the below figure, which shows a
-collection of Folders in a organization's website.
-
-.. figure:: ../Figures/10-7.png
-
-   Folder structure of an organizational website
-
-Suppose each department folder has a *department_id* string
-property that identifies the accounting ledger id for that
-department. This property could be used by a shared Z SQL Method to
-query information for just that department.  To illustrate,
-create various nested folders with different *department_id*
-string properties and then create a Z SQL Method with the id
-*requisition_something* in the root folder that takes four
-arguments, *department_id*, *description*, *quantity*, and *unit_cost*. and the
-following query template::
-
-  INSERT INTO requisitions 
-    (
-      department_id, description, quantity, unit_cost
-    )
-  VALUES
-    (
-      <dtml-sqlvar department_id type="string">,
-      <dtml-sqlvar description type="string">,
-      <dtml-sqlvar quantity type="int">,
-      <dtml-sqlvar unit_cost type="float">
-    )
-
-Now, create a Z Search Interface with a *Search Id* of
-"requisitionSomethingForm" and the *Report id* of
-"requisitionSomething".  Select the *requisition_something* Z
-SQL Method as the *Searchable Object* and click *Add*.
-
-Edit the *requisitionSomethingForm* and remove the first input box for
-the *department_id* field.  We don't want the value of *department_id*
-to come from the form, we want it to come from a property that is
-acquired.
-
-Now, you should be able to go to a URL like::
-
-  http://example.org/Departments/Support/requisitionSomethingForm
-
-and requisition some punching bags for the Support department.
-Alternatively, you could go to::
-
-  http://example.org/Departments/Sales/requisitionSomethingForm
-
-and requisition some tacky rubber key-chains with your logo on
-them for the Sales department.  Using Zope's security system as
-described in the chapter entitled `Users and
-Security <Security.html>`_, you can now restrict access to these forms
-so personnel from departments can requisition items just for their
-department and not any other.
-
-The interesting thing about this example is that *department_id*
-was not one of the arguments provided to the query.  Instead of
-obtaining the value of this variable from an argument, it
-*acquires* the value from the folder where the Z SQL Method is
-accessed.  In the case of the above URLs, the
-*requisition_something* Z SQL Method acquires the value from the
-*Sales* and *Support* folders. This allows you to tailor SQL
-queries for different purposes. All the departments can share a
-query but it is customized for each department.
-
-By using acquisition and explicit argument passing you can
-tailor your SQL queries to your web application.
-
-Traversing to Result Objects
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-So far you've provided arguments to Z SQL Methods from web forms,
-explicit argument, and acquisition.  You can also provide
-arguments to Z SQL Methods by calling them from the web with
-special URLs. This is called *traversing* to results
-objects. Using this technique you can "walk directly up to" result
-objects using URLs.
-
-In order to traverse to result objects with URLs, you must be
-able to ensure that the SQL Method will return only one result
-object given one argument.  For example, create a new Z SQL Method
-named *employee_by_id*, with *emp_id* in the 'Arguments' field and the
-following in the SQL Template::
-
-  select * from employees where
-    <dtml-sqltest emp_id op="eq" type="int">
-
-This method selects one employee out of the *employees* table based on
-their employee id.  Since each employee has a unique id, only one
-record will be returned. Relational databases can provide these kinds
-of uniqueness guarantees.
-
-Zope provides a special URL syntax to access ZSQL Methods that always
-return a single result. The URL consists of the URL of the ZSQL Method
-followed by the argument name followed by the argument value. For
-example, *http://localhost:8080/employee_by_id/emp_id/42*. Note, this 
-URL will return a single result object as if you queried the ZSQL
-Method from DTML and passed it a single argument it would return
-a list of results that happend to only have one item in it.
-
-Unfortunately the result object you get with this URL is not
-very interesting to look at. It has no way to display itself in
-HTML. You still need to display the result object.  To do this,
-you can call a DTML Method on the result object.  This can be
-done using the normal URL acquisition rules described in Chapter
-10, "Advanced Zope Scripting".  For example, consider the
-following URL::
-
-  http://localhost:8080/employee_by_id/emp_id/42/viewEmployee
-
-Here we see the *employee_by_id* Z SQL Method being passed the *emp_id*
-argument by URL. The *viewEmployee* method is then called on the
-result object. Let's create a *viewEmployee* DTML Method and try
-it out. Create a new DTML Method named *viewEmployee* and give
-it the following content::
-
-  <dtml-var standard_html_header>
-
-    <h1><dtml-var last>, <dtml-var first></h1>
-
-    <p><dtml-var first>'s employee id is <dtml-var emp_id>.  <dtml-var
-    first> makes <dtml-var salary fmt="dollars-and-cents"> per year.</p>
-
-  <dtml-var standard_html_footer>
-
-Now when you go to the URL
-*http://localhost:8080/employee_by_id/emp_id/42/viewEmployee*
-the *viewEmployee* DTML Method is bound the result object that
-is returned by *employee_by_id*.  The *viewEmployee* method can
-be used as a generic template used by many different Z SQL
-Methods that all return employee records.
-
-Since the *employee_by_id* method only accepts one argument, it
-isn't even necessary to specify *emp_id* in the URL to qualify
-the numeric argument.  If your Z SQL Method has one argument,
-then you can configure the Z SQL Method to accept only one extra
-path element argument instead of a pair of arguments.  This
-example can be simplified even more by selecting the
-*employee_by_id* Z SQL Method and clicking on the *Advanced*
-tab.  Here, you can see a check box called *Allow "Simple" Direct
-Traversal*.  Check this box and click *Change*.  Now, you can
-browse employee records with simpler URLs like
-*http://localhost:8080/employee_by_id/42/viewEmployee*.  Notice
-how no *emp_id* qualifier is declared in the URL.
-
-Traversal gives you an easy way to provide arguments and bind
-methods to Z SQL Methods and their results.  Next we'll show you
-how to bind whole classes to result objects to make them even
-more powerful.
-
-Other Result Object Methods
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Up to now we have just been iterating through the attributes of
-the Result object in DTML. The result object does however provide
-other methods which can be easier in some situations. These
-methods can be accessed from Scripts (Python) and page templates.
-For example in Python we could write::
-
-  result=context.list_all_employees()
-  return len(result)
-
-and in ZPT::
-
-  <span tal:content="python: len(list_all_employees())" />
-
-
-Assuming that we have set 'result' to being a result object we can
-use the following methods:
-
-'len(result)'
-  this will show the number rows returned (which would be 3 in the example
-  above).
-
-'result.names()'
-  a list of all the column headings, returning a list containing 'emp_id',
-  'first', 'last' and 'salary'
-
-'result.tuples()'
-  returns a list of tuples in our example::
-
-      [(43, 'Bob', 'Roberts', 50000),
-       (101, 'Cheeta', 'leCat', 100000),
-       (99, 'Jane', 'Junglewoman', 100001)]
-
-'result.dictionaries()'
-  will return a list of dictionaries, with one dictionary for each row::
-
-        [{'emp_id': 42, 'first': 'Bob','last': 'Roberts', 'salary': 50000},
-         {'emp_id': 101, 'first: 'Cheeta', 'last': 'leCat', 'salary': 100000},
-         {'emp_id': 99, 'first': 'Jane', 'last': 'Junglewoman', 'salary': 100001}]
-
-'result.data_dictionary()'
-  returns a dictionary describing the structure of the results table. The
-  dictionary has the key 'name', 'type', 'null' and 'width'. Name and type
-  are self explanatory, 'null' is true if that field may contain a null
-  value and width is the width in characters of the field. Note that 'null'
-  and 'width' may not be set by some Database Adapters.
-
-'result.asRDB()'
-  displays the result in a similar way to a relational database. The DTML
-  below displays the result below::
-
-    <pre>
-      <dtml-var "list_all_employees().asRDB()">
-    </pre>
-
-    ... displays ...
-
-    emp_id first last salary
-    42 Bob Roberts 50000
-    101 Cheeta leCat 100000
-    99 Jane Junglewoman 100001
-
-'result[0][1]'
-  return row 0, column 1 of the result, 'bob' in this example. Be careful
-  using this method as changes in the schema will cause unexpected results.
-
-Binding Classes to Result Objects
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A Result object has an attribute for each column in a results row.
-As we have seen there are some basic methods for processing these
-attributes to produce some more useful output. However we can go
-further by writing our own custom methods and adding them into the
-Result object.
-
-There are two ways to bind a method to a Result object.  As you
-saw previously, you can bind DTML and other methods to Z SQL
-Method Result objects using traversal to the results object
-coupled with the normal URL based acquisition binding mechanism
-described in the chapter entitled `Advanced Zope
-Scripting <ScriptingZope.html>`_.  You can also bind methods to Result
-objects by defining a Python class that gets *mixed in* with the
-normal, simple Result object class.  These classes are defined in
-the same location as External Methods in the filesystem, in Zope's
-*Extensions* directory.  Python classes are collections of methods
-and attributes.  By associating a class with a Result object, you
-can make the Result object have a rich API and user interface.
-
-Classes used to bind methods and other class attributes to
-Result classes are called *Pluggable Brains*, or just *Brains*.
-Consider the example Python class::
-
-  class Employee:
-
-    def fullName(self):
-      """ The full name in the form 'John Doe' """
-      return self.first + ' ' + self.last
-
-When result objects with this Brains class are created as the
-result of a Z SQL Method query, the Results objects will have
-*Employee* as a base class. This means that the record objects
-will have all the methods defined in the *Employee* class,
-giving them behavior, as well as data.
-
-To use this class, create the above class in the *Employee.py*
-file in the *Extensions* directory. Go the *Advanced* tab of the
-*employee_by_id* Z SQL Method and enter *Employee* in the *Class
-Name* field, and *Employee* in the *Class File* field and click
-*Save Changes*.  Now you can edit the *viewEmployee* DTML Method
-to contain::
-
-  <dtml-var standard_html_header>
-
-    <h1><dtml-var fullName></h1>
-
-    <p><dtml-var first>'s employee id is <dtml-var emp_id>.  <dtml-var
-    first> makes <dtml-var salary fmt="dollars-and-cents"> per year.</p>
-
-  <dtml-var standard_html_footer>
-
-Now when you go to the URL
-*http://localhost:8080/employee_by_id/42/viewEmployee* the
-*fullName* method is called by the *viewEmployee* DTML Method.
-The *fullName* method is defined in the *Employee* class of the
-*Employee* module and is bound to the result object returned by
-*employee_by_id*
-
-*Brains* provide a very powerful facility which allows you to
-treat your relational data in a more object-centric way. For
-example, not only can you access the *fullName* method using
-direct traversal, but you can use it anywhere you handle result
-objects. For example::
-
-  <dtml-in employee_by_id>
-    <dtml-var fullName>
-  </dtml-in>
-
-For all practical purposes your Z SQL Method returns a sequence
-of smart objects, not just data.
-
-This example only "scratches the surface" of what can be done with
-Brains classes. With a bit of Python, you could create brains
-classes that accessed network resources, called other Z SQL
-Methods, or performed all kinds of business logic.  Since advanced
-Python programming is not within the scope of this book, we
-regrettably cannot provide a great number of examples of this sort
-of functionality, but we will at least provide one below.
-
-Here's a more powerful example of brains. Suppose that you have
-an *managers* table to go with the *employees* table that you've
-used so far. Suppose also that you have a *manager_by_id* Z SQL
-Method that returns a manager id manager given an *emp_id* argument::
-
-  select manager_id from managers where
-    <dtml-sqltest emp_id type="int" op="eq">        
-
-You could use this Z SQL Method in your brains class like so::
-
-  class Employee:
-
-      def manager(self):
-          """
-          Returns this employee's manager or None if the
-          employee does not have a manager.
-          """
-          # Calls the manager_by_id Z SQL Method.
-          records=self.manager_by_id(emp_id=self.emp_id)
-          if records:
-              manager_id=records[0].manager_id
-              # Return an employee object by calling the
-              # employee_by_id Z SQL Method with the manager's emp_id
-              return self.employee_by_id(emp_id=manager_id)[0]
-
-This 'Employee' class shows how methods can use other Zope
-objects to weave together relational data to make it seem like a
-collection of objects. The 'manager' method calls two Z SQL
-Methods, one to figure out the emp_id of the employee's manager,
-and another to return a new Result object representing the
-manager. You can now treat employee objects as though they have
-simple references to their manager objects. For example you
-could add something like this to the *viewEmployee* DTML Method::
-
-  <dtml-if manager>
-    <dtml-with manager>
-      <p> My manager is <dtml-var first> <dtml-var last>.</p>
-    </dtml-with>
-  </dtml-if>
-
-As you can see brains can be both complex and powerful. When
-designing relational database applications you should try to
-keep things simple and add complexity slowly. It's important to make
-sure that your brains classes don't add lots of unneeded overhead. 
-
-Caching Results
-~~~~~~~~~~~~~~~
-
-You can increase the performance of your SQL queries with
-caching. Caching stores Z SQL Method results so that if you call
-the same method with the same arguments frequently, you won't
-have to connect to the database every time. Depending on your
-application, caching can dramatically improve performance.
-
-To control caching, go to the *Advanced* tab of a SQL Method. You have
-three different cache controls as shown in the figure below.
-
-.. figure:: ../Figures/10-8.png
-
-   Caching controls for Z SQL Methods
-
-The *Maximum number of rows received* field controls how much
-data to cache for each query. The *Maximum number of results to
-cache* field controls how many queries to cache. The *Maximum
-time (in seconds) to cache results* controls how long cached
-queries are saved for.  In general, the larger you set these
-values the greater your performance increase, but the more
-memory Zope will consume. As with any performance tuning, you
-should experiment to find the optimum settings for your application.
-
-In general you will want to set the maximum results to cache to
-just high enough and the maximum time to cache to be just long
-enough for your application. For site with few hits you should
-cache results for longer, and for sites with lots of hits you
-should cache results for a shorter period of time. For machines
-with lots of memory you should increase the number of cached
-results. To disable caching set the cache time to zero
-seconds. For most queries, the default value of 1000 for the
-maximum number of rows retrieved will be adequate. For extremely
-large queries you may have to increase this number in order to
-retrieve all your results.
-
-Transactions
-~~~~~~~~~~~~
-
-A transaction is a group of operations that can be undone all at
-once.  As was mentioned in the chapter entitled `Zope Concepts and
-Architecture <ZopeArchitecture.html>`_, all changes done to Zope are
-done within transactions.  Transactions ensure data integrity.
-When using a system that is not transactional and one of your web
-actions changes ten objects, and then fails to change the
-eleventh, then your data is now inconsistent.  Transactions allow
-you to revert all the changes you made during a request if an
-error occurs.
-
-Imagine the case where you have a web page that bills a customer
-for goods received.  This page first deducts the goods from the
-inventory, and then deducts the amount from the customers
-account.  If the second operation fails for some reason you
-want to make sure the change to the inventory doesn't take effect.
-
-Most commercial and open source relational databases support
-transactions. If your relational database supports transactions,
-Zope will make sure that they are tied to Zope transactions. This
-ensures data integrity across both Zope and your relational
-database.
-
-In our example, the transaction would start with the customer
-submitting the form from the web page and would end when the page
-is displayed. It is guaranteed that operations in this transaction
-are either all performed or none are performed even if these
-operations use a mix of Zope Object Database and external
-relational database.
-
-Further help
-------------
-
-The zope-db at zope.org is the place to ask questions about relational
-databases. You can subscribe or browse the archive of previous postings
-at http://mail.zope.org/mailman/listinfo/zope-db
-
-Summary
--------
-
-Zope allows you to build web applications with relational
-databases. Unlike many web application servers, Zope has its own
-object database and does not require the use of relational
-databases to store information.
-
-Zope lets you use relational data just like you use other Zope
-objects. You can connect your relational data to business logic
-with scripts and brains, you can query your relational data with Z
-SQL Methods and presentation tools like DTML, and your can even
-use advanced Zope features like URL traversal, acquisition, undo
-and security while working with relational data.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/ScriptingZope.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/ScriptingZope.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/ScriptingZope.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,926 +0,0 @@
-Advanced Zope Scripting
-=======================
-
-In the chapter entitled "Basic Zope Scripting", you have seen
-how to manage Zope objects programmatically.  In this chapter,
-we will explore this topic some more.  Subjects discussed
-include additional scripting objects, script security, and
-calling script objects from presentation objects like Page
-Templates.  As we have mentioned before,
-separation of logic and presentation is a key factor in
-implementing maintainable web applications.
-
-What is *logic* and how does it differ from presentation? Logic
-provides those actions which change objects, send messages, test
-conditions and respond to events, whereas presentation formats and
-displays information and reports. Typically you will use
-Page Templates to handle presentation, and Zope scripting to
-handle logic.
-
-Warning
--------
-
-Zope *Script* objects are objects that encapsulate a small chunk of code
-written in a programming language. They first appeared in Zope 2.3, and have
-been the preferred way to write programming logic in Zope for many years. Today
-it is discouraged to use Scripts for any but the most minimal logic. If you
-want to create more than trivial logic, you should approach this by creating a
-Python package and write your logic *on the file system*.
-
-This book does not cover this development approach in its details. This
-chapter is still useful to read, as it allows you to get an understanding on
-some of the more advanced techniques and features of Zope.
-
-Calling Scripts
----------------
-
-In the "Basic Zope Scripting" chapter, you learned how to call scripts from the
-web and, conversely, how to call Page Templates from Python-based Scripts. In
-fact scripts can call scripts which call other scripts, and so on.
-
-Calling Scripts from Other Objects
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can call scripts from other objects, whether they are
-Page Templates or Scripts (Python). The
-semantics of each language differ slightly, but the same rules
-of acquisition apply. You do not necessarily have to know what
-language is used in the script you are calling; you only need to
-pass it any parameters that it requires, if any.
-
-Calling Scripts from Page Templates 
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-Calling scripts from Page Templates is much like calling them
-by URL or from Python. Just use standard TALES path
-expressions as described in the chapter entitled "Using Zope
-Page Templates.":ZPT.html>`_  For example::
-
-  <div tal:replace="context/hippo/feed">
-    Output of feed()
-  </div>
-
-The inserted value will be HTML-quoted. You can disable
-quoting by using the *structure* keyword, as described in
-the chapter entitled `Advanced Page Templates <AdvZPT.html>`_
-
-To call a script without inserting a value in the
-page, you can use *define* and ignore the variable assigned::
-
-  <div tal:define="dummy context/hippo/feed" />
-
-In a page template, *context* refers to the current context.  It
-behaves much like the *context* variable in a Python-based
-Script.  In other words, *hippo* and *feed* will both be
-looked up by acquisition.
-
-If the script you call requires arguments, you must use a 
-TALES python expression in your template, like so::
-
-  <div tal:replace="python:context.hippo.feed(food='spam')">
-    Output of feed(food='spam')
-  </div>
-
-Just as in Path Expressions, the 'context' variable refers to the
-acquisition context the Page Template is called in.  
-
-The python expression above is exactly like a line of
-code you might write in a Script (Python).
-
-One difference is the notation used for attribute access --
-Script (Python) uses the standard Python period notation,
-whereas in a TALES path expression, a forward slash is
-used.
-
-For further reading on using Scripts in Page Templates, refer
-to the chapter entitled `Advanced Page Templates`_.
-
-Calling scripts from Python
-%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-Calling scripts from other scripts works similar to calling
-scripts from page templates, except that you must
-*always* use explicit calling (by using
-parentheses). For example, here is how you might call
-the *updateInfo* script from Python::
-
-  new_color='brown'
-  context.updateInfo(color=new_color, 
-                     pattern="spotted")
-
-Note the use of the *context* variable to tell Zope to find
-updateInfo by acquisition. 
-
-Zope locates the scripts you call by using acquisition the
-same way it does when calling scripts from the web.  Returning
-to our hippo feeding example of the last section, let's see
-how to vaccinate a hippo from Python. The figure
-below shows a slightly updated object hierarchy that contains
-a script named *vaccinateHippo.py*. 
-
-.. figure:: ../Figures/zoo-again.png 
-
-   A collection of objects and scripts
-
-Here is how you can call the *vaccinate* script on the
-*hippo* obect from the *vaccinateHippo.py* script::
-
-  context.Vet.LargeAnimals.hippo.vaccinate()
-
-In other words, you simply access the object by using the same
-acquisition path as you would use if you called it from the
-web. The result is the same as if you visited the URL
-*Zoo/Vet/LargeAnimals/hippo/vaccinate*. Note that in this Python
-example, we do not bother to specify *Zoo* before *Vet*. We can
-leave *Zoo* out because all of the objects involved, including
-the script, are in the Zoo folder, so it is implicitly part
-of the acquisition chain.
-
-Calling Scripts: Summary and Comparison
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-Let's recap the ways to call a hypothetical *updateInfo* script on a *foo*
-object, with argument passing: from your web browser, from Python and from Page
-Templates.
-
-- by URL::
-
-   http://my-zope-server.com:8080/foo/updateInfo?amount=lots
-
-- from a Script (Python)::
-
-   context.foo.updateInfo(amount="lots")
-
-- from a Page Template::
-
-   <span tal:content="context/foo/updateInfo" />
-
-- from a Page Template, with arguments::
-
-   <span tal:content="python:context.foo.updateInfo(amount='lots')" />
-
-Regardless of the language used, this is a very common idiom
-to find an object, be it a script or any other kind of object:
-you ask the context for it, and if it exists in this context
-or can be acquired from it, it will be used.
-
-Zope will throw a *KeyError* exception if the script you are
-calling cannot be acquired. If you are not certain that a
-given script exists in the current context, or if you want to
-compute the script name at run-time, you can use this Python
-idiom::
-
-  updateInfo = getattr(context, "updateInfo", None)
-  if updateInfo is not None:
-      updateInfo(color="brown", pattern="spotted")
-  else:
-      # complain about missing script
-      return "error: updateInfo() not found"
-
-The *getattr* function is a Python built-in. The first
-argument specifies an object, the second an attribute
-name.  The *getattr* function will return the named
-attribute, or the third argument if the attribute cannot be
-found. So in the next statement we just have to test whether
-the *updateInfo* variable is None, and if not, we know we can
-call it.
-
-Advanced Acquisition 
---------------------
-
-In the chapter entitled "Acquisition":Acquisition.html>`_ , we
-introduced acquisition by containment, which we have been using
-throughout this chapter. In acquisition by containment, Zope
-looks for an object by going back up the containment hierarchy
-until it finds an object with the right id. In Chapter 7 we also
-mentioned *context acquisition*, and warned that it is a tricky
-subject capable of causing your brain to explode. If you are
-ready for exploding brains, read on.
-
-The most important thing for you to understand in this chapter is
-that context acquisition exists and can interfere with whatever
-you are doing. Today it is seen as a fragile and complex topic and
-rarely ever used in practice.
-
-Recall our Zoo example introduced earlier in this chapter.
-
-.. figure:: ../Figures/zoo.png 
-
-   Zope Zoo Example hierarchy
-
-We have seen how Zope uses URL traversal and acquisition to find
-objects  in  higher containers.  More  complex arrangements  are
-possible. Suppose you want to call the *vaccinate* script on the
-*hippo*  object. What  URL can  you use?  If you  visit  the URL
-*Zoo/LargeAnimals/hippo/vaccinate* Zope will not be able to find
-the  *vaccinate* script  since it  isn't in  any of  the *hippo*
-object's containers.
-
-The solution is to give the path to the script as part of the
-URL. Zope allows you to combine two or more URLs into one in
-order to provide more acquisition context! By using acquisition,
-Zope will find the script as it backtracks along the URL. The
-URL to vaccinate the hippo is
-*Zoo/Vet/LargeAnimals/hippo/vaccinate*. Likewise, if you want to
-call the *vaccinate* script on the *kargarooMouse* object you
-should use the URL
-*Zoo/Vet/SmallAnimals/kargarooMouse/vaccinate*.
-
-Let's follow along as Zope traverses the URL
-*Zoo/Vet/LargeAnimals/hippo/vaccinate*. Zope starts in the root
-folder and looks for an object named *Zoo*. It moves to the
-*Zoo* folder and looks for an object named *Vet*. It moves to
-the *Vet* folder and looks for an object named
-*LargeAnimals*. The *Vet* folder does not contain an object with
-that name, but it can acquire the *LargeAnimals* folder from its
-container, *Zoo* folder. So it moves to the *LargeAnimals*
-folder and looks for an object named *hippo*.  It then moves to
-the *hippo* object and looks for an object named
-*vaccinate*. Since the *hippo* object does not contain a
-*vaccinate* object and neither do any of its containers, Zope
-backtracks along the URL path trying to find a *vaccinate*
-object. First it backs up to the *LargeAnimals* folder where
-*vaccinate* still cannot be found. Then it backs up to the *Vet*
-folder.  Here it finds a *vaccinate* script in the *Vet*
-folder. Since Zope has now come to the end of the URL, it calls
-the *vaccinate* script in the context of the *hippo* object.
-
-Note that we could also have organized the URL a bit
-differently. *Zoo/LargeAnimals/Vet/hippo/vaccinate* would also
-work. The difference is the order in which the context elements
-are searched. In this example, we only need to get *vaccinate*
-from *Vet*, so all that matters is that *Vet* appears in the URL
-after *Zoo* and before *hippo*.
-
-When Zope looks for a sub-object during URL traversal, it first
-looks for the sub-object in the current object. If it cannot
-find it in the current object it looks in the current object's
-containers. If it still cannot find the sub-object, it backs up
-along the URL path and searches again. It continues this process
-until it either finds the object or raises an error if it cannot
-be found. If several context folders are used in the URL, they
-will be searched in order from *left to right*.
-
-Context acquisition can be a very useful mechanism, and it
-allows you to be quite expressive when you compose URLs. The
-path you tell Zope to take on its way to an object will
-determine how it uses acquisition to look up the object's
-scripts.
-
-Note that not all scripts will behave differently depending on
-the traversed URL. For example, you might want your script to
-acquire names only from its parent containers and not from the
-URL context. To do so, simply use the *container* variable
-instead of the *context* variable in the script, as described
-above in the section "Using Python-based Scripts."
-
-Context Acquisition Gotchas
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Containment before context
-%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-It is important to realize that context acquisition
-*supplements* container acquisition. It does not *override*
-container acquisition.
-
-One at a time
-%%%%%%%%%%%%%
-
-Another point that often confuses new users is that each element
-of a path "sticks" for the duration of the traversal, once it is
-found. Think of it this way: objects are looked up one at a
-time, and once an object is found, it will not be looked up
-again.  For example, imagine this folder structure:
-
-.. figure:: ../Figures/acquisition.png
-
-   Acquisition example folder structure
-
-Now suppose that the *about_penguins* page contains a link to
-*Images/penguins.png*. Shouldn't this work? Won't
-*/Images/penguins.png* succeed when
-*/Content/Images/penguins.png* fails?  The answer is no. We
-always traverse from left to right, one item at a time. 
-First we find *Content*, then *Images* within it; *penguins.png* 
-appears in neither of those, and we haved searched all 
-parent containers of every element in the URL, so 
-there is nothing more to search in this URL.
-Zope stops there and raises an error. Zope never looks in */Images*
-because it has already found */Content/Images*.
-
-Readability
-%%%%%%%%%%%
-
-Context acquisition can make code more difficult to
-understand. A person reading your script can no longer simply
-look backwards up one containment hierarchy to see where an
-acquired object might be; many more places might be searched,
-all over the zope tree folder. And the order in which objects
-are searched, though it is consistent, can be confusing.
-
-Fragility
-%%%%%%%%%
-
-Over-use of context acquisition can also lead to fragility. In
-object-oriented terms, context acquisition can lead to a site
-with low cohesion and tight coupling. This is generally regarded
-as a bad thing. More specifically, there are many simple actions
-by which an unwitting developer could break scripts that rely on
-context acquisition. These are more likely to occur than with
-container acquisition, because potentially every part of your
-site affects every other part, even in parallel folder branches.
-
-For example, if you write a script that calls another script by
-a long and torturous path, you are assuming that the folder tree
-is not going to change. A maintenance decision to reorganize the
-folder hierarchy could require an audit of scripts in *every*
-part of the site to determine whether the reorganization will
-break anything. 
-
-Recall our Zoo example. There are several ways in which a zope
-maintainer could break the feed() script:
-
-Inserting another object with the name of the method
-  This is a normal technique for customizing behavior in Zope, but context
-  acquisition makes it more likely to happen by accident. Suppose that
-  giraffe vaccination is controlled by a regularly scheduled script that
-  calls *Zoo/Vet/LargeAnimals/giraffe/feed*. Suppose a content
-  administrator doesn't know about this script and adds a DTML page called
-  *vaccinate* in the giraffe folder, containing information about
-  vaccinating giraffes. This new *vaccinate* object will be acquired before
-  *Zoo/Vet/vaccinate*.  Hopefully you will notice the problem before your
-  giraffes get sick.
-
-Calling an inappropriate path
-  if you visit *Zoo/LargeAnimals/hippo/buildings/visitor_reception/feed*,
-  will the reception area be filled with hippo food?  One would hope not.
-  This might even be possible for someone who has no permissions on the
-  reception object. Such URLs are actually not difficult to construct. For
-  example, using relative URLs in standard_html_header can lead to some
-  quite long combinations of paths.
-
-Thanks to Toby Dickenson for pointing out these fragility issues
-on the zope-dev mailing list.
-
-
-Passing Parameters to Scripts
------------------------------
-
-All scripts can be passed parameters. A parameter gives a script
-more information about what to do. When you call a script from the
-web, Zope will try to find the script's parameters in the web
-request and pass them to your script. For example, if you have a
-script with parameters *dolphin* and *REQUEST* Zope will
-look for *dolphin* in the web request, and will pass the request
-itself as the *REQUEST* parameter. In practical terms this means
-that it is easy to do form processing in your script. For example,
-here is a form::
-
-  <form action="form_action">
-    Name of Hippo <input type="text" name="name" /><br />
-    Age of Hippo <input type="text" name="age" /><br />
-    <input type="submit" />
-  </form>
-
-You can easily process this form with a script named
-*form_action* that includes *name* and *age* in its parameter
-list::
-
-  ## Script (Python) "form_action"
-  ##parameters=name, age
-  ##
-  "Process form"
-  age=int(age)
-  message= 'This hippo is called %s and is %d years old' % (name, age)
-  if age < 18:
-      message += '\n %s is not old enough to drive!' % name
-  return message
-
-There is no need to process the form manually to extract values
-from it. Form elements are passed as strings, or lists of
-strings in the case of checkboxes and multiple-select input.
-
-In addition to form variables, you can specify any request
-variables as script parameters. For example, to get access to the
-request and response objects just include 'REQUEST' and 'RESPONSE'
-in your list of parameters. Request variables are detailed more
-fully in `Appendix B: API Reference <AppendixB.html>`_ .
-
-In the Script (Python) given above, there is a subtle problem. You
-are probably expecting an integer rather than a string for age,
-but all form variables are passed as strings.  You could
-manually convert the string to an integer using the Python *int*
-built-in::
-
-  age = int(age)
-
-But this manual conversion may be inconvenient. Zope provides a
-way for you to specify form input types in the form, rather than
-in the processing script. Instead of converting the *age* variable
-to an integer in the processing script, you can indicate that it
-is an integer in the form itself::
-
-  Age <input type="text" name="age:int" />
-
-The ':int' appended to the form input name tells Zope to
-automatically convert the form input to an integer. This
-process is called *marshalling*. If the user of
-your form types something that cannot be converted to an integer
-(such as "22 going on 23") then Zope will raise an exception as
-shown in the figure below.
-
-.. figure:: ../Figures/8-3.png
-
-   Parameter conversion error
-
-It's handy to have Zope catch conversion errors, but you may not
-like Zope's error messages. You should avoid using Zope's
-converters if you want to provide your own error messages.
-
-Zope can perform many parameter conversions. Here is a list of Zope's
-basic parameter converters.
-
-*boolean*
-  Converts a variable to true or false. Variables
-  that are 0, None, an empty string, or an empty sequence are
-  false, all others are true.
-
-*int*
-  Converts a variable to an integer.
-
-*long*
-  Converts a variable to a long integer.
-
-*float*
-  Converts a variable to a floating point number.
-
-*string*
-  Converts a variable to a string. Most variables
-  are strings already so this converter is seldom used.
-
-*text*
-  Converts a variable to a string with normalized line
-  breaks.  Different browsers on various platforms encode line
-  endings differently, so this script makes sure the line endings are
-  consistent, regardless of how they were encoded by the browser.
-
-*list*
-  Converts a variable to a Python list.
-
-*tuple*
-  Converts a variable to a Python tuple. A tuple is
-  like a list, but cannot be modified.
-
-*tokens*
-  Converts a string to a list by breaking it on white
-  spaces.
-
-*lines*
-  Converts a string to a list by breaking it on new
-  lines.
-
-*date*
-  Converts a string to a *DateTime* object. The formats
-  accepted are fairly flexible, for example '10/16/2000',
-  '12:01:13 pm'.
-
-*required*
-  Raises an exception if the variable is not present.
-
-*ignore_empty*
-  Excludes the variable from the request if
-  the variable is an empty string.
-
-These converters all work in more or less the same way to coerce
-a form variable, which is a string, into another specific
-type. You may recognize these converters from the chapter
-entitled Using Basic Zope Objects , in which we
-discussed properties. These converters are used by Zope's
-property facility to convert properties to the right type.
-
-The *list* and *tuple* converters can be used in combination with other
-converters.  This allows you to apply additional converters to each
-element of the list or tuple.  Consider this form::
-
-  <form action="processTimes"> 
-
-    <p>I would prefer not to be disturbed at the following
-    times:</p>
-
-    <input type="checkbox" name="disturb_times:list:date"
-    value="12:00 AM" /> Midnight<br />
-
-    <input type="checkbox" name="disturb_times:list:date"
-    value="01:00 AM" /> 1:00 AM<br />
-
-    <input type="checkbox" name="disturb_times:list:date"
-    value="02:00 AM" /> 2:00 AM<br />
-
-    <input type="checkbox" name="disturb_times:list:date"
-    value="03:00 AM" /> 3:00 AM<br />
-
-    <input type="checkbox" name="disturb_times:list:date"
-    value="04:00 AM" /> 4:00 AM<br />
-
-    <input type="submit" />
-  </form>
-
-By using the *list* and *date* converters together, Zope will
-convert each selected time to a date and then combine all selected
-dates into a list named *disturb_times*.
-
-A more complex type of form conversion is to convert a series of inputs
-into *records.* Records are structures that have attributes. Using
-records, you can combine a number of form inputs into one variable with
-attributes.  The available record converters are:
-
-*record*
-  Converts a variable to a record attribute.
-
-*records*
-  Converts a variable to a record attribute in a list of
-  records.
-
-*default*
-  Provides a default value for a record attribute if the
-  variable is empty.
-
-*ignore_empty*
-  Skips a record attribute if the variable is empty.
-
-Here are some examples of how these converters are used::
-
-  <form action="processPerson">
-
-    First Name <input type="text" name="person.fname:record" /><br />
-    Last Name <input type="text" name="person.lname:record" /><br />
-    Age <input type="text" name="person.age:record:int" /><br />
-
-    <input type="submit" />
-  </form>
-
-This form will call the *processPerson* script with one
-parameter, *person*. The *person* variable will have the attributes
-*fname*, *lname* and *age*. Here's an example of how you might
-use the *person* variable in your *processPerson* script::
-
-  ## Script (Python) "processPerson"
-  ##parameters=person
-  ##
-  "Process a person record"
-  full_name="%s %s" % (person.fname, person.lname)
-  if person.age < 21:
-      return "Sorry, %s. You are not old enough to adopt an aardvark." % full_name
-  return "Thanks, %s. Your aardvark is on its way." % full_name
-
-The *records* converter works like the *record* converter except
-that it produces a list of records, rather than just one. Here is
-an example form::
-
-  <form action="processPeople">
-
-    <p>Please, enter information about one or more of your next of
-    kin.</p>
-
-    <p>
-      First Name <input type="text" name="people.fname:records" />
-      Last Name <input type="text" name="people.lname:records" />
-    </p>
-
-    <p>
-      First Name <input type="text" name="people.fname:records" />
-      Last Name <input type="text" name="people.lname:records" />
-    </p>
-
-    <p>
-      First Name <input type="text" name="people.fname:records" />
-      Last Name <input type="text" name="people.lname:records" />
-    </p>
-
-    <input type="submit" />
-  </form>    
-
-This form will call the *processPeople* script with a variable
-called *people* that is a list of records. Each record will have
-*fname* and *lname* attributes.  Note the difference between the
-*records* converter and the *list:record* converter: the former
-would create a list of records, whereas the latter would produce
-a single record whose attributes *fname* and *lname* would each
-be a list of values.
-
-The order of combined modifiers does not matter; for example,
-*int:list* is identical to *list:int*.
-
-Another useful parameter conversion uses form variables to
-rewrite the action of the form. This allows you to submit a form
-to different scripts depending on how the form is filled
-out. This is most useful in the case of a form with multiple
-submit buttons. Zope's action converters are:
-
-*action*
-  Appends the attribute value to the original form
-  action of the form. This is mostly useful for the case in
-  which you have multiple submit buttons on one form.  Each
-  button can be assigned to a script that gets called when that
-  button is clicked to submit the form. A synonym for *action*
-  is *method*.
-
-*default_action*
-  Appends the attribute value to the
-  original action of the form when no other *action* converter
-  is used.
-
-Here's an example form that uses action converters::
-
-  <form action="employeeHandlers">
-
-    <p>Select one or more employees</p>
-
-    <input type="checkbox" name="employees:list" value="Larry" /> Larry<br />
-    <input type="checkbox" name="employees:list" value="Simon" /> Simon<br />
-    <input type="checkbox" name="employees:list" value="Rene" /> Rene<br />
-
-    <input type="submit" name="fireEmployees:action" value="Fire!" /><br />
-
-    <input type="submit" name="promoteEmployees:action" value="Promote!" />
-
-  </form>
-
-We assume a folder 'employeeHandlers' containing two
-scripts named 'fireEmployees' and 'promoteEmployees'.  The
-form will call either the *fireEmployees* or the
-*promoteEmployees* script, depending on which of the two
-submit buttons is used.  Notice also how it builds a list
-of employees with the *list* converter.  Form converters
-can be very useful when designing Zope applications.
-
-Script Security
----------------
-
-All scripts that can be edited through the web are subject to
-Zope's standard security policies. The only scripts that are not
-subject to these security restrictions are scripts that must be
-edited through the filesystem.
-
-The chapter entitled `Users and Security <Security.html>`_ covers
-security in more detail. You should consult the *Roles of
-Executable Objects* and *Proxy Roles* sections for more
-information on how scripts are restricted by Zope security
-constraints.
-
-Security Restrictions of Script (Python)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Scripts are restricted in order to limit their ability
-to do harm. What could be harmful? In general, scripts
-keep you from accessing private Zope objects, making harmful
-changes to Zope objects, hurting the Zope process itself, and
-accessing the server Zope is running on. These restrictions
-are implemented through a collection of limits on what your
-scripts can do.
-
-Loop limits
-  Scripts cannot create infinite loops. If your script
-  loops a very large number of times Zope will raise an error. This
-  restriction covers all kinds of loops including *for* and *while*
-  loops. The reason for this restriction is to limit your ability to
-  hang Zope by creating an infinite loop.
-
-Import limits
-  Scripts cannot import arbitrary
-  packages and modules. You are limited to importing the
-  *Products.PythonScripts.standard* utility module, the
-  *AccessControl* module, some helper modules
-  (*string*, *random*, *math*, *sequence*), and modules
-  which have been specifically made available to scripts
-  by product authors.  See `Appendix B: API Reference`_
-  for more information on these
-  modules.
-
-Access limits
-  You are restricted by standard Zope
-  security policies when accessing objects. In other words
-  the user executing the script is checked for
-  authorization when accessing objects. As with all
-  executable objects, you can modify the effective roles a
-  user has when calling a script using *Proxy Roles* (see
-  the chapter entitled `Users and Security`_
-  for more information). In addition, you cannot access
-  objects whose names begin with an underscore, since Zope
-  considers these objects to be private. Finally, you can
-  define classes in scripts but it is not really practical
-  to do so, because you are not allowed to access
-  attributes of these classes! Even if you were allowed to
-  do so, the restriction against using objects whose names
-  begin with an underscore would prevent you from using
-  your class's __init__ method.  If you need to define
-  classes, use *packages* You may,
-  however, define functions in scripts, although it is
-  rarely useful or necessary to do so.  In practice, a
-  Script in Zope is treated as if it were a single method
-  of the object you wish to call it on.
-
-Writing limits
-  In general you cannot directly change Zope object
-  attributes using scripts. You should call the appropriate
-  methods from the Zope API instead.
-
-Despite these limits, a determined user could use large amounts
-of CPU time and memory using Python-based Scripts. So malicious
-scripts could constitute a kind of denial of service attack by
-using lots of resources. These are difficult problems to solve.
-You probably should not grant access to scripts to
-untrusted people.
-
-
-Python versus Page Templates
-----------------------------
-
-Zope gives you multiple ways to script. For small scripting
-tasks the choice of Python-based Scripts or Page Templates
-probably doesn't make a big difference.  For larger,
-logic-oriented tasks you should use Python-based Scripts or
-write packages on the file-system.
-
-For presentation, Python should *not* be used; instead you use ZPT.
-
-Just for the sake of comparison, here is a simple presentational script 
-suggested by Gisle Aas in ZPT and Python.
-
-In ZPT::
-
-  <div tal:repeat="item context/objectValues" 
-       tal:replace="python:'%s: %s\n' % (item.getId(), str(item))" />
-
-In Python::
-
-  for item in context.objectValues():
-      print "%s: %s" % (item.getId(), item)
-  print "done"
-  return printed
-
-Remote Scripting and Network Services
--------------------------------------
-
-Web servers are used to serve content to software clients; usually
-people using web browser software.  The software client can also be
-another computer that is using your web server to access some kind of
-service.
-
-Because Zope exposes objects and scripts on the web, it can be used to
-provide a powerful, well organized, secure web API to other remote
-network application clients.
-
-There are two common ways to remotely script Zope.  The first way
-is using a simple remote procedure call protocol called
-*XML-RPC*.  XML-RPC is used to execute a procedure on a remote
-machine and get a result on the local machine.  XML-RPC is designed
-to be language neutral, and in this chapter you'll see examples in
-Python and Java.
-
-The second common way to remotely script Zope is with any HTTP
-client that can be automated with a script.  Many language
-libraries come with simple scriptable HTTP clients and there are
-many programs that let you you script HTTP from the command line.
-
-Using XML-RPC
-~~~~~~~~~~~~~
-
-XML-RPC is a simple remote procedure call mechanism that works
-over HTTP and uses XML to encode information. XML-RPC clients
-have been implemented for many languages including Python,
-Java and JavaScript.
-
-In-depth information on XML-RPC can be found at the "XML-RPC
-website":http://www.xmlrpc.com/. 
-
-All Zope scripts that can be called from URLs can be called via
-XML-RPC. Basically XML-RPC provides a system to marshal
-arguments to scripts that can be called from the web. As you saw
-earlier in the chapter Zope provides its own marshaling
-controls that you can use from HTTP. XML-RPC and Zope's own
-marshaling accomplish much the same thing. The advantage of
-XML-RPC marshaling is that it is a reasonably supported
-standard that also supports marshaling of return values as well
-as argument values.
-
-Here's a fanciful example that shows you how to remotely script
-a mass firing of janitors using XML-RPC.
-
-Here's the code in Python::
-
-  import xmlrpclib
-
-  server = xmlrpclib.Server('http://www.zopezoo.org/')
-  for employee in server.JanitorialDepartment.personnel():
-      server.fireEmployee(employee)
-
-In Java::
-
-  try {
-      XmlRpcClient server = new XmlRpcClient("http://www.zopezoo.org/");
-      Vector employees = (Vector) server.execute("JanitorialDepartment.personnel");
-
-      int num = employees.size();
-      for (int i = 0; i < num; i++) {
-          Vector args = new Vector(employees.subList(i, i+1));
-          server.execute("fireEmployee", args);
-      }
-
-  } catch (XmlRpcException ex) {
-      ex.printStackTrace();
-  } catch (IOException ioex) {
-      ioex.printStackTrace();
-  }
-
-Actually the above example will probably not run correctly, since you
-will most likely want to protect the *fireEmployee* script. This brings
-up the issue of security with XML-RPC. XML-RPC does not have any
-security provisions of its own; however, since it runs over HTTP it can
-leverage existing HTTP security controls. In fact Zope treats an
-XML-RPC request exactly like a normal HTTP request with respect to
-security controls. This means that you must provide authentication in
-your XML-RPC request for Zope to grant you access to protected
-scripts.
-
-Remote Scripting with HTTP
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Any HTTP client can be used for remotely scripting Zope.
-
-On Unix systems you have a number of tools at your
-disposal for remotely scripting Zope. One simple example
-is to use *wget* to call Zope script URLs and use *cron*
-to schedule the script calls. For example, suppose you
-have a Zope script that feeds the lions and you would like
-to call it every morning.  You can use *wget* to call the
-script like so::
-
-  $ wget --spider http://www.zopezope.org/Lions/feed
-
-The *spider* option tells *wget* not to save the response as a
-file. Suppose that your script is protected and requires
-authorization. You can pass your user name and password with *wget* to
-access protected scripts::
-
-  $ wget --spider --http-user=ZooKeeper \
-      --http-passwd=SecretPhrase \
-      http://www.zopezope.org/Lions/feed
-
-Now let's use *cron* to call this command every morning at 8am. Edit
-your crontab file with the *crontab* command::
-
-  $ crontab -e
-
-Then add a line to call wget every day at 8 am::
-
-  0 8 * * * wget -nv --spider --http_user=ZooKeeper \
-    --http_pass=SecretPhrase http://www.zopezoo.org/Lions/feed
-
-(Beware of the linebreak -- the above should be input as
-one line, minus the backslash).
-
-The only difference between using *cron* and calling *wget* manually is
-that you should use the *nv* switch when using *cron* since you don't
-care about output of the *wget* command.
-
-For our final example let's get really perverse. Since networking is
-built into so many different systems, it's easy to find an unlikely
-candidate to script Zope. If you had an Internet-enabled toaster you
-would probably be able to script Zope with it. Let's take Microsoft
-Word as our example Zope client. All that's necessary is to get Word to
-agree to tickle a URL.
-
-The easiest way to script Zope with Word is to tell word to open a
-document and then type a Zope script URL as the file name as shown in
-[8-9].
-
-.. figure:: ../Figures/8-9.png
-
-   Calling a URL with Microsoft Word
-
-Word will then load the URL and return the results of calling the Zope
-script. Despite the fact that Word doesn't let you POST arguments this
-way, you can pass GET arguments by entering them as part of the URL.
-
-You can even control this behavior using Word's built-in Visual Basic
-scripting. For example, here's a fragment of Visual Basic that tells
-Word to open a new document using a Zope script URL::
-
-  Documents.Open FileName:="http://www.zopezoo.org/LionCages/wash?use_soap=1&water_temp=hot" 
-
-You could use Visual Basic to call Zope script URLs in many different
-ways.
-
-Zope's URL to script call translation is the key to remote
-scripting. Since you can control Zope so easily with simple URLs you
-can easy script Zope with almost any network-aware system.
-
-Conclusion
-----------
-
-With scripts you can control Zope objects and glue together your
-application's logic, data, and presentation. You can
-programmatically manage objects in your Zope folder hierarchy by
-using the Zope API.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/SearchingZCatalog.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/SearchingZCatalog.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/SearchingZCatalog.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,1890 +0,0 @@
-Searching and Categorizing Content
-==================================
-
-The ZCatalog is Zope's built in search engine. It allows you to
-categorize and search all kinds of Zope objects. You can also use it
-to search external data such as relational data, files, and remote
-web pages.  In addition to searching you can use the ZCatalog to
-organize collections of objects.
-
-The ZCatalog supports a rich query interface. You can perform full text
-searching, can search multiple indexes at once, and can even specify
-weighing for different fields in your results. In addition, the
-ZCatalog keeps track of meta-data about indexed objects.
-
-The two most common ZCatalog usage patterns are:
-
-Mass Cataloging
-  Cataloging a large collection of objects all at once.
-
-Automatic Cataloging
-  Cataloging objects as they are created and tracking changes made to them.
-
-Getting started with Mass Cataloging
-------------------------------------
-
-Let's take a look at how to use the ZCatalog to search documents.
-Cataloging a bunch of objects all at once is called *mass cataloging*.
-Mass cataloging involves four steps:
-
-- Creating a ZCatalog
-
-- Creating indexes
-
-- Finding objects and cataloging them
-
-- Creating a web interface to search the ZCatalog.
-
-Creating a ZCatalog
--------------------
-
-Choose *ZCatalog* from the product add list to create a ZCatalog
-object within a subfolder named 'Zoo'.  This takes you to the
-ZCatalog add form, as shown in the figure below.
-
-.. figure:: ../Figures/creatingzcatalog.png
-
-   ZCatalog add form
-
-The Add form asks you for an *Id* and a *Title*.  Give your
-ZCatalog the Id 'AnimalCatalog' and click *Add* to create your new
-ZCatalog.  The ZCatalog icon looks like a folder with a small
-magnifying glass on it.  Select the *AnimalCatalog* icon to see
-the *Contents* view of the ZCatalog.
-
-A ZCatalog looks a lot like a folder, but it has a few more
-tabs.  Six tabs on the ZCatalog are the exact same six tabs you
-find on a standard folder.  ZCatalog have the following views:
-*Contents*, *Catalog*, *Properties*, *Indexes*, *Metadata*,
-*Find Objects*, *Advanced*, *Undo*, *Security*, and *Ownership*.
-When you click on a ZCatalog, you are on the *Contents*
-view. Here, you can add new objects and the ZCatalog will
-contain them just as any folder does. Although a ZCatalog is
-like a normal Zope folder, this does not imply that the objects
-contained within it are automatically searchable.  A ZCatalog
-can catalog objects at any level of your site, and it needs to
-be told exactly which ones to index.
-
-Creating Indexes
-~~~~~~~~~~~~~~~~
-
-In order to tell Zope what to catalog and where to store the
-information, we need to create a *Lexicon* and an *Index*.  A
-*Lexicon* is necessary to provide word storage services for
-full-text searching, and an *Index* is the object which stores
-the data necessary to perform fast searching.
-
-In the contents view of the *AnimalCatalog* ZCatalog, choose
-*ZCTextIndex Lexicon*, and give it an id of *zooLexicon*
-
-.. figure:: ../Figures/creatinglexicon.png
-
-   ZCTextIndex Lexicon add form
-
-Now we can create an index that will record the information we
-want to have in the ZCatalog.  Click on the *Indexes* tab of the
-ZCatalog.  A drop down menu lists the available indexes.  Choose
-*ZCTextIndex*; in the add form fill in the id *zooTextIdx*.
-Fill in *PrincipiaSearchSource* in the "Field name" input.  This
-tells the ZCTextIndex to index the body text of the DTML
-Documents (*PrincipiaSearchSource* is an API method of all DTML
-Document and Method objects).  Note that *zooLexicon* is
-preselected in the *Lexicon* menu.
-
-.. figure:: ../Figures/creatingtextindex.png
-
-   ZCTextIndex add form
-
-.. note::
-
-   When you want the textindex to work on other types of objects,
-   they have to provide a method named "PrincipiaSearchSource" which
-   returns the data of the object which has to be searched.
-
-To keep this example short we will skip over some of the options
-presented here.  In the section on indexes below, we will
-discuss this more thoroughly.
-
-Additionally, we will have to tell the ZCatalog which attributes
-of each cataloged object that it should store directly.  These
-attributes are called *Metadata*, however they should not be
-confused with the idea of metadata in Zope CMF, Plone, or other
-content management systems--here, this just means that these are
-attributes that will be stored directly in the catalog for
-performance benefits.  For now, just go to the
-*Metadata* tab of the ZCatalog and add *id* and *title*.
-
-Finding and Cataloging Objects
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Now that you have created a ZCatalog and an Index, you can move
-onto the next step: finding objects and cataloging them.
-Suppose you have a zoo site with information about animals.  To
-work with these examples, create two DTML Documents along-side
-the *AnimalCatalog* object (within the same folder that contains
-the *AnimalCatalog* ZCatalog) that contain information about
-reptiles and amphibians.
-
-The first should have an Id of "chilean_frog", a title "Chilean
-four-eyed frog" and its body text should read something like
-this::
-
-  The Chilean four-eyed frog has a bright
-  pair of spots on its rump that look like enormous eyes. When
-  seated, the frog's thighs conceal these eyespots. When
-  predators approach, the frog lowers its head and lifts its
-  rump, creating a much larger and more intimidating head.
-  Frogs are amphibians.
-
-For the second, fill in an id of "carpet_python" and a title of
-"Carpet Python"; its body text could be::
-
-  *Morelia spilotes variegata* averages 2.4 meters in length.  It
-  is a medium-sized python with black-to-gray patterns of
-  blotches, crossbands, stripes, or a combination of these
-  markings on a light yellowish-to-dark brown background.  Snakes
-  are reptiles.
-
-Visitors to your Zoo want to be able to search for information on
-the Zoo's animals.  Eager herpetologists want to know if you have
-their favorite snake, so you should provide them with the ability
-to search for certain words and show all the documents that
-contain those words.  Searching is one of the most useful and
-common web activities.
-
-The *AnimalCatalog* ZCatalog you created can catalog all of the
-documents in your Zope site and let your users search for specific
-words.  To catalog your documents, go to the *AnimalCatalog*
-ZCatalog and click on the *Find Objects* tab.
-
-In this view, you tell the ZCatalog what kind of objects you are
-interested in.  You want to catalog all DTML Documents so select
-*DTML Document* from the *Find objects of type* multiple selection
-and click *Find and Catalog*.
-
-The ZCatalog will now start from the folder where it is located
-and search for all DTML Documents.  It will search the folder and
-then descend down into all of the sub-folders and their
-sub-folders.  For example, if your ZCatalog is located at
-'/Zoo/AnimalCatalog', then the '/Zoo' folder and all its
-subfolders will get searched. 
-
-If you have lots and lots of objects, this may take a long time
-to complete, so be patient.
-
-After a period of time, the ZCatalog will take you to the *Catalog*
-view automatically, with a status message telling you what it just
-did.
-
-Below the status information is a list of objects that are
-cataloged, they are all DTML Documents.  To confirm that these are
-the objects you are interested in, you can click on them to visit
-them.  Viewing an object in the catalog shows you what was indexed
-for the object, and what metadata items are stored for it.
-
-You have completed the first step of searching your objects,
-cataloging them into a ZCatalog. Now your documents are in the
-ZCatalog's database. Now you can move onto the fourth step,
-creating a web page and result form to query the ZCatalog.
-
-Search and Report Forms
-~~~~~~~~~~~~~~~~~~~~~~~
-
-To create search and report forms, make sure you are inside the
-*AnimalCatalog* ZCatalog and select *Z Search Interface* from the
-add list.  Select the *AnimalCatalog* ZCatalog as the searchable
-object, as shown in the figure below.
-
-.. figure:: ../Figures/creatingsearchinterface.png
-
-   Creating a search form for a ZCatalog
-
-Name the *Report Id* "SearchResults", the *Search Input Id*
-"SearchForm", select "Generate Page Templates" and click *Add*.
-This will create two new Page Templates in the *AnimalCatalog*
-ZCatalog named *SeachForm* and *SearchResults*.
-
-These objects are *contained in* the ZCatalog, but they are not
-*cataloged by* the ZCatalog.  The *AnimalCatalog* has only
-cataloged DTML Documents.  The search Form and Report templates
-are just a user interface to search the animal documents in the
-ZCatalog. You can verify this by noting that the search and
-report forms are not listed in the *Cataloged Objects* tab.
-
-To search the *AnimalCatalog* ZCatalog, select the *SearchForm*
-template and click on its *Test* tab.  
-
-By typing words into the *ZooTextIdx* form element you can
-search all of the documents cataloged by the *AnimalCatalog*
-ZCatalog.  For example, type in the word "Reptiles".  The
-*AnimalCatalog* ZCatalog will be searched and return a simple
-table of objects that have the word "Reptiles" in them.  The
-search results should include the carpet python.  You can also
-try specifying multiple search terms like "reptiles OR
-amphibians".  Search results for this query should include both
-the Chilean four-eyed Frog and the carpet python.
-Congratulations, you have successfully created a ZCatalog,
-cataloged content into it and searched it through the web.
-
-Configuring ZCatalogs
----------------------
-
-The ZCatalog is capable of much more powerful and complex searches
-than the one you just performed. Let's take a look at how the
-ZCatalog stores information. This will help you tailor your
-ZCatalogs to provide the sort of searching you want.
-
-Defining Indexes
-~~~~~~~~~~~~~~~~
-
-ZCatalogs store information about objects and their contents in
-fast databases called *indexes*.  Indexes can store and retrieve
-large volumes of information very quickly.  You can create
-different kinds of indexes that remember different kinds of
-information about your objects.  For example, you could have one
-index that remembers the text content of DTML Documents, and
-another index that remembers any objects that have a specific
-property.
-
-When you search a ZCatalog you are not searching through your
-objects one by one. That would take far too much time if you had
-a lot of objects.  Before you search a ZCatalog, it looks at
-your objects and remembers whatever you tell it to remember
-about them.  This process is called *indexing*.  From then on,
-you can search for certain criteria and the ZCatalog will return
-objects that match the criteria you provide.
-
-A good way to think of an index in a ZCatalog is just like an
-index in a book.  For example, in a book's index you can look up
-the word *Python*::
-
-  Python: 23, 67, 227
-
-The word *Python* appears on three pages.  Zope indexes work
-like this except that they map the search term, in this case the
-word *Python*, to a list of all the objects that contain it,
-instead of a list of pages in a book.
-
-In Zope 2.6, indexes can be added and removed from a ZCatalog
-using the "pluggable" index interface as shown in the figure below:
-
-.. figure:: ../Figures/managingindexes.png
-
-   Managing indexes
-
-Each index has a name, like *PrincipiaSearchSource*,
-and a type, like *ZCTextIndex*.
-
-When you catalog an object the ZCatalog uses each index to
-examine the object. The ZCatalog consults attributes and methods
-to find an object's value for each index. For example, in the
-case of the DTML Documents cataloged with a
-'PrincipiaSearchSource' index, the ZCatalog calls each document's
-'PrincipiaSearchSource' method and records the results in its
-'PrincipiaSearchSource' index. If the ZCatalog cannot find an
-attribute or method for an index, then it ignores it. In other
-words it's fine if an object does not support a given
-index. There are eight kinds of indexes that come standard with
-Zope 2.6, and others that can be added.  The standard eight are:
-
-ZCTextIndex
-  Searches text. Use this kind of index when you
-  want a full-text search.
-
-FieldIndex
-  Searches objects for specific values. Use this
-  kind of index when you want to search objects, numbers, or
-  specific strings.
-
-KeywordIndex
-  Searches collections of specific values. This
-  index is like a FieldIndex, but it allows you to search
-  collections rather than single values.
-
-PathIndex
-  Searches for all objects that contain certain URL
-  path elements.  For example, you could search for all the
-  objects whose paths begin with '/Zoo/Animals'.
-
-TopicIndex
-  Searches among FilteredSets;  each set contains
-  the document IDs of documents which match the set's filter
-  expression.  Use this kind of index to optimize
-  frequently-accessed searches. 
-
-DateIndex
-  A subclass of FieldIndex, optimized for date-time
-  values.  Use this index for any field known to be a date or a
-  date-time. 
-
-DateRangeIndex
-  Searches objects based on a pair of dates /
-  date-times.  Use this index to search for objects which are
-  "current" or "in effect" at a given time. 
-
-TextIndex
-  Old version of a full-text index.  Only provided
-  for backward compatibility, use ZCTextIndex instead.
-
-We'll examine these different indexes more closely later in the
-chapter. New indexes can be created from the *Indexes* view of a
-ZCatalog.  There, you can enter the *name* and select a *type*
-for your new index.  This creates a new empty index in the
-ZCatalog.  To populate this index with information, you need to
-go to the *Advanced* view and click the the *Update Catalog*
-button.  Recataloging your content may take a while if you have
-lots of cataloged objects.  For a ZCTextIndex, you will also
-need a *ZCTextIndex Lexicon* object in your ZCatalog - see below
-for details. 
-
-To remove an index from a ZCatalog, select the Indexes and click
-on the *Delete* button.  This will delete the index and all of
-its indexed content.  As usual, this operation is undoable.
-
-Defining Meta Data
-~~~~~~~~~~~~~~~~~~
-
-The ZCatalog can not only index information about your object,
-but it can also store information about your object in a
-*tabular database* called the *Metadata Table*.  The *Metadata
-Table* works similarly to a relational database table, it
-consists of one or more *columns* that define the *schema* of
-the table.  The table is filled with *rows* of information about
-cataloged objects.  These rows can contain information about
-cataloged objects that you want to store in the table. Your meta
-data columns don't need to match your ZCatalog's indexes. Indexes
-allow you to search; meta-data allows you to report search
-results.
-
-The Metadata Table is useful for generating search reports. It
-keeps track of information about objects that goes on your
-report forms.  For example, if you create a Metadata Table
-column called *Title*, then your report forms can use this
-information to show the titles of your objects that are returned
-in search results instead of requiring that you actually obtain
-the object to show its title.
-
-To add a new Metadata Table column, type in the name of the column
-on the *Metadata Table* view and click *Add*.  To remove a column
-from the Metadata Table, select the column check box and click on
-the *Delete* button.  This will delete the column and all of its
-content for each row.  As usual, this operation is undoable.  Next
-let's look more closely at how to search a ZCatalog.
-
-While metadata columns are useful, there are performance tradeoffs
-from using too many.  As more metadata columns are added, the
-catalog itself becomes larger (and slower), and getting the
-result objects becomes more memory- and performance-intensive.
-Therefore, you should choose metadata columns only for those
-fields that you'll want to show on common search results. 
-Consider carefully before adding a field that returns a large
-result (like the full text of a document) to metadata.
-
-Searching ZCatalogs
--------------------
-
-You can search a ZCatalog by passing it search terms. These search
-terms describe what you are looking for in one or more indexes. The
-ZCatalog can glean this information from the web request, or you
-can pass this information explicitly from DTML or Python. In
-response to a search request, a ZCatalog will return a list of
-records corresponding to the cataloged objects that match the
-search terms.
-
-Searching with Forms
-~~~~~~~~~~~~~~~~~~~~
-
-In this chapter you used the *Z Search Interface* to
-automatically build a Form/Action pair to query a ZCatalog (the
-Form/Action pattern is discussed in the chapter entitled
-`Advanced Page Templates <AdvZPT.html>`_ ).  The *Z Search
-Interface* builds a very simple form and a very simple
-report. These two methods are a good place to start
-understanding how ZCatalogs are queried and how you can
-customize and extend your search interface.
-
-Suppose you have a ZCatalog that holds news items named
-'NewsCatalog'.  Each news item has 'content', an 'author' and a
-'date' attribute.  Your ZCatalog has three indexes that
-correspond to these attributes, namely "contentTextIdx",
-"author" and "date".  The contents index is a ZCTextIndex, and
-the author and date indexes are a FieldIndex and a DateIndex.
-For the ZCTextIndex you will need a ZCTextIndexLexicon, and to
-display the search results in the 'Report' template, you should
-add the 'author', 'date' and 'absolute_url' attributes as
-Metadata.  Here is a search form that would allow you to query
-such a ZCatalog::
-
-  <html><body>
-  <form action="Report" method="get">
-  <h2 tal:content="template/title_or_id">Title</h2>
-  Enter query parameters:<br><table>
-  <tr><th>Author</th>
-  <td><input name="author" width=30 value=""></td></tr>
-  <tr><th>Content</th>
-  <td><input name="contentTextIdx" width=30 value=""></td></tr>
-  <tr><th>Date</th>
-  <td><input name="date" width=30 value=""></td></tr>
-  <tr><td colspan=2 align=center>
-  <input type="SUBMIT" name="SUBMIT" value="Submit Query">
-  </td></tr>
-  </table>
-  </form>
-  </body></html>
-
-This form consists of three input boxes named 'contentTextIdx',
-'author', and 'date'.  These names must match the names of the
-ZCatalog's indexes for the ZCatalog to find the search terms.
-Here is a report form that works with the search form::
-
-  <html>
-  <body tal:define="searchResults context/NewsCatalog;">
-  <table border>
-    <tr>
-      <th>Item no.</th>
-      <th>Author</th>
-      <th>Absolute url</th>
-      <th>Date</th>
-    </tr>
-    <div tal:repeat="item searchResults">
-    <tr>
-      <td>
-        <a href="link to object" tal:attributes="href item/absolute_url">
-          #<span tal:replace="repeat/item/number">
-            search item number goes here
-          </span>
-        </a>
-      </td>
-      <td><span tal:replace="item/author">author goes here</span></td>
-      <td><span tal:replace="item/date">date goes here</span></td>
-    </tr>
-    </div>
-  </table>
-  </body></html>
-
-There are a few things going on here which merit closer
-examination.  The heart of the whole thing is in the definition
-of the 'searchResults' variable::
-
-  <body tal:define="searchResults context/NewsCatalog;">
-
-This calls the 'NewsCatalog' ZCatalog.  Notice how the form
-parameters from the search form ( 'contentTextIdx' ,
-'author', 'date' ) are not mentioned here at all.
-Zope automatically makes sure that the query parameters from the
-search form are given to the ZCatalog.  All you have to do is
-make sure the report form calls the ZCatalog.  Zope locates the
-search terms in the web request and passes them to the ZCatalog.
-
-The ZCatalog returns a sequence of *Record Objects* (just like
-ZSQL Methods).  These record objects correspond to *search
-hits*, which are objects that match the search criteria you
-typed in. For a record to match a search, it must match all
-criteria for each specified index. So if you enter an author and
-some search terms for the contents, the ZCatalog will only return
-records that match both the author and the contents.
-
-ZSQL Record objects have an attribute for every column in the
-database table.  Record objects for ZCatalogs work very
-similarly, except that a ZCatalog Record object has an attribute
-for every column in the Metadata Table.  In fact, the purpose of
-the Metadata Table is to define the schema for the Record
-objects that ZCatalog queries return.
-
-Searching from Python
-~~~~~~~~~~~~~~~~~~~~~
-
-Page Templates make querying a ZCatalog from a form very simple.
-For the most part, Page Templates will automatically make sure
-your search parameters are passed properly to the ZCatalog.
-
-Sometimes though you may not want to search a ZCatalog from a web
-form; some other part of your application may want to query a
-ZCatalog.  For example, suppose you want to add a sidebar to the
-Zope Zoo that shows news items that only relate to the animals
-in the section of the site that you are currently looking at.
-As you've seen, the Zope Zoo site is built up from Folders that
-organize all the sections according to animal.  Each Folder's id
-is a name that specifies the group or animal the folder
-contains.  Suppose you want your sidebar to show you all the
-news items that contain the id of the current section.  Here is
-a Script called 'relevantSectionNews' that queries the news
-ZCatalog with the currentfolder's id::
-
-  ## Script (Python) "relevantSectionNews"
-  ##
-  """ Returns news relevant to the current folder's id """
-  id=context.getId()
-  return context.NewsCatalog({'contentTextIdx' : id})
-
-This script queries the 'NewsCatalog' by calling it like a
-method.  ZCatalogs expect a *mapping* as the first argument when
-they are called.  The argument maps the name of an index to the
-search terms you are looking for.  In this case, the
-'contentTextIdx' index will be queried for all news items that
-contain the name of the current Folder.  To use this in your
-sidebar place you could insert this snippet where appropriate in
-the main ZopeZoo Page Template::
-
-  ...
-  <ul>
-    <li tal:repeat="item context/relevantSectionNews">
-      <a href="news link" tal:attributes="href item/absolute_url">
-        <span tal:replace="item/title">news title</span>
-      </a>
-    </li>
-  </ul>
-  ...     
-
-This template assumes that you have defined 'absolute_url' and
-'title' as Metadata columns in the 'NewsCatalog'. Now, when you
-are in a particular section, the sidebar will show a simple list
-of links to news items that contain the id of the current animal
-section you are viewing.  (Note: in reality, you shouldn't use
-an index called 'absolute_url', but should rely instead on the
-getURL() method call below, as that works even in virtual hosting
-settings.
-
-Methods of Search Results
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The list of results you get for a catalog search is actually
-a list of Catalog Brain objects.  In addition to having an
-attribute for each item of your metadata, they also have
-several useful methods:
-
-has_key(key)
-  Returns true if the result object has a meta-data element 
-  named key.
-
-getPath()
-  Returns the physical path of the result object.  This can be
-  used to uniquely identify each object if some kind of
-  post-processing is performed.
-
-getURL()
-  Returns the URL of the result object.  You should use this
-  instead of creating a metadata element for 'absolute_url',
-  This can differ from getPath() if you are using virtual hosting.
-
-getObject()
-  Returns the actual zope object from the result object.  This
-  is useful if you want to examine or show an attribute or
-  method of the object that isn't in the metadata--once we have
-  the actual object, we can get any normal attribute or method
-  of it.  However, be careful not to use this instead of defining
-  metadata.  Metadata, being stored in the catalog, is 
-  pre-calculated and quickly accessed; getting the same type of
-  information by using 'getObject().attribute_name' requires
-  actually pulling your real object from the ZODB and may be
-  a good deal slower.  On the other hand, stuffing everything
-  you might ever need into metadata will slow down all querying
-  of your catalog, so you'll want to strike a balance. A good
-  idea is to list in metadata those things that would normally
-  appear on a tabular search results form; other things that
-  might be needed less commonly (and for fewer result objects
-  at a time) can be retried with getObject.
-
-getRID()
-  Returns the Catalog's record id for the result object.  This
-  is an implementation detail, and is not useful except for
-  advanced uses.
-
-Searching and Indexing Details
-------------------------------
-
-Earlier you saw that the ZCatalog includes eight types of
-indexes.  Let's examine these indexes more closely, and look
-at some of the additional available indexes, to understand
-what they are good for and how to search them.
-
-Searching ZCTextIndexes
-~~~~~~~~~~~~~~~~~~~~~~~
-
-A ZCTextIndex is used to index text.  After indexing, you can
-search the index for objects that contain certain words.
-ZCTextIndexes support a rich search grammar for doing more
-advanced searches than just looking for a word.
-
-Boolean expressions
-%%%%%%%%%%%%%%%%%%%
-
-  Search for Boolean expressions
-  like::
-
-    word1 AND word2
-
-  This will search for all objects that contain *both* "word1"
-  and "word2".  Valid Boolean operators include AND, OR, and
-  NOT.  A synonym for NOT is a leading hyphen::
-
-    word1 -word2
-
-  which would search for occurences of "word1" but would
-  exclude documents which contain "word2".  A sequence of words
-  without operators implies AND. A search for "carpet python
-  snakes" translates to "carpet AND python AND snakes".
-
-Parentheses
-%%%%%%%%%%%
-
-  Control search order with parenthetical 
-  expressions::
-
-    (word1 AND word2) OR word3)
-
-  This will return objects containing "word1" and "word2" *or*
-  just objects that contain the term "word3".
-
-Wild cards
-%%%%%%%%%%
-
-  Search for wild cards
-  like::
-
-    Z*
-
-  which returns all words that begin with "Z", 
-  or::
-
-     Zop?
-
-  which returns all words that begin with "Zop" and have one
-  more character - just like in a Un*x shell.  Note though that
-  wild cards cannot be at the beginning of a search phrase.
-  "?ope" is an illegal search term and will be ignored.
-
-Phrase search
-%%%%%%%%%%%%%
-
-  Double-quoted text implies phrase search, 
-  for example::
-
-    "carpet python" OR frogs 
-
-  will search for all occurences of the phrase "carpet python"
-  or of the word "frogs"
-
-All of these advanced features can be mixed together.  For
-example::
-
-  ((bob AND uncle) AND NOT Zoo*)
-
-will return all objects that contain the terms "bob" and "uncle"
-but will not include any objects that contain words that start
-with "Zoo" like "Zoologist", "Zoology", or "Zoo" itself.
-
-Similarly, a search 
-for::
-
-  snakes OR frogs -"carpet python"
-
-will return all objects which contain the word "snakes" or
-"frogs" but do not contain the phrase "carpet python".
-
-Querying a ZCTextIndex with these advanced features works just
-like querying it with the original simple features.  In the HTML
-search form for DTML Documents, for example, you could enter
-"Koala AND Lion" and get all documents about Koalas and Lions.
-Querying a ZCTextIndex from Python with advanced features works
-much the same; suppose you want to change your
-'relevantSectionNews' Script to not include any news items that
-contain the word "catastrophic"::
-
-  ## Script (Python) "relevantSectionNews"
-  ##
-  """ Returns relevant, non-catastropic news """
-  id=context.getId()
-  return context.NewsCatalog(
-           {'contentTextIdx' : id + ' -catastrophic'}
-          )
-
-ZCTextIndexes are very powerful.  When mixed with the Automatic
-Cataloging pattern described later in the chapter, they give you
-the ability to automatically full-text search all of your
-objects as you create and edit them.
-
-In addition, below, we'll talk about TextIndexNG indexes, which
-are a competing index type that can be added to Zope, and offers
-even more additional features for full-text indexing.
-
-Lexicons
-~~~~~~~~
-
-Lexicons are used by ZCTextIndexes.  Lexicons process and store
-the words from the text and help in processing queries.
-
-Lexicons can:
-
-Normalize Case
-  Often you want search terms to be case insensitive, eg. a search for
-  "python", "Python" and "pYTHON" should return the same results.  The
-  lexicons' *Case Normalizer* does exactly that.
-
-Remove stop words
-  Stop words are words that are very common in a given language and should
-  be removed from the index.  They would only cause bloat in the index and
-  add little information.  In addition, stop words, being common words,
-  would appear in almost every page, without this option turned on, a user
-  searching for "the python house" would get back practically every single
-  document on the site (since they would all likely contain "the"), taking
-  longer and adding no quality to their results.
-
-Split text into words
-  A splitter parses text into words.  Different texts have different needs
-  of word splitting - if you are going to process HTML documents, you might
-  want to use the HTML aware splitter which effectively removes HTML tags.
-  On the other hand, if you are going to index plain text documents *about*
-  HTML, you don't want to remove HTML tags - people might want to look them
-  up.  Also, an eg. chinese language document has a different concept of
-  words and you might want to use a different splitter. 
-
-The Lexicon uses a pipeline architecture. This makes it possible
-to mix and match pipeline components.  For instance, you could
-implement a different splitting strategy for your language and
-use this pipeline element in conjunction with the standard text
-processing elements.  Implementing a pipeline element is out of
-the scope of this book; for examples of implementing and
-registering a pipeline element see
-eg. 'Products.ZCTextIndex.Lexicon.py'.  A pipeline
-element should conform to the 'IPipelineElement' interface.
-
-To create a ZCTextIndex, you first have to create a Lexicon
-object.  Multiple ZCTextIndexes can share the same lexicon. 
-
-Searching Field Indexes
-~~~~~~~~~~~~~~~~~~~~~~~
-
-*FieldIndexes* have a different aims than ZCTextIndexes.  A ZCTextIndex
-will treat the value it finds in your object, for example the
-contents of a News Item, like text.  This means that it breaks
-the text up into words and indexes all the individual words.
-
-A FieldIndex does not break up the value it finds.  Instead, it
-indexes the entire value it finds.  This is very useful for
-tracking object attributes that contain simple values, such as
-numbers or short string identifiers.
-
-In the news item example, you created a FieldIndex
-'author'.  With the existing search form, this field is
-not very useful.  Unless you know exactly the name of the author
-you are looking for, you will not get any results.  It would be
-better to be able to select from a list of all the *unique*
-authors indexed by the author index.
-
-There is a special method on the ZCatalog that does exactly this
-called 'uniqueValuesFor'.  The 'uniqueValuesFor' method returns
-a list of unique values for a certain index.  Let's change your
-search form and replace the original 'author' input box
-with something a little more useful::
-
-  <html><body>
-  <form action="Report" method="get">
-  <h2 tal:content="template/title_or_id">Title</h2>
-  Enter query parameters:<br><table>
-  <tr><th>Author</th>
-  <td>
-    <select name="author:list" size="6" multiple>             
-      <option 
-        tal:repeat="item python:context.NewsCatalog.uniqueValuesFor('author')" 
-        tal:content="item"
-        value="opt value">
-      </option>
-    </select>
-  </td></tr>
-  <tr><th>Content</th>
-  <td><input name="content_index" width=30 value=""></td></tr>
-  <tr><th>Date</th>
-  <td><input name="date_index" width=30 value=""></td></tr>
-  <tr><td colspan=2 align=center>
-  <input type="SUBMIT" name="SUBMIT" value="Submit Query">
-  </td></tr>
-  </table>
-  </form>
-  </body></html>
-
-The new, important bit of code added to the search form 
-is::
-
-    <select name="author:list" size="6" multiple>             
-      <option 
-        tal:repeat="item python:context.NewsCatalog.uniqueValuesFor('author')" 
-        tal:content="item"
-        value="opt value">
-      </option>
-    </select>
-
-In this example, you are changing the form element 'author' from
-just a simple text box to an HTML multiple select box.  This box
-contains a unique list of all the authors that are indexed in
-the 'author' FieldIndex.  When the form gets submitted, the
-select box will contain the exact value of an authors name, and
-thus match against one or more of the news objects.  Your search
-form should look now like the figure below.
-
-.. figure:: ../Figures/uniqueauthorsform.png
-
-   Range searching and unique Authors
-
-Be careful if you catalog objects with many different values; you
-can easily end up with a form with a thousand items in the drop-down
-menu. Also, items must match *exactly*, so strings that differ
-in capitalization will be considered different.
-
-That's it.  You can continue to extend this search form using HTML
-form elements to be as complex as you'd like.  In the next section,
-we'll show you how to use the next kind of index, keyword indexes.
-
-Searching Keyword Indexes
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A *KeywordIndex* indexes a sequence of keywords for objects and
-can be queried for any objects that have one or more of those
-keywords.
-
-Suppose that you have a number of Image objects that have a
-'keywords' property. The 'keywords' property is a lines property
-that lists the relevant keywords for a given Image, for example,
-"Portraits", "19th Century", and "Women" for a picture of Queen
-Victoria.  
-
-The keywords provide a way of categorizing Images. Each Image can
-belong in one or more categories depending on its 'keywords'
-property. For example, the portrait of Queen Victoria belongs to
-three categories and can thus be found by searching for any of the
-three terms. 
-
-You can use a *Keyword* index to search the 'keywords' property. Define
-a *Keyword* index with the name 'keywords' on your ZCatalog. Then
-catalog your Images. Now you should be able to find all the Images
-that are portraits by creating a search form and searching for
-"Portraits" in the 'keywords' field. You can also find all pictures
-that represent 19th Century subjects by searching for "19th
-Century". 
-
-It's important to realize that the same Image can be in more
-than one category. This gives you much more flexibility in
-searching and categorizing your objects than you get with a
-FieldIndex. Using a FieldIndex your portrait of Queen Victoria
-can only be categorized one way.  Using a KeywordIndex it can be
-categorized a couple different ways.
-
-Often you will use a small list of terms with KeywordIndexes.
-In this case you may want to use the 'uniqueValuesFor' method to
-create a custom search form. For example here's a snippet of a
-Page Template that will create a multiple select box for all the
-values in the 'keywords' index::
-
-  <select name="keywords:list" multiple>
-    <option 
-      tal:repeat="item python:context.uniqueValuesFor('keywords')"
-      tal:content="item">
-        opt value goes here
-    </option>
-  </select>
-
-Using this search form you can provide users with a range of
-valid search terms. You can select as many keywords as you want and
-Zope will find all the Images that match one or more of your
-selected keywords. Not only can each object have several indexed
-terms, but you can provide several search terms and find all
-objects that have one or more of those values.
-
-Searching Path Indexes
-~~~~~~~~~~~~~~~~~~~~~~
-
-Path indexes allow you to search for objects based on their
-location in Zope. Suppose you have an object whose path is
-'/zoo/animals/Africa/tiger.doc'. You can find this object with
-the path queries: '/zoo', or '/zoo/animals', or
-'/zoo/animals/Africa'. In other words, a path index allows you
-to find objects within a given folder (and below).
-
-If you place related objects within the same folders, you can
-use path indexes to quickly locate these objects. For example::
-
-  <h2>Lizard Pictures</h2>
-  <p tal:repeat="item
-      python:context.AnimalCatalog(pathindex='/Zoo/Lizards', 
-      meta_type='Image')">
-    <a href="url" tal:attributes="href item/getURL" tal:content="item/title">
-      document title
-    </a>
-  </p>    
-
-This query searches a ZCatalog for all images that are located
-within the '/Zoo/Lizards' folder and below. It creates a link to
-each image.  To make this work, you will have to create a
-FieldIndex 'meta_type' and a Metadata entries for 'title'.
-
-Depending on how you choose to arrange objects in your site, you
-may find that a path indexes are more or less effective.  If you
-locate objects without regard to their subject (for example, if
-objects are mostly located in user "home" folders) then path
-indexes may be of limited value.  In these cases, key word and
-field indexes will be more useful.
-
-Searching DateIndexes
-~~~~~~~~~~~~~~~~~~~~~
-
-DateIndexes work like FieldIndexes, but are optimised for
-DateTime values.  To minimize resource usage, DateIndexes have a
-resolution of one minute, which is considerably lower than the
-resolution of DateTime values.
-
-DateIndexes are used just like FieldIndexes; below in the
-section on "Advanced Searching with Records" we present an
-example of searching them.
-
-Searching DateRangeIndexes
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-DateRangeIndexes are specialised for searching for ranges of
-DateTime values.  An example application would be NewsItems
-which have two DateTime attributes 'effective' and 'expiration',
-and which should only be published if the current date would
-fall somewhere in between these two date values.  Like
-DateIndexes, DateRangeIndexes have a resolution of one minute. 
-
-DateRangeIndexes are widely used in CMF and Plone, where
-content is compared to an effective date and an expiration
-date.
-
-DateRangeIndexes also allow one or both of the boundary dates of
-the indexed objects to be left open which greatly simplifies
-application logic when querying for "active" content where expiration
-and effective dates are optional.
-
-Searching TopicIndexes
-~~~~~~~~~~~~~~~~~~~~~~
-
-A TopicIndex is a container for so-called FilteredSets. A
-FilteredSet consists of an expression and a set of internal
-ZCatalog document identifiers that represent a pre-calculated
-result list for performance reasons. Instead of executing the
-same query on a ZCatalog multiple times it is much faster to use
-a TopicIndex instead.
-
-TopicIndexes are also useful for indexing boolean attributes or
-attributes where only one value is queried for. They can do this more
-efficiently then a field index.
-
-Building up FilteredSets happens on the fly when objects are
-cataloged and uncatalogued. Every indexed object is evaluated
-against the expressions of every FilteredSet. An object is added
-to a FilteredSet if the expression with the object evaluates to
-True. Uncatalogued objects are removed from the FilteredSet.
-
-A built-in type of FilteredSet is the PythonFilteredSet - it
-would be possible to construct custom types though.
-
-A PythonFilteredSet evaluates using the eval() function inside the
-context of the FilteredSet class. The object to be indexes must
-be referenced inside the expression using "o.".  Below are some
-examples of expressions.
-
-This would index all DTML 
-Methods::
-
-  o.meta_type=='DTML Method'
-
-This would index all folderish objects which have a non-empty
-title::
-
-  o.isPrincipiaFolderish and o.title
-
-Querying of TopicIndexes is done much in the same way as with
-other Indexes.  Eg., if we named the last FilteredSet above
-'folders_with_titles', we could query our TopicIndex with a
-Python snippet like::
-
-  zcat = context.AnimalCatalog
-  results = zcat(topicindex='folders_with_titles')
-
-Provided our 'AnimalCatalog' contains a TopicIndex 'topicindex',
-this would return all folderish objects in 'AnimalCatalog' which
-had a non-empty title.  
-
-TopicIndexes also support the 'operator' parameter with Records.
-More on Records below.
-
-Advanced Searching with Records
--------------------------------
-
-A more advanced feature is the ability to query indexes more
-precisely using record objects.  Record objects contain
-information about how to query an index.  Records are Python
-objects with attributes, or mappings.  Different indexes support
-different record attributes.
-
-Note that you don't have to use record-style queries unless you
-need the features introduced by them: you can continue to use
-traditional queries, as demonstrated above.
-
-A record style query involves passing a record (or dictionary)
-to the catalog instead of a simple query string.
-
-Keyword Index Record Attributes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-'query'
- Either a sequence of words or a single word.
- (mandatory)
-
-'operator'
- Specifies whether all keywords or only one need
- to match. Allowed values: 'and', 'or'. (optional, default:
- 'or')
-
-For example::
-
-  # big or shiny
-  results=ZCatalog(categories=['big, 'shiny'])
-
-  # big and shiny
-  results=ZCatalog(categories={'query':['big','shiny'], 
-                                       'operator':'and'})
-
-The second query matches objects that have both the keywords
-"big" and "shiny". Without using the record syntax you can
-only match objects that are big or shiny.
-
-FieldIndex Record Attributes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-'query'
-  Either a sequence of objects or a single value to be
-  passed as query to the index (mandatory)
-
-'range'
-  Defines a range search on a Field Index (optional, default: not set).
-
-  Allowed values:
-
-    'min'
-      Searches for all objects with values larger than
-      the minimum of the values passed in the 'query' parameter.
-
-    'max'
-      Searches for all objects with values smaller than
-      the maximum of the values passed in the 'query' parameter.
-
-    'minmax'
-      Searches for all objects with values smaller than the maximum of the
-      values passed in the 'query' parameter and larger than the minimum of
-      the values passwd in the 'query' parameter. 
-
-For example, here is a PythonScript snippet using a range 
-search::
-
-  # animals with population count greater than 5
-  zcat = context.AnimalCatalog
-  results=zcat(population_count={
-                   'query' : 5,
-                   'range': 'min'}
-              )
-
-This query matches all objects in the AnimalCatalog which have a
-population count greater than 5 (provided that there is a
-FieldIndex 'population_count' and an attribute 'population_count'
-present).
-
-Or::
-
-  # animals with population count between 5 and 10
-  zcat = context.AnimalCatalog
-  results=zcat(population_count={
-                   'query': [ 5, 10 ],
-                   'range': 'minmax'}
-              )
-
-This query mathches all animals with population count
-between 5 and 10 (provided that the same FieldIndex
-'population_count' indexing the attribute 'population_count'.)
-
-Path Index Record Attributes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-'query'
-  Path to search for either as a string (e.g. "/Zoo/Birds") or list (e.g.
-  ["Zoo", "Birds"]). (mandatory)
-
-'level'
-  The path level to begin searching at.  Level defaults to 0, which means
-  searching from the root.  A level of -1 means start from anywhere in the
-  path. 
-
-Suppose you have a collection of objects with these paths:
-
-- '/aa/bb/aa'
-
-- '/aa/bb/bb'
-
-- '/aa/bb/cc'
-
-- '/bb/bb/aa'
-
-- '/bb/bb/bb'
-
-- '/bb/bb/cc'
-
-- '/cc/bb/aa'
-
-- '/cc/bb/bb'
-
-- '/cc/bb/cc'
-
-Here are some examples queries and their results to show how the
-'level' attribute works:
-
-'query="/aa/bb", level=0'
-  This gives the same behaviour as our previous examples, ie. searching
-  absolute from the root, and results in:
-
-  - '/aa/bb/aa'
-
-  - '/aa/bb/bb'
-
-  - '/aa/bb/cc'
-
-'query="/bb/bb", level=0'
-  Again, this returns the default: 
-
-  - '/bb/bb/aa'
-
-  - '/bb/bb/bb'
-
-  - '/bb/bb/cc'
-
-'query="/bb/bb", level=1'
-  This searches for all objects which have '/bb/bb' one level down from
-  the root:
-
-  - '/aa/bb/bb'
-
-  - '/bb/bb/bb'
-
-  - '/cc/bb/bb'
-
-'query="/bb/bb", level=-1'
-  Gives all objects which have '/bb/bb' anywhere in their path:
-
-  - '/aa/bb/bb'
-
-  - '/bb/bb/aa'
-
-  - '/bb/bb/bb'
-
-  - '/bb/bb/cc'
-
-  - '/cc/bb/bb'
-
-'query="/xx", level=-1'
-  Returns None
-
-You can use the level attribute to flexibly search different
-parts of the path.
-
-As of Zope 2.4.1, you can also include level information in a
-search without using a record. Simply use a tuple containing the
-query and the level. Here's an example tuple: '("/aa/bb", 1)'.
-
-DateIndex Record Attributes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The supported Record Attributes are the same as those of the
-FieldIndex:
-
-'query'
-  Either a sequence of objects or a single value to be
-  passed as query to the index (mandatory)
-
-'range'
-  Defines a range search on a DateIndex (optional,
-  default: not set).
-
-  Allowed values:
-
-    'min'
-      Searches for all objects with values larger than
-      the minimum of the values passed in the 'query' parameter.
-
-    'max'
-      Searches for all objects with values smaller than
-      the maximum of the values passed in the 'query' parameter.
-
-    'minmax'
-      Searches for all objects with values smaller
-      than the maximum of the values passed in the 'query'
-      parameter and larger than the minimum of the values passwd
-      in the 'query' parameter. 
-
-As an example, we go back to the NewsItems we created in the
-Section *Searching with Forms*.  For this example, we created
-news items with attributes 'content', 'author', and 'date'.
-Additionally, we created a search form and a report template for
-viewing search results.  
-
-Searching for dates of NewsItems was not very comfortable
-though - we had to type in exact dates to match a document.
-
-With a 'range' query we are now able to search for ranges of
-dates.  Take a look at this PythonScript snippet::
-
-  # return NewsItems newer than a week
-  zcat = context.NewsCatalog
-  results = zcat( date={'query' : context.ZopeTime() - 7,
-                        'range' : 'min'
-                })
-
-DateRangeIndex Record Attributes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-DateRangeIndexes only support the 'query' attribute on Record
-objects.  The 'query' attribute results in the same
-functionality as querying directly; returning matches where
-the date supplied to the query falls between the start and
-end dates from the indexed object.
-
-TopicIndex Record Attributes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Like KeywordIndexes, TopicIndexes support the 'operator'
-attribute:
-
-'operator'
-  Specifies whether all FieldSets or only one need to match.
-  Allowed values: 'and', 'or'. (optional, default: 'or')
-
-ZCTextIndex Record Attributes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Because ZCTextIndex operators are embedded in the query string,
-there are no additional Record Attributes for ZCTextIndexes.
-
-Creating Records in HTML
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can also perform record queries using HTML forms. Here's an
-example showing how to create a search form using records::
-
-  <form action="Report" method="get">
-  <table>
-  <tr><th>Search Terms (must match all terms)</th>
-      <td><input name="content.query:record" width=30 value=""></td></tr>
-      <input type="hidden" name="content.operator:record" value="and">
-  <tr><td colspan=2 align=center>
-  <input type="SUBMIT" value="Submit Query">
-  </td></tr>
-  </table>
-  </form>
-
-For more information on creating records in HTML see the section
-"Passing Parameters to Scripts" in Chapter 14, Advanced Zope
-Scripting.
-
-Automatic Cataloging
---------------------
-
-Automatic Cataloging is an advanced ZCatalog usage pattern that
-keeps objects up to date as they are changed. It requires that as
-objects are created, changed, and destroyed, they are
-automatically tracked by a ZCatalog. This usually involves the
-objects notifying the ZCatalog when they are created, changed, or
-deleted.
-
-This usage pattern has a number of advantages in comparison to
-mass cataloging. Mass cataloging is simple but has drawbacks.  The
-total amount of content you can index in one transaction is
-equivalent to the amount of free virtual memory available to the
-Zope process, plus the amount of temporary storage the system has.
-In other words, the more content you want to index all at once,
-the better your computer hardware has to be.  Mass cataloging
-works well for indexing up to a few thousand objects, but beyond
-that automatic indexing works much better.
-
-If you can trade off memory for time, you can enable
-'Subtransactions' in the 'Advanced' tab of the catalog. This
-commits the work in chunks, reducing memory requirements, but
-taking longer. It is a good solution for mass cataloging with a
-very large number of records.
-
-Another major advantage of automatic cataloging is that it can
-handle objects that change. As objects evolve and change, the
-index information is always current, even for rapidly changing
-information sources like message boards.
-
-On the other hand, cataloging a complex object when it changes
-(especially if the catalog index attempts to translate the
-information, as TextIndexNG, described below, can do with
-PDF files or Microsoft Office files). Some sites may benefit
-from mass cataloging, and having a cron job or other scheduled
-job initiate the mass cataloging every night.
-
-In standard (non-CMF, non-Plone) Zope, none of the built-in
-object types attempt to automatically catalog themselves. In
-CMF and Plone, the "contentish" object (Documents, News Item,
-Event, etc.) all use automatic cataloging to add themselves
-to the standard CMF catalog, 'portal_catalog'.  The CMF
-and especially Plone offer many advantages; if you're interested
-in building a content-oriented site, you should consider
-these technologies.
-
-Advanced Catalog Topics
------------------------
-
-Sorting
-~~~~~~~
-
-When you execute a ZCatalog call, your result set may or may not
-be returned in a particular order:
-
-- If your query contains no text index fields, your results will
-  not be sorted in any particular order.  For example, with a
-  query based off a KeywordIndex, or query based off both
-  a KeywordIndex and a DateIndex, you will get a indeterminate
-  ordering.
-
-- For results that include a text index, your results will be
-  returned in order of revelance of the text search.  That is,
-  the result set will be sorted based how often
-  search words appear in the indexes.  A search for the word
-  'frog' against a text index will give priority toward an object
-  that uses that word many times compared with
-  an object that uses that fewer.  This is
-  a simplified version of the way that many web search engines
-  work: the more "relevant" your keywords are to an item, the
-  higher its ordering in the results. In particular, with
-  the ZCTextIndex, you have a choice between two algorithms
-  for how to weight the sorting:
-
-  - Okapi: is the best general choice. It does very well
-    when comparing an ordinary "human query" against a longer
-    text field. For example, querying a long description field
-    for a short query like 'indoor OR mammal' would work very
-    well.
-
-  - Cosine: is better suited for when the length of the
-    query comes close to matching the length of the field
-    itself.
-
-You, of course, may want to force a particular order onto your
-results.  You can do this after you get a result set using
-normal Python syntax::
-
-  # get ordered results from search
-  zcat=context.AnimalCatalog
-  results=zcat({'title':'frog'})
-  results=[(row.title, row) for row in results]
-  results.sort()
-
-This can be, however, very inefficient.
-
-When results are returned by the ZCatalog, they are in a special
-form called a `LazyResults` set.  This means that Zope hasn't
-gone to the trouble of actually creating the entire list, but
-has just sketched out the list and will fill it in at the exact
-point that you ask for each item.  This is helpful, since it lets
-you query the catalog for a result set with 10,000 items without
-Zope having to really construct a 10,000 item long list of results.
-However, when we try to sort this, Zope will have to actually
-create this list since it can't rely on it's lazy, just-in-time
-method.
-
-Normally, you'll only show the first 20 or 50 or so of a result
-set, so sorting 10,000 items just to show the first 20 is a waste
-of time and memory.  Instead, we can ask the catalog to do the
-sorting for us, saving both time and space.
-
-To do this, we'll pass along several additional keywords in our
-search method call or query:
-
-sort_on
-  The field name to sort the results on
-
-sort_order
-  'ascending' or 'descending', with the default
-    being 'ascending. Note that you can also use 'reverse'
-    as a synonym for 'descending'
-
-sort_limit
-  Since you're likely to only want to use the
-    first 20 or 50 or so items, we can give a hint to the 
-    ZCatalog not to bother to sort beyond this by passing along
-    a 'sort_limit' parameter, which is the number of records
-    to sort.
-
-For example, assuming we have a 'latin_name' FieldIndex on our
-animals, we can sort them by name in a PythonScript with::
-
-  zcat=context.AnimalCatalog
-  zcat({'sort_on':'latin_name'})
-
-or::
-
-  zcat=context.AnimalCatalog
-  zcat({'sort_on':'latin_name', 'sort_order':'descending'})
-
-or, if we know we'll only want to show the first 20 records::
-
-  zcat=context.AnimalCatalog
-  zcat({'sort_on':'latin_name',
-        'sort_order':'descending',
-        'sort_limit':20})
-
-or, combining this with a query restriction::
-
-  zcat=context.AnimalCatalog
-  zcat({'title':'frog',
-        'sort_on':'latin_name',
-        'sort_order':'descending',
-        'sort_limit':20})
-
-This gives us all records with the 'title' "frog", sorted
-by 'latin_name', and doesn't bother to sort after the first
-20 records.
-
-Note that using 'sort_limit' does not guarantee that we'll get
-exactly that number of records--we may get fewer if they're
-aren't that many matching or query, and we may get more. 
-'sort_limit' is merely a request for optimization. To
-ensure that we get no more than 20 records, we'll want to 
-truncate our result set::
-
-  zcat=context.AnimalCatalog
-  zcat({'sort_on':'latin_name',
-        'sort_order':'descending',
-        'sort_limit':20})[:20]
-
-Unsortable Fields
-%%%%%%%%%%%%%%%%%
-
-In order to sort on a index, we have to actually keep the
-full attribute or method value in that index.  For many
-index types, such as DateIndex or FieldIndex, this is
-normally done.  However, for text indexes, such as
-ZCTextIndex, TextIndex (deprecated), and TextIndexNG
-(described below), the index doesn't keep the actual
-attribute or method results in the index.  Instead, it
-cleans up the input (often removing "stop words",
-normalizing input, lowercasing it, removing duplicates,
-etc., depending on the options chosen.  So a term paper
-with an attribute value of::
-
-  "A Critique of 'Tora! Tora! Tora!'"
-
-could actually be indexed as :
-
-  ( 'critique', 'tora' )
-
-once the common stop words ("a", "of") are removed,
-it is lowercased and de-deduplicated.  (In reality,
-the indexed information is much richer, as it keeps
-track of things like how often words appear, and which
-words appear earlier in the the stream, but this gives
-you an idea of what is stored.)
-
-This is a necessary and positive step to make the index
-use less storage and less memory, and increases search
-results, as your site user doesn't have to worry about
-getting incidental words ("the", "a", etc.) correct,
-nor about capitalization, etc.
-
-**Note:** As we'll see, TextIndexNG indexes can even
-do advanced tricks, such as normalizing a word and
-stemming it, so that a search for "vehicles" could
-find "vehicle" or even "car".
-
-However, this process means that the index no longer knows
-the actual value, and, therefore, can't sort on it.
-Due to this, it is not possible to use the 'sort_on'
-feature with text indexes types.
-
-To work around this, you can either sort the results of
-the query using the normal python 'sort()' feature
-(shown above), or you can create an additional non-text
-index on the field, described below, in the section
-'Indexing a Field with Two Index Types'.
-
-Similarly, the API call 'uniqueValuesFor', described above,
-cannot be used on text-type indexes, since the exact
-values are not kept.
-
-Searching in More Than One Index Using "OR"
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-As mentioned, if you search in more than one index,
-you must meet your criteria for each index you search
-in, i.e., there is an implied 'AND' between each of the
-searches::
-
-  # find sunset art by Van Gogh
-  zcat=context.ArtCatalog
-  results=zcat({'keyword':'sunsets', 'artist':'Van Gogh'})
-
-This query finds all sunset art by Van Gogh: both of
-these conditions must be true.
-
-There is no way to directly search in more than one
-index without this 'AND' condition; instead, you can
-perform two catalog searches and concatenate their
-results. For example::
-
-  # find sunset art OR art by Van Gogh
-  zcat=context.ArtCatalog
-  results=zcat({'keyword':'sunsets'}) + \
-          zcat({'artist':'Van Gogh'})
-
-This method, however, does not remove duplicates, so
-a painting of a sunset by VanGogh would appear twice.
-
-For alternate strategies about searching in two places,
-see 'PrincipiaSearchSource' and 'FieldedTextIndex', below,
-both of which can be used as possible workarounds.
-
-Indexing a Field With Two Index Types
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Since the different indexes act differently, it can be advantageous
-to have the same attribute indexed by more than one index.  For
-example, our animals have a 'latin_name' attribute that gives their
-formal genus/species latin name.  A user should be able to search
-that trying to match a name *exactly*, and we should be able to
-sort results based on that, both of which suggest a FieldIndex.  In
-addition, though, users may want to search that like a text field,
-where they can match parts of words, in which case we would a
-ZCTextIndex (or TextIndexNG, described below).
-
-In a case like this, a good strategy is to create one index for the
-FieldIndex on 'latin_name'.  Let's call that index 'latin_name'.
-Then, you can create a ZCTextIndex that uses a new feature: the
-ability to have the indexed attribute be different than the index
-name itself.
-
-When you create the second index, the ZCTextIndex, you can give it
-the Id 'latin_name_text', and have the 'Indexed attributes' field
-be 'latin_name'.  Now, when we catalog our animals, their
-'latin_name' attribute is indexed in two ways: once, as a
-FieldIndex, that we can sort against and match exactly, and once as
-a ZCTextIndex, that we can search like a text field with full text
-search.
-
-The second index has a different name, so when make our catalog
-call, we'll need to be sure to use that name if we want to search
-it like a text field::
-
-  # search latin_name
-  zcat=context.AnimalCatalog
-  exact_results=zcat({'latin_name':'homo sapien'})
-  fuzzy=zcat({'latin_name_text':'sap*'})
-
-Note that a good strategy is to have the search be against the
-ZCTextIndex, but sort it by the FieldIndex::
-
-  # free text search, sorted
-  zcat=context.AnimalCatalog
-  results=zcat({'latin_name_text':'sap*',
-                'sort_on':'latin_name'})
-
-PrincipiaSearchSource
-~~~~~~~~~~~~~~~~~~~~~
-
-You can choose to create indexes on any attribute or method that
-you would find useful to search on; however, one that is
-generally helpful is 'PrincipiaSearchSource'.  Several of the
-built-in Zope objects, such as DTMLDocuments, and many add-on
-objects to Zope have a 'PrincipiaSearchSource' attribute or
-method that returns a value that is meant to be used for general
-purpose searching.  Traditionally, 'PrincipiaSearchSource'
-would include the text in an object's title, it's body, and
-anywhere else you'd want to be able to search. 
-
-For example, if you downloaded a zope product that managed
-our zoo, and it had an Animal type that you could add to your
-site, this animal type would probably expose a 
-PrincipiaSearchSource that looked something like this::
-
-  def PrincipiaSearchSource(self):
-    "used for general searching for animal"
-    return self.title + ' ' + self.latin_name + ' ' \
-         + self.description + ' ' + self.environment
-
-So that, if you create a 'PrincipiaSearchSource' index and
-search again that, you can find this animal by using words
-that are in it's 'title', 'latin_name', 'description', or
-'environment', without having to worry about which field,
-exactly, they're in.  This is similar to searching with a
-web search engine, in that you use can use a single text string
-to find the "right" information, without needing to know about
-the type of object you're looking for.  It is especially
-helpful in allowing you to create a site-wide search: searching
-animals specifically by their 'latin_name' or 'environment'
-might be useful for a biologist in the right section of your
-site, but for a general purpose visitor, they might like
-to search using the phrase "jungle" and find results without
-having to know to search for that in the 'environment' field
-of a search form.
-
-If you create custom types by using more advanced techniques described
-elsewhere, you should create a PrincipiaSearchSource method that returns
-appropriate object-wide text searching capabilities.
-
-ZCatalogs and CMF/Plone
-~~~~~~~~~~~~~~~~~~~~~~~
-
-The CMF was built from the ground up to understand the
-difference between things that are "content", such as a news item
-or press release, and those things that are not, such as
-a DTMLMethod used to show a press release, or a ZCatalog
-object.  In addition, the CMF includes several stock items
-that are intended to be used for content, including:
-Document, Event, NewsItem, and others.  These content items
-are already set up for autocataloging, so that any changes
-made will appear in the catalog.
-
-In non-CMF Zope, the traditional name for a general-purpose
-catalog is 'Catalog' (though you can always create your own
-catalog with any id you want; we've used the example
-'AnimalCatalog' in this chapter for a special-purpose catalog
-for searching animal-specific info in our zoo.)  Even though
-'Catalog' is the traditional name, Zope does not come with
-such a catalog in the ZODB already, you have to create it.
-
-In CMF (and Plone, an out-of-the-box portal system built
-on top of the CMF), there is always a catalog created, called
-'portal_catalog', at the root of the CMF site.  All of the
-built-in content objects (and almost every add-on content
-object for the CMF/Plone) are set to autocatalog to this
-'portal_catalog'.  This is required, since many of the features
-of the CMF and Plone, such as listing current content, finding
-content of correct types, etc., rely on the 'portal_catalog'
-and the searching techniques shown here to function.
-
-In CMF and Plone, the index name 'PrincipiaSearchSource' is
-not traditionally used.  Instead, an index is created called
-'SearchableText', and used in the same manner as
-'PrincipiaSearchSource'.  All of the standard contentish
-objects have a 'SearchableText' method that returns things
-like title, description, body, etc., so that they can be
-general-text searched.
-
-Add-On Index Types
-------------------
-
-TextIndexNG
-~~~~~~~~~~~
-
-TextIndexNG is a new text index that competes with ZCTextIndex.
-Unlike ZCTextIndex, TextIndexNG is an add-on product that must be
-separately installed. It offers a large number of features:
-
-- Document Converters 
-
-  If your attribute value isn't plain text, TextIndexNG can convert
-  it to text to index it.  This will allow you to store, for
-  instance, a PDF file in Zope
-  and be able to search the text of that PDF file.  Current
-  formats it can convert are: HTML, PDF, Postscript, Word,
-  Powerpoint, and OpenOffice.
-
-- Stemmer Support
-
-  Reduces words to a stem (removes verb endings and
-  plural-endings), so a user can search for "car" and get "car"
-  and "cars", without having to try the search twice.  It
-  knows how to perform stemming in 13 different languages.
-
-- Similarity Search
-
-  Can find words that are "similar" to your words, based on
-  the Levenshtein algorithm.  Essentially, this measures the
-  distance between two terms using indicators such as how
-  many letters differ from one to another.
-
-- Near Search
-
-  Can look for words that are near each other.  For example,
-  a search for "Zope near Book" would find results where
-  these words were close to each other in the document.
-
-- Customizable Parsers
-
-  Rather than having only one way to express a query, TextIndexNG
-  uses a "pluggable" architecture where a Python programmers can
-  create new parsers.  For example, to find a document that
-  includes the word "snake" but not the word "python", you'd
-  search for "snake andnot python" in the default parser.
-  However, given your users expectations (and native language),
-  they might prefer to say "snake and not python" or "snake
-  -python" or such.  TextIndexNG comes with three different
-  parsers: a rich, default one, a simple one that is suitable for
-  more general serarching, and a German one that uses
-  german-language words ("nicht" for "not", for example).
-  Although writing a new parser is an advanced task, it would be
-  possible for you to do so if you wanted to let users express
-  the question in a different form.
-
-- Stop Words
-
-  You can customize the list of "stop words" that are too common
-  to both indexing or search for.
-
-- Wilcard Search
-
-  You can use a "wildcard" to search for part of a word, such as
-  "doc*" to find all words starting with "doc".  Unlike
-  ZCTextIndex, you can also use wildcards are the start of a
-  word, such as "\*doc" to find all words ending with "doc", as
-  well.
-
-- Normalization Support
-
-  Removing accented characters so that users can search for an
-  accented word without getting the accents exactly right.
-
-- Auto-Expansion
-
-  This optional feature allows you to get better search results
-  when some of the query terms could not be found.  In this
-  case, it uses a similarity matching to "expand" the query
-  term to find more matches.
-
-- Ranking Support
-
-  Sorting of results based on their word frequencies,
-  similar to the sorting capabilities of ZCTextIndex.
-
-TextIndexNG is an excellent replacement for ZCTextIndex,
-especially if you have non-English language documents or expect to
-have users that will want to use a rich query syntax.
-
-Full information on TextIndexNG is available at
-http://pypi.python.org/pypi/textindexng.
-
-FieldedTextIndex
-~~~~~~~~~~~~~~~~
-
-FieldTextIndex is a new index type that is not (yet) a standard
-part of Zope, but is a separate product that can be installed
-and used with a standard catalog.
-
-Often, a site will have a combined field (normally
-'PrincipiaSearchSource' or 'SearchableText', as described above)
-for site-wide searching, and individual fields for more
-content-aware searching, such as the indexes on 'latin_name',
-'environment', etc.
-
-Since it's slows down performance to concatenate catalog result
-sets directly, the best strategy for searching across many fields
-is often use the 'PrincipiaSearchSource'/'SearchableText'
-strategy of a single text index.  However, this can be *too*
-limiting, as sometimes users want to search in several fields at
-once, rather than in all.
-
-FieldedTextIndex solves these problems by extending the standard
-ZCTextIndex so that it can receive and index the textual data of an
-object's field attributes as a mapping of field names to field
-text.  The index itself performs the aggregation of the fielded
-data and allows queries to be performed across all fields (like a
-standard text index) or any subset of the fields which have been
-encountered in the objects indexed.
-
-In other words, a normal 'PrincipiaSearchSource' method would
-look something like this::
-
-  # concatenate all fields user might want to search
-  def PrincipiaSearchSource(self):
-    return self.title + ' ' + self.description \
-         + self.latin_name + ' ' + self.environment
-
-However, you have to search this all at once--you can't opt to
-search just 'title' and 'latin_name', unless you created separate
-indexes for these fields.  Creating separate indexes for these
-fields is a waste of space and memory, though, as the same
-information is indexed several times.
-
-With FieldedTextIndex, your 'PrincipiaSearchSource' method would
-look like this::
-
-  # return all fields user might want to search
-  def PrincipiaSearchSource(self):
-    return { 'title':self.title,
-             'description':self.description,
-             'latin_name':self.latin_name,
-             'environment':self.environment }
-
-This index can be searched with the normal methods::
-
-  # search like a normal index
-  zcat=context.AnimalCatalog
-  results=zcat({'PrincipiaSearchSource':'jungle'})
-
-In addition, it can be searched indicating which fields you want
-to search::
-
-  # search only specific fields
-  zcat=context.AnimalCatalog
-  results=zcat(
-    {'PrincipiaSearchSource':'query':'jungle',
-                             'fields':['title','latin_name']})
-
-In this second example, only 'title' and 'latin_name' will be
-searched.
-
-In addition, FieldedTextIndexes support *weighing*, so that
-different fields "weigh" more in the query weigh, and a match in
-that field influences the results so that it appears earlier in the
-result list.  For example, in our zoo, matching part of an animals
-'latin_name' should count very highly, matching part of the 
-'title' should count highly, and matching part of the description
-should count less so.
-
-We can specify the weighing like this::
-
-  # search with weighing
-  zcat=context.AnimalCatalog
-  results=zcat(
-    {'PrincipiaSearchSource':'query':'jungle',
-                             'field_weights':{
-                                     'latin_name':3,
-                                     'title':2,
-                                     'description':1 }})
-
-This is a *very* powerful feature for building a comprehensive
-search strategy for a site, since it lets us control the results to
-better give the user what they probaby want, rather than returning
-documents based solely on how many times their search word appears.
-
-The examples given here are for searching a FieldedIndex using
-PythonScripts, however they can be searched directly from the
-REQUEST in a form like other fields.
-
-Since a FieldedTextIndex can act just like a normal ZCTextIndex if
-queried with just a search string, yet offer additional features
-above and beyond the normal ZCTextIndex, it's a good idea to use
-this for any text index where you'd concatenate more than one
-attribute or method result together, such as for 'SearchableText'
-or 'PrincipiaSearchSource'.
-
-FieldedTextIndex can be downloaded at
-http://zope.org/Members/Caseman/FieldedTextIndex.
-Full documentation on how to create this type of index, and further
-information on how to search it, including how to search it from
-web forms, is available in the README file that comes with this
-product.
-
-Conclusion
-----------
-
-The cataloging features of ZCatalog allow you to search your objects
-for certain attributes very quickly.  This can be very useful for sites
-with lots of content that many people need to be able to search in an
-efficient manner.
-
-Searching the ZCatalog works a lot like searching a relational
-database, except that the searching is more object-oriented.  Not all
-data models are object-oriented however, so in some cases you will want
-to use the ZCatalog, but in other cases you may want to use a
-relational database.  The next chapter goes into more details about how
-Zope works with relational databases, and how you can use relational
-data as objects in Zope.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/Security.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/Security.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/Security.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,1365 +0,0 @@
-Users and Security
-==================
-
-Introduction to Zope Security
------------------------------
-
-Zope is a multi-user system. However, instead of relying upon the
-user accounts provided by the operating system under which it runs,
-Zope maintains one or more of its own user databases.  It is not
-necessary to create a user account on the operating system under
-which Zope runs in order to grant someone a user account which they
-may use to access your Zope application or manage Zope via its
-management interface.
-
-It is important to note that Zope users do not have any of the
-privileges of a "normal" user on your computer's operating system.
-For instance, they do not possess the privilege to change arbitrary
-files on your computer's filesystem.  Typically, a Zope user may
-influence the content of databases that are connected to Zope may
-execute scripts (or other "logic" objects) based on Zope's
-security-restricted execution environment.  It is also possible to
-allow users to create their own scripts and content "through the
-web" by giving them access to the Zope Management Interface.
-However, you can restrict the capability of a user or a class of
-users to whatever suits your goals.  The important concept to absorb
-is that Zope's security is entirely divorced from the operating
-system upon which it runs.
-
-In Zope, users have only the capabilities granted to them by a Zope
-*security policy*.  As the administrator of a Zope system, you have
-the power to change your Zope system's security policies to whatever
-suits your business requirements.
-
-Furthermore, using security policies you can provide the capability
-to "safely" *delegate* capabilities to users defined within
-different parts of a Zope site.  "Safe delegation" is one of the
-important and differentiating features of Zope.  It is possible to
-grant users the capability in a Zope site to administer users and
-create scripts and content via the Zope Management Interface.  This
-is called "safe" delegation because it is relatively "safe" to grant
-users these kinds of capabilities within a particular portion of a
-Zope site, as it does not compromise operating system security nor
-Zope security in other portions of the site.  Caveats to safe
-delegation pertain to denial of service and resource exhaustion (it
-is not possible to control a user's resource consumption with any
-true measure of success within Zope), but it is possible to delegate
-these capabilities to "semi-trusted" users in order to decentralize
-control of a website, allowing it to grow faster and require less
-oversight from a central source.
-
-In this chapter we will look more closely at administering users,
-building roles, mapping roles to permissions, and creating a
-security policy for your Zope site.
-
-Review:  Logging In and Logging Out of the Zope Management Interface
---------------------------------------------------------------------
-
-As we first saw in the chapter entitled `Installing Zope
-<InstallingZope.html>`_ , you may log into the Zope Management
-Interface by visiting a "management" URL in your web browser,
-entering a username and password when prompted. We also pointed
-out in `Using the Zope Management Interface <UsingZope.html>`_ that
-due to the way many web browsers work, you often must perform an
-extra step when an authentication dialog is raised or you must
-quit your browser to log out of Zope.  Review these chapters for
-more information about the basics of logging in and out of the
-Zope Management Interface.
-
-Zope's "Stock" Security Setup
------------------------------
-
-"Out of the box", a vanilla Zope site has two different classes of
-users: *Managers* and *Anonymous* users.  You have already seen
-via the `Installing Zope`_ chapter how you can
-log into the Zope management interface with the "initial" user
-called "admin".  The initial "admin" user is a user with the
-*Manager* role, which allows him to perform almost any duty that
-can be performed within a Zope instance.
-
-By default, in the "stock" Zope setup, Managers have the rights to
-alter Zope content and logic objects and view the management
-interface, while the Anonymous users are only permitted to view
-rendered content. This may be sufficient for many simple websites
-and applications, especially "public-facing" sites which have no
-requirement for users to "log in" or compose their own content.
-
-Identification and Authentication
----------------------------------
-
-When a user accesses a protected resource (for example, by attempting to view a
-"protected" Page Template) Zope will ask the user to log in by presenting an
-authentication dialog. Once the dialog has been "filled out" and submitted,
-Zope will look for the user account represented by this set of credentials. By
-default Zope uses HTTP basic authentication. A cookie-based authentication can
-be implemented by adding a CookieCrumbler to the site's base folder.
-
-Zope *identifies* a user by examining the username and password
-provided during the entry into the authentication dialog.  If Zope
-finds a user within one of its user databases with the username
-provided, the user is identified.
-
-Once a user has been identified, *authentication* may or may not
-happen.  Authentication succeeds if the password provided by the
-user in the dialog matches the password registered for that user
-in the database.
-
-Zope will only attempt to identify and authenticate a user if he
-attempts to perform an action against Zope which an anonymous user
-has not been permitted the capability to perform; if a user never
-attempts to access a protected resource, Zope will continue to
-treat the user as an anonymous user.
-
-Zope prompts a user for authentication if the user attempts to
-access a "protected" resource without an adequate set of
-credentials, as determined by the resource's security policy.  For
-example, if a user attempts to access a method of an object which
-has a restrictive security policy (like all of Zope's management
-interface methods) the user will be prompted for authentication if
-he is not logged in.  You've seen this behavior already if you've
-ever attempted to log in to Zope and have been asked for a
-username and password to access the ZMI.  The ZMI is an example of
-a Zope application.  Zope's security machinery performs security
-checks on behalf of the ZMI; it "pops up" an authentication dialog
-requesting that the user enter a username and password.
-
-Different things can happen with respect to being prompted for
-authentication credentials in response to a request for a protected
-resource depending on the current state of a login session.  If
-the user has not not yet logged in, Zope will prompt the user for
-a username and password.  If the user is logged in but the account
-under which he is logged in does not have sufficient privilege to
-perform the action he has requested, Zope will prompt him for a
-*different* username and password.  If he is logged in and the
-account under which he has logged in *does* have sufficient
-privileges to perform the requested action, the action will be
-performed.  If a user cannot be authenticated because he provides
-a nonexistent username or an incorrect password to an existing
-authentication dialog, Zope re-prompts the user for authentication
-information as necessary until the user either "gets it right" or
-gives up.
-
-In general, there is no need for a user to log in to Zope if he
-only wishes to use public resources.  For example, to view the
-parts of your Zope website that are publically available, a user
-should not need to log in.
-
-Authorization, Roles, and Permissions
--------------------------------------
-
-Once a user has been authenticated, Zope determines whether or not
-he has access to the resource which is being protected. This
-process is called *authorization*.  Remember that the only reason
-that Zope asked for credentials is because the user was attempting
-to view a resource which was not viewable by an anonymous user.
-The "resource which is being protected" referred to above is the
-object which the user requested to perform an action against,
-which caused the authentication process to begin.
-
-The process of authorization involves two intermediary layers
-between the user and the protected resource: *roles* and
-*permissions*.
-
-Users have *roles* which describe "what they can do" such as
-"Author", "Manager", and "Editor".  These roles are controlled by
-the Zope system administrator.  Users may have more than one role,
-and may have a different set of roles in different contexts.  Zope
-objects have permissions which describe "what can be done with
-them" such as "View", "Delete objects", and "Manage properties".
-These permissions are defined either within Zope itself or by Zope
-*Products*, each of which may define its own set of permissions.
-
-A *context* in Zope is a "place" within the Zope object hierarchy.
-In relation to security, a context is an object that has a
-location within the Zope Object Database.  For example, a
-description of a context could be expressed as "a folder object named zoo'
-within the Zope root object". In essence, a context can be thought of as an
-object's "location" within the Zope Object Database, described by
-its "path".  Each object that exists in the Zope Object Database
-which has a web-manageable interface can be associated with its
-own security policy.  Objects can also "acquire" security policies
-from containing objects in order to ease the burden of creating a
-security policy.  In fact, most Zope objects acquire their
-security policies from their containers because it makes a given
-security policy easier to maintain.  Only when there are
-exceptions to the "master" security policy in a context are
-individual objects associated with a differing policy.
-
-In essence, *security policies map roles to permissions in a
-context*; in other words they say "who" can do "what", and
-"where". For example, the security policy for a Folder (the
-context) may associate the "Manager" role (the roles) with the
-"Delete objects" permission (the permissions). Thus, this security
-policy allows managers to delete objects in this folder.  If
-objects created within this folder do not override their parents'
-security policy, they acquire this policy.  So, for example, if a
-Page Template is created within this folder, it may also be deleted
-by users with the Manager role.  Subobjects within subfolders of
-the original folder have the same policy unless they override it
-themselves, ad infinitum.
-
-Managing Users
---------------
-
-In the chapter entitled `Installing Zope`_, you
-were provided with an "initial" account named 'admin', which
-possesses the 'Manager' role, allowing you to manage the objects
-in your Zope instance.  To allow other people to log into Zope,
-and to further understand Zope security, you should create user
-accounts under which different users may authenticate.
-
-Creating Users in User Folders
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A Zope *User* object defines a user account. A Zope *User* has a
-name, a password, one or more *roles*, and various other
-properties.  Roles are granted to a user in order to make it
-easier to control the scope of what he or she may do within a
-Zope site.
-
-To create user accounts in Zope, you create users within *User
-Folders*.  A user folder contains user objects that define Zope
-user accounts.  User Folder objects always have a Zope "id" of
-'acl_users'.  More than one user folder can exist within a Zope
-instance, but more than one user folder may not exist within the
-*same* Zope Folder.
-
-To create a new account, visit the root Zope folder. Click on
-the object named *acl_users*.  Click the *Add* button to create
-a new user.
-
-.. figure:: ../Figures/6-1.png
-
-   Adding a user to a user folder
-
-The form shown above lets you define the user. Type a username
-in the *Name* field (for example, "bob").  The username can
-contain letters, spaces, and numbers. The username is case
-sensitive.  Choose a password for your new user and enter it in
-the *Password* and *(Confirm)* fields.  In the next section, we
-will provide information about allowing a user to change his or
-her own password.
-
-The *Domains* field lets you restrict Internet domains from
-which the user can log in. This allows you to add another safety
-control to your account. For example if you always want your a
-user to log in from work you could enter your work's Internet
-domain name, for example "myjob.com", in the Domains field. You
-can specify multiple domains separated by spaces to allow the
-user to log in from multiple domains. For example if you decide
-that your coworker should be able to manage Zope from their home
-account too, you could set the domains to "myjob.com
-myhome.net". You can also use IP numbers with asterisks to
-indicate wildcard names instead of domain names to specify
-domains. For example, "209.67.167.*" will match all IP addresses
-that start with "209.67.167".
-
-The *Roles* multiple select list indicates which roles the user
-should have.  The Zope default roles include *Manager* and
-*Owner*.  In general users who need to perform management tasks
-using the Zope Management Interface should be given the
-*Manager* role.  The *Owner* role is not appropriate to grant in
-most cases because a user normally only has the Owner role in
-the context of a specific object. Granting the Owner role to a
-user in the User Folder management interface grants that user
-ownership of all objects within the folder in which the user
-folder is placed as well as all subfolders and subobjects of
-that folder.  It is unfortunate that the Owner role is present
-in the list of roles to choose from in the User Folder
-management interface, as it is confusing, little-used, and only
-now exists to service backwards compatibility.  In most cases it
-can be ignored completely.
-
-You may define your own roles such as *Editor* and *Reviewer*.
-In the section later in this chapter named "Defining Roles", we
-will create a new set of roles.  For now, we will work with the
-"stock" Zope roles.
-
-To create the new user click the *Add* button. You should see a
-new user object in the user folder.
-
-Zope User accounts defined in the "stock" user folder
-implementation do not support additional properties like
-email addresses and phone numbers.  For support of properties
-like these, you will have to use external User products like the
-CMF Membership Component (in the `CMF <http://cmf.zope.org>`_).
-
-Users can not be copied and pasted between User Folders.  The
-facility does not exist to perform this.
-
-Editing Users
-~~~~~~~~~~~~~
-
-You can edit existing users by clicking on their name within the
-User Folder management interface screen. Performing this action
-causes a form to be displayed which is very similar to the form
-you used to create a user. In fact, you may control most of the
-same settings that we detailed in the "Adding Users" section
-from within this form.  It is possible to visit this management
-screen and change a user's password, his roles, and his domain
-settings.  In the "stock" user folder implementation, you cannot
-change a user's name, however, so you will need to delete and
-recreate a user if you need to change his name.
-
-It is not possible for someone to find out a user's password by
-using the management interface.  Another manager may have access
-to *change* another user's password, but he may not find out
-what the current password is from within the management
-interface.  If a user's password is lost, it is lost forever.
-
-Like all Zope management functions, editing users is protected
-by the security policy. Users can only change their password if
-they have the *Manage Users* permission in the context of their
-own user folder, which managers have by default.  It is often
-desirable to allow users to change their own passwords.  One
-problem is that by giving a user the *Manage Users* permission,
-they are also able to edit other user accounts and add/delete
-users.  This may or may not be what you want.  
-
-To grant the capability for users to change their own passwords
-without being able to influence other users' information, set up
-a script with *Proxy Roles* to do the work for you after reading
-the section within this chapter entitled "Proxy Roles".
-
-In general, user folders work like normal Zope folders; you can
-create, edit and delete contained objects. However, user folders
-are not as capable as normal folders. You cannot cut and paste
-users in a user folder, and you can't create anything besides a
-user in a user folder.
-
-To delete an existing user from a user folder, select the user and
-click the *Delete* button. 
-
-Defining a User's Location
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Zope can contain multiple user folders at different locations in
-the object database hierarchy. A Zope user cannot access
-protected resources above the user folder in which their account
-is defined.  The location of a user's account information
-determines the scope of the user's access.
-
-If an account is defined in a user folder within the root
-folder, the user may access protected objects defined within the
-root folder. This is probably where the account you are using
-right now is defined.  You can however, create user folders
-within any Zope folder.  If a user folder is defined in a
-subfolder, the user may only access protected resources within
-that subfolder and within subfolders of that subfolder, and so
-on.  
-
-Consider the case of a user folder at
-*/BeautySchool/Hair/acl_users*. Suppose the user *Ralph
-Scissorhands* is defined in this user folder.  Ralph cannot
-access protected Zope resources above the folder at
-*/BeautySchool/Hair*. Effectively Ralph's view of protected
-resources in the Zope site is limited to things in the
-*BeautySchool/Hair* folder and below. Regardless of the roles
-assigned to Ralph, he cannot access protected resources "above"
-his location.  If Ralph was defined as having the 'Manager'
-role, he would be able to go directly to
-/BeautySchool/Hair/manage to manage his resources, but could not
-access /BeautySchool/manage at all.
-
-To access the Zope Management Interface as Manager user who is
-*not* defined in the "root" user folder, use the URL to the
-folder which contains his user folder plus 'manage'.  For
-example, if Ralph Scissorhands above has the Manager role as
-defined within a user folder in the *BeautySchool/Hair* folder,
-he would be able to access the Zope Management Interface by
-visiting 'http://zopeserver/BeautySchool/Hair/manage'.
-
-Of course, any user may access any resource which is *not*
-protected, so a user's creation location is not at all relevant
-with respect to unprotected resources.  The user's location only
-matters when he attempts to use objects in a way that requires
-authentication and authorization, such as the objects which
-compose the Zope Management Interface.
-
-It is straightforward to delegate responsibilities to site
-managers using this technique. One of the most common Zope
-management patterns is to place related objects in a folder
-together and then create a user folder in that folder to define
-people who are responsible for those objects.  By doing so, you
-"safely" *delegate* the responsibility for these objects to
-these users.
-
-For example, suppose people in your organization wear
-uniforms. You are creating an intranet that provides information
-about your organization, including information about
-uniforms. You might create a 'uniforms' folder somewhere in the
-intranet Zope site. In that folder you could put objects such as
-pictures of uniforms and descriptions for how to wear and clean
-them.  Then you could create a user folder in the 'uniforms'
-folder and create an account for the head tailor. When a new
-style of uniform comes out the tailor doesn't have to ask the
-web master to update the site, he or she can update their own
-section of the site without bothering anyone else.
-Additionally, the head tailor cannot log into any folder above
-the 'uniforms' folder, which means the head tailor cannot manage
-any objects other than those in the 'uniforms' folder.
-
-*Delegation* is a very common pattern in Zope applications. By
-delegating different areas of your Zope site to different users,
-you can take the burden of site administration off of a small
-group of managers and spread that burden around to different
-specific groups of users.
-
-Working with Alternative User Folders  
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-It may be that you don't want to manage your user account through the web using
-Zope's "stock" user folder implementation. Perhaps you already have a user
-database, or perhaps you want to use other tools to maintain your account
-information. Zope allows you to use alternate sources of data as user
-information repositories. The most popular user folder implementation is called
-`PluggableAuthService`_ which allows you to mix-in and combine a vast number of
-different authentication schemes and backends, like LDAP or MySQL.
-
-.. _PluggableAuthService: http://pypi.python.org/pypi/Products.PluggableAuthService
-
-Some user folders provide alternate login and logout controls in
-the form of web pages, rather than relying on Basic HTTP
-Authentication controls. Despite this variety, all user folders
-use the same general log in procedure of prompting you for
-credentials when you access a protected resource.
-
-While most users are managed with user folders of one kind or
-another, Zope has a few special user accounts that are not
-managed with user folder.
-
-Special User Accounts
-~~~~~~~~~~~~~~~~~~~~~
-
-Zope provides three special user accounts which are not defined
-with user folders, the *anonymous user*, the *emergency user*,
-and the *initial manager*. The anonymous user is used
-frequently, while the emergency user and initial manager
-accounts are rarely used but are important to know about.
-
-Zope Anonymous User
-%%%%%%%%%%%%%%%%%%%
-
-Zope has a built-in user account for "guests" who possess no
-credentials.  This is the 'Anonymous' user. If you don't have
-a user account on Zope, you'll be considered to be the
-'Anonymous' user.
-
-The 'Anonymous' *user* additionally possesses the 'Anonymous'
-*role*. The "stock" Zope security policy restricts users which
-possess the 'Anonymous' role from accessing nonpublic
-resources. You can tailor this policy, but most of the time
-you'll find the default anonymous security settings adequate.
-
-As we mentioned earlier in the chapter, you must try to access
-a protected resource in order for Zope to attempt
-authentication.  Even if you've got a user account on the
-system, Zope will consider you the 'Anonymous' user until you
-been prompted for login and you've successfully logged in.
-
-Zope Emergency User
-%%%%%%%%%%%%%%%%%%%
-
-Zope has a special user account for emergency use known as the
-*emergency user*. The emergency user is not restricted
-by normal security settings. However, the emergency user
-cannot create any new objects with the exception of new user
-objects.
-
-The emergency user is typically only useful for two things:
-fixing broken permissions, and creating and changing user
-accounts.
-
-You may use the emergency user account to create or change
-other user accounts.  Typically, you use the emergency user
-account to define accounts with the 'Manager' role or change
-the password of an existing account which already possesses
-the 'Manager' role.  This is useful in case you lose your
-management user password or username.  Typically, after you
-create or change an existing a manager account you will log
-out as the emergency user and log back in as the manager.
-
-Another reason to use the emergency user account is to "fix"
-broken permissions.  If you lock yourself out of Zope by
-removing permissions you need to manage Zope, you can use the
-emergency user account to repair the permissions. In this case
-log in as the emergency user and make sure that your manager
-account has the 'View management screens' and 'Change
-permissions' permissions with respect to the object you're
-attempting to view. Then log out and log back with your
-manager account and you should have enough access to fix
-anything else that is broken.
-
-The emergency user cannot create new "content", "logic" or
-"presentation" objects.  A common error message seen by users
-attempting to use the emergency user account in trying to
-create a new object is shown below.
-
-.. figure:: ../Figures/6-2.png
-
-   Error caused by trying to create a new object when logged in
-   as the emergency user
-
-The error above lets you know that the emergency user cannot
-create new objects. This is "by design", and the reasoning
-behind this policy may become clearer later in the chapter
-when we cover ownership.  
-
-Creating an Emergency User
-%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-Unlike normal user accounts that are defined through the Zope
-Management Interface, the emergency user account is defined
-through a file in the filesystem. You can change the emergency
-user account by editing or generating the file named 'access'
-in the Zope home directory (the main Zope directory). Zope
-comes with a command line utility in the Zope home directory
-named 'zpasswd.py' to manage the emergency user account.  On
-UNIX, run 'zpasswd.py' by passing it the 'access' file path as
-its only argument::
-
-  $ cd (... where your ZOPE_HOME is... )
-  $ python zpasswd.py access
-
-  Username: superuser
-  Password:
-  Verify password:
-
-  Please choose a format from:
-
-  SHA - SHA-1 hashed password
-  CRYPT - UNIX-style crypt password
-  CLEARTEXT - no protection.
-
-  Encoding: SHA
-  Domain restrictions:         
-
-Due to pathing differences, Windows users usually need to
-enter this into a command prompt to invoke zpasswd::
-
-  > cd (... where your ZOPE_HOME is ...)
-  > cd bin
-  > python ..\zpasswd.py ..\access
-
-The 'zpasswd.py' script steps you through the process of
-creating an emergency user account. Note that when you type in
-your password it is not echoed to the screen. You can also run
-'zpasswd.py' with no arguments to get a list of command line
-options.  When setting up or changing the emergency user's
-details, you need to restart the Zope process for your changes
-to come into effect.
-
-Zope Initial Manager
-%%%%%%%%%%%%%%%%%%%%
-
-The initial manager account is created by the Zope installer
-so you can log into Zope the first time. When you first
-install Zope you should see a message like this::
-
-  creating default inituser file
-  Note:
-          The initial user name and password are 'admin'
-          and 'IVX3kAwU'.
-
-          You can change the name and password through the web
-          interface or using the 'zpasswd.py' script.
-
-This lets you know the initial manager's name and
-password. You can use this information to log in to Zope for
-the first time as a manager. 
-
-Initial users are defined in a similar way to the emergency
-user; they are defined in a file on the filesystem named
-'inituser'.  On UNIX, the 'zpasswd.py' program can be used to
-edit or generate this file the same way it is used to edit or
-generate the emergency user 'access' file::
-
-  $ cd ( ... were your ZOPE_HOME is ... )
-  $ python zpasswd.py inituser
-
-  Username: bob
-  Password:
-  Verify password:
-
-  Please choose a format from:
-
-  SHA - SHA-1 hashed password
-  CRYPT - UNIX-style crypt password
-  CLEARTEXT - no protection.
-
-  Encoding: SHA
-  Domain restrictions:    
-
-This will create an 'inituser' file which contains a user
-named "bob" and will set its password.  The password is not
-echoed back to you when you type it in.  The effect of
-creating an 'inituser' file depends on the state of the
-existing Zope database.
-
-When Zope starts up, if there are *no* users in the root user
-folder (such as when you start Zope with a "fresh" ZODB
-database), and an 'inituser' file exists, the user defined
-within 'inituser' will be created within the root user folder.
-If any users already exist within the root user folder, the
-existence of the 'inituser' file has no effect.  Normally,
-initial users are created by the Zope installer for you, and
-you shouldn't have to worry about changing them.  Only in
-cases where you start a new Zope database (for example, if you
-delete the 'var/Data.fs' file) should you need to worry about
-creating an 'inituser' file.  Note that if Zope is being used
-in an INSTANCE_HOME setup, the created "inituser" file must be
-copied to the INSTANCE_HOME directory. Most Zope setups are
-not INSTANCE_HOME setups (unless you've explicitly made it
-so), so you typically don't need to worry about this.  The
-'inituser' feature is a convenience and is rarely used in
-practice except by the installer.
-
-Protecting Against Password Snooping
-------------------------------------
-
-The HTTP Basic Authentication protocol that Zope uses as part of
-its "stock" user folder implementation passes login information
-"over the wire" in an easily decryptable way.  It is employed,
-however, because it has the widest browser support of any
-available authentication mechanism.
-
-If you're worried about someone "snooping" your username/password
-combinations, or you wish to manage your Zope site ultra-securely,
-you should manage your Zope site via an SSL (Secured Sockets
-Layer) connection.  The easiest way to do this is to use Apache or
-another webserver which comes with SSL support and put it "in
-front" of Zope. The chapter of this book entitled
-`Virtual Hosting <VirtualHosting.html>`_ provides some background that may be
-helpful to set up an SSL server in front of Zope.
-
-Managing Custom Security Policies
----------------------------------
-
-Zope security policies control authorization; they define *who*
-can do *what* and *where* they can do it. Security policies
-describe how roles are associated with permissions in the context
-of a particular object. Roles label classes of users, and
-permissions protect objects. Thus, security policies define which
-classes of users (roles) can take what kinds of actions
-(permissions) in a given part of the site.
-
-Rather than stating which specific user can take which specific
-action on which specific object, Zope allows you to define which
-kinds of users can take which kinds of action in which areas of
-the site. This sort of generalization makes your security policies
-simple and more powerful. Of course, you can make exceptions to
-your policy for specific users, actions, and objects.
-
-Working with Roles
-~~~~~~~~~~~~~~~~~~
-
-Zope users have *roles* that define what kinds of actions they
-can take. Roles define classes of users such as *Manager*,
-*Anonymous*, and *Authenticated*.
-
-Roles are similar to UNIX groups in that they abstract groups of
-users. And like UNIX groups, each Zope user can have one or more
-roles.
-
-Roles make it easier for administrators to manage
-security. Instead of forcing an administrator to specifically
-define the actions allowed by each user in a context, the
-administrator can define different security policies for
-different user roles in a context.  Since roles are classes of
-users, he needn't associate the policy directly with a user.
-Instead, he may associate the policy with one of the user's
-roles.
-
-Zope comes with four built-in roles:
-
-Manager
-  This role is used for users who perform standard Zope
-  management functions such as creating and edit Zope folders and
-  documents.
-
-Anonymous
-  The Zope 'Anonymous' user has this role. This
-  role should be authorized to view public resources. In general
-  this role should not be allowed to change Zope objects.
-
-Owner
-  This role is assigned automatically to users in the
-  context of objects they create. We'll cover ownership later in
-  this chapter.
-
-Authenticated
-  This role is assigned automatically to users
-  whom have provided valid authentication credentials.  This
-  role means that Zope "knows" who a particular user is. When
-  Users are logged in they are considered to also have the
-  Authenticated role, regardless of other roles.
-
-For basic Zope sites you can typically "get by" with only having
-'Manager' and 'Anonymous' roles. For more complex sites you may
-want to create your own roles to classify your users into
-different categories.
-
-Defining Global Roles
-~~~~~~~~~~~~~~~~~~~~~
-
-A "global" role is one that shows up in the "roles" column of
-the 'Security' tab of your Zope objects.  To create a new
-"global" role go to the *Security* tab of your root Zope object
-(or any other 'folderish' Zope object) and scroll down to the
-bottom of the screen. Type the name of the new role in the *User
-defined role* field, and click *Add Role*. Role names should be
-short one or two word descriptions of a type of user such as
-"Author", "Site Architect", or "Designer". You should pick role
-names that are relevant to your application.
-
-You can verify that your role was created, noticing that there
-is now a role column for your new role at the top of the screen.
-You can delete a role by selecting the role from the select list
-at the bottom of the security screen and clicking the *Delete
-Role* button.  You can only delete your own custom roles, you
-cannot delete any of the "stock" roles that come with Zope.
-
-You should notice that roles can be used at the level at which
-they are defined and "below" in the object hierarchy.  For
-example, if you create a role in a 'myfolder' folder that
-exists in the Zope root folder, that role cannot be used outside
-of the 'myfolder' folder and any of its subfolders and
-subobjects.  If you want to create a role that is appropriate
-for your entire site, create it in the root folder.
-
-In general, roles should be applicable for large sections of
-your site. If you find yourself creating roles to *limit* access
-to parts of your site, chances are there are better ways to
-accomplish the same thing. For example you could simply change
-the security settings for existing roles on the folder you want
-to protect, or you could define users deeper in the object
-hierarchy to limit their access. 
-
-Understanding Local Roles
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-*Local roles* are an advanced feature of Zope security.
-Specific *users* can be granted extra roles when working within
-the context of a certain object by using a local role.  If an
-object has local roles associated with a user then that user
-gets those additional roles while working with that object,
-without needing to reauthenticate.
-
-For example, if a user creates an object using the Zope
-Management Interface, they are always given the additional local
-role of *Owner* in the context of that object. A user might not
-have the ability to edit Page Templates in general if he does not
-possess a set of global roles which allow him to do so, but for
-Page Templates he owns, the user may edit the Page Template by
-virtue of possessing the *Owner* local role.
-
-Local roles are a fairly advanced security control. Zope's
-automatic control of the *Owner* local role is likely the only
-place you'll encounter local roles unless you create an
-application which makes use of them.  The main reason you might
-want to manually control local roles is to give a specific user
-special access to an object. In general you should avoid setting
-security for specific users if possible. It is easier to manage
-security settings that control groups of users instead of
-individuals.
-
-Understanding Permissions
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A permission defines a single action which can be taken upon a
-Zope object. Just as roles abstract users, permissions abstract
-objects. For example, many Zope objects, including Page Templates
-and Folders, can be viewed. This action is protected by
-the *View* permission.  Permissions are defined by Zope
-developers in Python packages and the Zope "core" itself. Packages are
-responsible for creating a set of permissions which are relevant
-to the types of objects they expose.
-
-Some permissions are only relevant for one type of object.
-Other permissions protect many types of objects, such
-as the *FTP access* and *WebDAV access* permissions which
-control whether objects are available via FTP and WebDAV.
-
-You can find out what permissions are available on a given object
-by going to the *Security* management tab.
-
-The default Zope permissions are described in `appendix A
-<http://www.zope.org/Documentation/Books/ZDG/current/AppendixA.stx>`_
-of the Zope Developer's Guide.
-
-.. figure:: ../Figures/6-3.png     
-
-   Security settings for a mail host object
-
-As you can see in the figure above, a mail host has a limited
-palette of permissions available. Contrast this to the many
-permissions that you see when setting security on a folder.
-
-Defining Security Policies
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Security policies are where roles meet permissions. Security
-policies define "who" can do "what" in a given part of the site.
-
-You can set a security policy on almost any Zope object. To set
-a security policy on an object, go the object's *Security* tab.
-For example, click on the security tab of the root folder.
-
-.. figure:: ../Figures/6-4.png
-
-   Security policy for the root folder
-
-In the figure above, the center of the screen displays a grid of
-check boxes. The vertical columns of the grid represent roles,
-and the horizontal rows of the grid represent permissions.
-Checking the box at the intersection of a permission and a role
-grants users with that role the ability to take actions
-protected by that permission in the context of the object being
-managed.  In this case, the context is the root folder.
-
-Many Zope Products add custom security permissions to your site
-when you install them.  This can make the permissions list grow
-quite large, and unwieldy.  Product authors should take care to
-re-use suitable existing permissions if possible, but many times
-it's not possible, so the permission list grows with each new
-Product that is installed.
-
-You'll notice by virtue of visiting the Security tab of the root
-folder that Zope comes with a default security policy that
-allows users which possess the 'Manager' role to perform most
-tasks, and that allows anonymous users to perform only a few
-restricted tasks.  The simplest (and most effective) way to
-tailor this policy to suit your needs is to change the security
-settings in the root folder.
-
-For example, you can make your site almost completely "private"
-by disallowing anonymous users the ability to view objects. To
-do this deny all anonymous users View access by unchecking the
-*View* Permission where it intersects the *Anonymous* role.  You
-can make your entire site private by making this security policy
-change in the root folder. If you want to make one part of your
-site private, you could make this change in the folder you want
-to make private.
-
-This example points out a very important point about security
-policies: they control security for a given part of the site
-only. The only global security policy is the one on the root
-folder.
-
-Security Policy Acquisition
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-How do different security policies interact? We've seen that you
-can create security policies on different objects, but what
-determines which policies control which objects? The answer is
-that objects use their own policy if they have one, additionally
-they acquire their parents' security policies through a process
-called *acquisition*.  We explored acquisition in the
-`Acquisition <Acquisition.html>`_ chapter.  Zope security makes
-extensive use of acquisition.
-
-Acquisition is a mechanism in Zope for sharing information among
-objects contained in a folder and its subfolders. The Zope
-security system uses acquisition to share security policies so
-that access can be controlled from high-level folders.
-
-You can control security policy acquisition from the
-*Security* tab.  Notice that there is a column of check boxes
-to the left of the screen labeled *Acquire permission
-settings*. Every check box in this column is checked by
-default. This means that security policy will acquire its
-parent's setting for each permission to role setting in
-addition to any settings specified on this screen.  Keep in mind
-that for the root folder (which has no parent to acquire from)
-this left most check box column does not exist.
-
-Suppose you want to make a folder private. As we saw before this
-merely requires denying the *Anonymous* role the *View*
-permission in the context of this object. But even though the
-"View" permission's box may be unchecked the folder might not be
-private. Why is this?  The answer is that the *Acquire
-permission settings* option is checked for the View
-permission. This means that the current settings are augmented
-by the security policies of this folder's parents. Somewhere
-above this folder the *Anonymous* role must be assigned to the
-*View* permission. You can verify this by examining the security
-policies of this folder's parents. To make the folder private we
-must uncheck the *Acquire permission settings* option. This will
-ensure that only the settings explicitly in this security policy
-are in effect.
-
-Each checked checkbox gives a role permission to do an action or
-a set of actions. With 'Acquire permission settings' checked,
-these permissions are *added* to the actions allowed in the
-parent folder.  If 'Acquire permission settings' is unchecked on
-the other hand, checkboxes must be explicitly set, and the
-security setting of the parent folder will have no influence.
-
-In general, you should always acquire security settings unless
-you have a specific reason to not do so. This will make managing
-your security settings much easier as much of the work can be
-done from the root folder.
-
-Security Usage Patterns
------------------------
-
-The basic concepts of Zope security are simple: roles and
-permissions are mapped to one another to create security policies.
-Users are granted roles (either global roles or local roles).
-User actions are restricted by the roles they possess in the
-context of an object.  These simple tools can be put together in
-many different ways. This can make managing security
-complex. Let's look at some basic patterns for managing security
-that provide good examples of how to create an effective and easy
-to manage security architecture.
-
-Security Rules of Thumb
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Here are a few simple guidelines for Zope security
-management. The security patterns that follow offer more
-specific recipes, but these guidelines give you some guidance
-when you face uncharted territory.
-
-1. Define users at their highest level of control, but no higher.
-
-2. Group objects that should be managed by the same people
-   together in folders.
-
-3. Keep it simple.
-
-Rules one and two are closely related. Both are part of a more
-general rule for Zope site architecture. In general you should
-refactor your site to locate related resources and users near
-each other. Granted, it's almost never possible to force
-resources and users into a strict hierarchy. However, a well
-considered arrangement of resources and users into folders and
-sub-folders helps tremendously.
-
-Regardless of your site architecture, try to keep things
-simple. The more you complicate your security settings the
-harder time you'll have understanding it, managing it and making
-sure that it's effective. For example, limit the number of new
-roles you create, and try to use security policy acquisition to
-limit the number of places you have to explicitly define
-security settings. If you find that your security policies,
-users, and roles are growing into a complex thicket, you should
-rethink what you're doing; there's probably a simpler way.
-
-Global and Local Policies
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The most basic Zope security pattern is to define a global
-security policy on the root folder and acquire this policy
-everywhere. Then as needed you can add additional policies
-deeper in the object hierarchy to augment the global policy. Try
-to limit the number of places that you override the global
-policy. If you find that you have to make changes in a number of
-places, consider consolidating the objects in those separate
-locations into the same folder so that you can make the security
-settings in one place.
-
-You should choose to acquire permission settings in your
-sub-policies unless your sub-policy is more restrictive than the
-global policy. In this case you should uncheck this option for
-the permission that you want to restrict.
-
-This simple pattern will take care of much of your security
-needs. Its advantages are that it is easy to manage and easy to
-understand. These are extremely important characteristics for
-any security architecture.
-
-Delegating Control to Local Managers
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The pattern of *delegation* is very central to Zope. Zope
-encourages you to collect like resources in folders together and
-then to create user accounts in these folders to manage their
-contents.
-
-Lets say you want to delegate the management of the *Sales*
-folder in your Zope site over to the new sales web manager,
-Steve.  First, you don't want Steve changing any objects which
-live outside the Sales folder, so you don't need to add him to
-the acl_users folder in the root folder.  Instead, you would
-create a new user folder in the *Sales* folder.
-
-Now you can add Steve to the user folder in *Sales* and give him the
-Role *Manager*.  Steve can now log directly into the Sales folder to
-manage his area of control by pointing his browser to
-*http://www.zopezoo.org/Sales/manage*.
-
-.. figure:: ../Figures/6-5.png
-
-   Managing the Sales folder
-
-Notice in the figure above that the navigation tree on the left
-shows that *Sales* is the root folder.  The local manager
-defined in this folder will never have the ability to log into
-any folders above *Sales*, so it is shown as the top folder.
-
-This pattern is very powerful since it can be applied
-recursively. For example, Steve can create a sub-folder for
-multi-level marketing sales. Then he can create a user folder in
-the multi-level marketing sales folder to delegate control of
-this folder to the multi-level marketing sales manager. And so
-on. This allows you to create websites managed by thousands of
-people without centralized control.  Higher level managers need
-not concern themselves too much with what their underlings
-do. If they choose they can pay close attention, but they can
-safely ignore the details since they know that their delegates
-cannot make any changes outside their area of control, and they
-know that their security settings will be acquired.
-
-Different Levels of Access with Roles
--------------------------------------
-
-The local manager pattern is powerful and scalable, but it takes
-a rather coarse view of security. Either you have access or you
-don't. Sometimes you need to have more fine grained
-control. Many times you will have resources that need to be used
-by more than one type of person. Roles provides you with a
-solution to this problem. Roles allow you to define classes of
-users and set security policies for them.
-
-Before creating new roles make sure that you really need
-them. Suppose that you have a website that publishes
-articles. The public reads articles and managers edit and publish
-articles, but there is a third class of user who can author
-articles, but not publish or edit them.
-
-One solution would be to create an authors folder where author
-accounts are created and given the *Manager* role. This folder
-would be private so it could only be viewed by
-managers. Articles could be written in this folder and then
-managers could move the articles out of this folder to publish
-them. This is a reasonable solution, but it requires that
-authors work only in one part of the site and it requires extra
-work by managers to move articles out of the authors
-folder. Also, consider that problems that result when an author
-wants to update an article that has been moved out of the
-authors folder.
-
-A better solution is to add an *Author* role.  Adding a role
-helps us because it allows access controls not based on
-location. So in our example, by adding an author role we make it
-possible for articles to be written, edited, and published
-anywhere in the site. We can set a global security policy that
-gives authors the ability to create and write articles, but
-doesn't grant them permissions to publish or edit articles.
-
-Roles allow you to control access based on who a user is, not
-just where they are defined.
-
-Controlling Access to Locations with Roles
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Roles can help you overcome a problem with the
-local manager pattern. The problem is that the local manager
-pattern requires a strict hierarchy of control.  There is no
-provision to allow two different groups of people to access the
-same resources without one group being the manager of the other
-group. Put another way, there is no way for users defined in one
-part of the site to manage resources in another part of the
-site.
-
-Let's take an example to illustrate the second limitation of the
-local manager pattern. Suppose you run a large site for a
-pharmaceutical company. You have two classes of users,
-scientists and salespeople. In general the scientists and the
-salespeople manage different web resources.  However, suppose
-that there are some things that both types of people need to
-manage, such as advertisements that have to contain complex
-scientific warnings. If we define our scientists in the *Science*
-folder and the salespeople in the *Sales* folder, where should we
-put the *AdsWithComplexWarnings* folder? Unless the Science folder
-is inside the Sales folder or vice versa there is no place that
-we can put the *AdsWithComplexWarnings* folder so that both
-scientists and salespeople can manage it. It is not a good
-political or practical solution to have the salespeople manage
-the scientists or vice versa; what can be done?
-
-The solution is to use roles. You should create two roles at a
-level above both the Science and Sales folders, say *Scientist*,
-and *SalesPerson*. Then instead of defining the scientists and
-salespeople in their own folders define them higher in the
-object hierarchy so that they have access to the
-*AdsWithComplexWarnings* folder.
-
-When you create users at this higher level, you should not give them
-the *Manager* role, but instead give them Scientist or SalesPerson as
-appropriate. Then you should set the security policies using the 
-checkboxes in the Security panel.  On the
-*Science* folder the *Scientist* role should have the equivalent of
-*Manager* control. On the *Sales* folder, the *Salesperson* role
-should have the same permissions as *Manager*. Finally on the
-*AdsWithComplexWarnings* folder you should give both *Scientist* and
-*Salesperson* roles adequate permissions. This way roles are used not
-to provide different levels of access, but to provide access to
-different locations based on who you are.
-
-Another common situation when you might want to employ this
-pattern is when you cannot define your managers locally. For
-example, you may be using an alternate user folder that requires
-all users to be defined in the root folder. In this case you
-would want to make extensive use of roles to limit access to
-different locations based on roles.
-
-This wraps up our discussion of security patterns. By now you
-should have a reasonable grasp of how to use user folders,
-roles, and security policies, to shape a reasonable security
-architecture for your application.  Next we'll cover two
-advanced security issues, how to perform security checks, and
-securing executable content.
-
-Performing Security Checks
---------------------------
-
-Most of the time when developing a Zope application, you needn't
-perform any "manual" security checks. The term for this type of
-security which does not require manual effort on the part of the
-application developer is "declarative".  Zope security is
-typically declarative.  If a user attempts to perform a secured
-operation, Zope will prompt them to log in. If the user doesn't
-have adequate permissions to access a protected resource, Zope
-will deny them access.
-
-However, sometimes you may wish to manually perform security
-checks. The main reason to do this is to limit the choices you
-offer a user to those for which they are authorized. This doesn't
-prevent a sneaky user from trying to access secured actions, but
-it does reduce user frustration, by not giving to user the option
-to try something that will not work.
-
-The most common security query asks whether the current user has a
-given permission. We use Zope's 'checkPermission' API to do this.
-For example, suppose your application allows some users to upload
-files. This action may be protected by the "Add Documents, Images,
-and Files" standard Zope permission. You can test to see if the
-current user has this permission in a Page Template::
-
-  <form action="upload" 
-    tal:condition="python:
-      modules['AccessControl'].getSecurityManager().checkPermission(
-         'Add / Documents, Images, and Files', context)">
-  ...
-  </form>
-
-A Python Script can be employed to perform the same task on behalf
-of a Page Template.  In the below example, we move the security
-check out of the Page Template and into a Python Script named
-'check_security', which we call from the Page Template.  Here is
-the Page template::
-
-  <form action="upload"
-        tal:condition="python: context.check_security(
-           'Add Documents, Images and Files', here)">
-
-Here is the 'check_security' Python Script which is referenced
-within the Page Template::
-
-  ## Script (Python) "check_security"
-  ##bind container=container
-  ##bind context=context
-  ##bind namespace=
-  ##bind script=script
-  ##bind subpath=traverse_subpath
-  ##parameters=permission, object
-  ##title=Checks security on behalf of a caller
-
-  from AccessControl import getSecurityManager
-  sec_mgr = getSecurityManager()
-  return sec_mgr.checkPermission(permission, object)
-
-You can see that permission checking may take place manually in
-any of Zope's logic objects.  Other functions exist in the Zope
-API for manually performing security checks, but 'checkPermission'
-is arguably the most useful.
-
-By passing the current object to 'checkPermission', we make sure
-that local roles are taken into account when testing whether the
-current user has a given permission.
-
-You can find out about the current user by accessing the user object. 
-The current user is a Zope object like any other and you can
-perform actions on it using methods defined in the API
-documentation.
-
-Suppose you wish to display the current user name on a web page to
-personalize the page. You can do this easily in Page Template::
-
-  <p tal:content="user/getUserName">username</p>
-
-The Zope security API for Scripts is explained in
-`Appendix B: API Reference <AppendixB.html>`_. The Zope security API for Page
-Templates is explained in
-`Appendix C: Zope Page Templates Reference <AppendixC.html>`_.
-
-Advanced Security Issues: Ownership and Executable Content
-----------------------------------------------------------
-
-You've now covered all the basics of Zope security. What remains
-are the advanced concepts of *ownership* and *executable
-content*. Zope uses ownership to associate objects with users who
-create them, and executable content refers to objects such as
-Scripts, which execute user code.
-
-For small sites with trusted users you can safely ignore these
-advanced issues. However for large sites where you allow untrusted
-users to create and manage Zope objects, it's important to
-understand ownership and securing executable content.
-
-The Problem: Trojan Horse Attacks
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The basic scenario that motivates both ownership and executable
-content controls is a *Trojan horse* attack. A Trojan horse is
-an attack on a system that operates by tricking a user into
-taking a potentially harmful action. A typical Trojan horse
-masquerades as a benign program that causes harm when you
-unwittingly run it.
-
-All computer systems are vulnerable to this style of attack.
-For web-based platforms, all that is required is to trick an
-authorized, but unsuspecting user to visit a URL that performs a
-harmful action that the attacker himself is not authorized to
-perform.
-
-This kind of attack is very hard to protect against. You can
-trick someone into clicking a link fairly easily, or you can use
-more advanced techniques such as Javascript to cause a user to
-visit a malicious URL.
-
-Zope offers some protection from this kind of Trojan horse. Zope
-helps protect your site from server-side Trojan attacks by
-limiting the power of web resources based on who authored them.
-If an untrusted user authors a web page, then the power of the
-web pages to do harm to unsuspecting visitors will be
-limited. For example, suppose an untrusted user creates a
-Script (Python) that deletes all the pages in your
-site. If anyone attempt to view the page, it will fail since the
-owner of the object does not have adequate permissions. If a
-manager views the page, it will also fail, even though the
-manager does have adequate permissions to perform the dangerous
-action.
-
-Zope uses ownership information and executable content
-controls to provide this limited protection.
-
-Managing Ownership
-~~~~~~~~~~~~~~~~~~
-
-When a user creates a Zope object, the user *owns* that object.
-An object that has no owner is referred to as *unowned.*
-Ownership information is stored in the object itself.  This is
-similar to how UNIX keeps track of the owner of a file.
-
-You find out how an object is owned by viewing the *Ownership*
-management tab, as shown in the figure below.
-
-.. figure:: ../Figures/6-6.png
-
-   Managing ownership settings
-
-This screen tells you if the object is owned and if so by
-whom.  If the object is owned by someone else, and you have the
-*Take ownership* permission, you can take over the ownership of an
-object.  You also have the option of taking ownership of all
-sub-objects by checking the *Take ownership of all sub-objects* box.
-Taking ownership is mostly useful if the owner account has been
-deleted, or if objects have been turned over to you for
-continued management.
-
-As we mentioned earlier in the chapter, ownership affects
-security policies because users will have the local role *Owner*
-on objects they own. However, ownership also affects security
-because it controls the role's executable content.
-
-Note that due to the way Zope "grew up" that the list of users
-granted the Owner local role in the context of the object is
-*not* related to its actual "owner".  The concepts of the owner
-"role" and executable content ownership are distinct.  Just
-because someone has the Owner local role in the context of an
-executable object does not mean that he is the *owner* of the
-object.
-
-Roles of Executable Content
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Python-based Scripts are said to be *executable* since their content is
-generated dynamically. Their content is also editable through the web.
-
-When you view an executable object by visiting its URL or
-calling it from a script, Zope runs the object's
-executable content. The objects actions are restricted by the
-roles of its owner and your roles. In other words an executable
-object can only perform actions that *both* the owner and the
-viewer are authorized for. This keeps an unprivileged user from
-writing a harmful script and then tricking a powerful user into
-executing the script. You can't fool someone else into
-performing an action that you are not authorized to perform
-yourself. This is how Zope uses ownership to protect against
-server-side Trojan horse attacks.
-
-It is important to note that an "unowned" object is typically no
-longer executable.  If you experience problems running an
-executable object, make sure that its ownership settings are
-correct.
-
-Proxy Roles
-~~~~~~~~~~~
-
-Sometimes Zope's system of limiting access to executable objects
-isn't exactly what you want. Sometimes you may wish to clamp
-down security on an executable object despite its ownership as a
-form of extra security. Other times you may want to provide an
-executable object with extra access to allow an unprivileged
-viewer to perform protected actions. *Proxy roles* provide you
-with a way to tailor the roles of an executable object.
-
-Suppose you want to create a mail form that allows anonymous
-users to send email to the webmaster of your site. Sending email
-is protected by the 'Use mailhost services'
-permission. Anonymous users don't normally have this permission
-and for good reason. You don't want just anyone to be able to
-anonymously send email with your Zope server.
-
-The problem with this arrangement is that your Script (Python) that
-sends email will fail for anonymous users. How can you get
-around this problem? The answer is to set the proxy roles on the
-Script (Python) that sends email so that when it executes it has the
-"Manager" role. Visit the Proxy management tab on your Python
-script, as shown in the figure below.
-
-.. figure:: ../Figures/6-7.png
-
-   Proxy role management
-
-Select *Manager* and click the *Change* button. This will set
-the proxy roles of the mail sending method to *Manager*. Note
-you must have the *Manager* role yourself to set it as a proxy
-role. Now when anyone, anonymous or not runs your mail sending
-method, it will execute with the *Manager* role, and thus will
-have authorization to send email.
-
-Proxy roles define a fixed amount of permissions for executable
-content. Thus you can also use them to restrict security. For
-example, if you set the proxy roles of a script to *Anonymous*
-role, then the script will never execute as having any other
-roles besides *Anonymous* despite the roles of the owner and
-viewer.
-
-Use Proxy roles with care, since they can be used to skirt the
-default security restrictions.
-
-Summary
--------
-
-Security consists of two processes, authentication and
-authorization. User folders control authentication, and security
-policies control authorization. Zope security is intimately tied
-with the concept of location; users have location, security
-policies have location, even roles can have location. Creating an
-effective security architecture requires attention to
-location. When in doubt refer to the security usage patterns
-discussed in this chapter.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/Sessions.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/Sessions.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/Sessions.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,1435 +0,0 @@
-Session Management
-##################
-
-This chapter describes Zope's built-in Session Management.
-
-Terminology
-===========
-
-Here's a mini-glossary of of key terms used within this document:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-Web session
-  a series of HTTP requests from the same browser to the same server during
-  that browser's execution life-span.
-
-Browser Id
-  the string or integer used to represent a single anonymous visitor to the
-  part of the Zope site managed by a single browser id manager. E.g.
-  "12083789728".
-
-Browser Id Name
-  the name which is looked for in places enumerated by the currently configured
-  browser id namespaces. E.g. "_ZopeId".
-
-Browser Id Namespaces
-  the browser id name will be found in one of three possible places
-  ("namespaces"): in form elements and/or query strings (aka "form"), in a
-  cookie, or in the URL.
-
-Session Data Object
-  an transient data object that is found by asking a session data container for
-  the item with a key that is the current browser id value.
-
-Session Id
-  the identifier for a session data object. This is different than the browser
-  id. Instead of representing a single - *visitor*- , it represents a single -
-  *visit*- .
-
-Session Managers
-================
-
-Web browsers communicate with Web Servers using HTTP. HTTP does not provide
-tools that can track users and data in the context of a web session. Zope's
-session management works-around the problem: it provides methods able to track
-site visitor activity. Applications like "shopping carts" use session
-management for this reason.
-
-Zope's session management makes use of name-spaces like cookies, HTTP form
-elements, and/or parts of URLs "in the background" to keep track of user
-sessions. Which of these name-spaces are used is configurable using the
-browser_id manager (described later).
-
-Session data is valid for the duration of a **configurable inactivity** timeout
-value or browser shut-down, which ever comes first. Zope's session management
-keeps track of anonymous users as well as those who have Zope login accounts.
-
-Important! Data maintained by Zope's session management is no more secure than
-HTTP itself. A session is secure if and only if:
-
-- the connection between a browser and Zope uses strong encryption (SSL
-  normally).
-
-- precautions specific to the security exposure are taken.
-
-It's clear that you should not store sensitive information like credit card
-numbers in a session container unless you understand the vulnerabilities. See
-the section entitled *Security Considerations* near the end of this document.
-
-It is advisable to use sessions only on pages where they are necessary because
-of a performance impact on your application. The severity varies depending on
-usage and configuration. A good "rule of thumb" is to account for a 5% - 10%
-speed-of-execution penalty.
-
-Some hints:
-
-- Do not use SESSION to store REQUEST variables. They are already available in
-  the REQUEST.
-
-- Do not store any data in SESSION that you can get from the Zope API. Its
-  faster (and more secure) to get user Id from Zope's Security Manager then it
-  is from the SESSION object.
-
-Session Manager Components
-==========================
-
-Browser Id Manager
-++++++++++++++++++
-
-This component determines a remote client's "browser id", which uniquely
-identifies a particular browser. The browser id is encoded in a
-form/querystring variable, a cookie variable, or as part of the URL. The
-browser id manager examines cookies, form and querystring elements, and URLs
-to determine the client's browser id. It can also modify cookies and URLs
-automatically in order to differentiate users between requests.
-
-- There may be more than one browser id manager in a Zope installation, but
-  commonly there will only be one. Application developers will generally not
-  talk directly to a browser id manager. Instead, they will use the Transient
-  Data Object (REQUEST.SESSION) which delegates some calls to a browser_id
-  manager.
-
-- Browser id managers have "fixed" Zope ids so they can be found via
-  acquisition by session data managers. Browser id managers also have
-  interfaces for encoding a URL with browser id information and performing
-  other utility functions.
-
-- The default sessioning configuration provides a Browser Id Manager as the::
-
-    /browser_id_manager object
-
-Session Data Manager
-++++++++++++++++++++
-
-This component is responsible for handing out session data to callers. When
-session data is required, the session data manager:
-
-* talks to a browser id manager to determine the current browser id-
-
-* creates a new session data object or hands back an existing session data
-  object based on the browser id.
-
-- Developers generally do not directly use methods of session data managers to
-  obtain session data objects. Instead, they rely on the built-in
-  REQUEST.SESSION object, which represents *the current session data object
-  related to the user's browser id*.
-
-- The session data object has an identifier distinct from the browser id. This
-  identifier represents a single user session with the server (unlike the
-  browser id, which represents a single browser). Many session data managers
-  can use one browser id manager. Many session data managers can be
-  instantiated on a single Zope installation. Different session data managers
-  can implement different policies related to session data object storage (e.g.
-  to which session data container the session data objects are stored).
-
-- The default sessioning configuration provides a Session Data Manager named::
-
-    /session_data_manager
-
-Transient Object Container
-++++++++++++++++++++++++++
-
-Also known as Session Data Containers, these components actually hold
-information related to sessions.
-
-- Currently, a Transient Object Container is used to hold a special "transient
-  data object" instance for each ongoing session. Developers will generally not
-  interact with transient data containers. Transient data containers are
-
-- responsible for expiring the session data objects which live within them.
-
-- The default sessioning configuration provides a Transient Object Container
-  named::
-
-    /temp_folder/session_data
-
-  The session data objects in the default::
-
-    session_data
-
-  Transient Object container are lost each time Zope is restarted.
-
-Transient Data Object
-+++++++++++++++++++++
-
-Also known as the Session Data Object. These are the objects which are stored
-in session data containers and managed by transient data managers.
-
-- Developers interact with a transient data object after obtaining one via
-  REQUEST.SESSION or from a session data manager directly. A single transient
-  data object actually stores the useful information related to a single user's
-  session.
-
-- Transient data objects can be expired automatically by transient data
-  containers as a result of inactivity, or they can be manually invalidated in
-  the course of a script.
-
-Using Session Data
-==================
-
-You will typically access session data through the::
-
-  SESSION
-
-attribute of the REQUEST object. Session data objects are like Python
-dictionaries: they can hold almost any kind of object as a key or a value. It's
-likely you will almost always use "normal" Python objects such as lists,
-dictionaries, strings, and numbers.
-
-Here's an example of how to work with a session using a Python Script::
-
-  ## Script (Python) "sessionTest"
-  secs_per_day=24*60*60
-  session=context.REQUEST.SESSION
-  if session.has_key('last view'):
-      # The script has been viewed before, since the 'last view'
-      then=session['last view']
-      now=context.ZopeTime()
-      session['last view']=now # reset last view to now
-      return 'Seconds since last view %.2f' % ((now - then) * secs_per_day)
-
-  # The script hasn't been viewed before, since there's no 'last view' 
-  session['last view']=context.ZopeTime()
-  return 'This is your first view'
-
-This example shows how to access SESSION data. But it is not a "best practice"
-example. If performance is an issue, you should not attempt to keep
-last-accessed time in this manner in a production application because it might
-slow your application down dramatically and cause problems under high load.
-
-Create a script with this body named *sessionTest* in your root folder and
-then click its *Test* tab. While viewing the output, reload the frame a few
-times. Note that the script keeps track of when you last viewed it and
-calculates how long it has been since you last viewed it. Notice that if you
-quit your browser and come back to the script it forgets you were ever there.
-However, if you simply visit some other pages and then return within 20 minutes
-or so, it still remembers the last time you viewed it.
-
-See the *Concepts and Caveats* section at the end of this document for things
-to watch out for while accessing Zope's Session Manager "naively".
-
-You can use sessions in Page Templates and DTML Documents, too. For example,
-here's a template snippet that displays the users favorite color (as stored in
-a session)::
-
-  <p tal:content="request/SESSION/favorite_color">Blue</p>
-
-Sessions have additional configuration parameters and usage patterns detailed
-below.
-
-Default Configuration
-=====================
-
-Zope is preconfigured with a default sessioning setup.
-
-The Zope "default" browser id manager lives in the root folder and is named::
-
-  browser_id_manager
-
-The Zope "default" session data manager lives in the root folder and is named::
-
-  session_data_manager
-
-A "default" transient data container (session data container) is created as::
-
-  /temp_folder/session_data
-
-when Zope starts up. The::
-
-  temp_folder
-
-object is a "mounted, nonundoing" database that keeps information in RAM, so
-"out of the box", Zope stores session information in RAM. The temp folder is a
-"nonundoing" storage (meaning you cannot undo transactions which take place
-within it) because accesses to transient data containers are very
-write-intensive, and undoability adds unnecessary overhead.
-
-A transient data container stores transient data objects. The default
-implementation the transient data object shipped with Zope is engineered to
-reduce the potential inherent in the ZODB for "conflict errors" related to the
-ZODB's "optimistic concurrency" strategy.
-
-You needn't change any of these default options to use sessioning under Zope
-unless you want to customize your setup. However, if you have custom needs, can
-create your own session data managers, browser id managers, temporary folders,
-and transient object containers by choosing these items from Zope's "add" list
-in the place of your choosing.
-
-Advanced Development Using Sessioning
-=====================================
-
-Overview
-++++++++
-
-When you work with the REQUEST.SESSION object, you are working with a "session
-data object" that is related to the current site user.
-
-Session data objects have methods of their own, including methods with allow
-developers to get and set data. Session data objects are also "wrapped" in the
-acquisition context of their session data manager, so you may additionally call
-any method on a session data object that you can call on a session data
-manager.
-
-Obtaining A Session Data Object
-+++++++++++++++++++++++++++++++
-
-The session data object associated with the browser id in the current request
-may be obtained via REQUEST.SESSION. If a session data object does not exist in
-the session data container, one will be created automatically when you
-reference REQUEST.SESSION::
-
-  <dtml-let data="REQUEST.SESSION">
-      The 'data' name now refers to a new or existing session data object.
-  </dtml-let>
-
-You may also use the::
-
-  getSessionData()
-
-method of a session data manager to do the same thing::
-
-  <dtml-let data="session_data_manager.getSessionData()">
-      The 'data' name now refers to a new or existing session data object.
-  </dtml-let>
-
-A reference to REQUEST.SESSION or::
-
-  getSessionData()
-
-implicitly creates a new browser id if one doesn't exist in the current
-request. These mechanisms also create a new session data object in the session
-data container if one does not exist related to the browser id in the current
-request. To inhibit this behavior, use the create=0 flag to the::
-
-  getSessionData()
-
-method. In ZPT::
-
-  <span tal:define="data python:context.session_data_manager.getSessionData(create=0)">
-
-Note: create=0 means return a reference to the session or None. create=1 means
-return a reference if one exists or create a new Session object and the
-reference.
-
-Modifying A Session Data Object
-+++++++++++++++++++++++++++++++
-
-Once you've used REQUEST.SESSION or::
-
-  session_data_manager.getSessionData()
-
-to obtain a session data object, you can set key/value pairs of that session
-data object.
-
-In ZPT::
-
-  <span tal:define="data python: request.SESSION">
-      <tal:block define="temp python: data.set('foo','bar')">
-          <p tal:content="python: data.get('foo')">bar will print here"</p>
-      </tal:block>
-  </span>
-
-An essentially arbitrary set of key/value pairs can be placed into a session
-data object. Keys and values can be any kinds of Python objects (note: see
-*Concepts and Caveats* section below for exceptions to this rule). The session
-data container which houses the session data object determines its expiration
-policy. Session data objects will be available across client requests for as
-long as they are not expired.
-
-Clearing A Session Data Object
-++++++++++++++++++++++++++++++
-
-You can clear all keys and values from a SESSION object by simply calling its
-clear() method.
-
-In ZPT::
-
-  <span tal:define="dummy python:request.SESSION.clear()"></span>
-
-Manually Invalidating A Session Data Object
-+++++++++++++++++++++++++++++++++++++++++++
-
-Developers can manually invalidate a session data object. When a session data
-object is invalidated, it will be flushed from the system.
-
-There is a caveat. If you invalidate the session object in a script then you
-**must** obtain a fresh copy of the session object by calling getSessionData
-and not by reference (REQUEST.SESSION).
-
-Here is an example using DTML:::
-
-  <!-- set a SESSION key and value -->
-  <dtml-let data="REQUEST.SESSION">
-  <dtml-call "data.set('foo','bar')      
-
-  <!-- Now invalidate the SESSION -->
-  <dtml-call "data.invalidate()">
-
-  <!-- But REQUEST.SESSION gives us stale data which is bad.
-  The next statement will still show 'foo' and 'bar'
-  <dtml-var "REQUEST.SESSION>
-
-  <!-- Heres the work-around: -->
-  data = session_data_manager.getSessionData()
-
-  <!-- Now we get a fresh copy and life is good as 'foo' and 'bar' have gone away as expected -->
-  <dtml-var data>
-
-Manual invalidation of session data is useful when you need a "fresh" copy of a
-session data object.
-
-If an "onDelete" event is defined for a session data object, the onDelete
-method will be called before the data object is invalidated. See a following
-section for information about session data object "onDelete" and "onAdd"
-events.
-
-Manually Invalidating A Browser Id Cookie
-+++++++++++++++++++++++++++++++++++++++++
-
-Invalidating a session data object does not invalidate the browser id cookie
-stored on the user's browser. Developers may manually invalidate the cookie
-associated with the browser id. To do so, they can use the::
-
-  flushBrowserIdCookie()
-
-method of a browser id manager. For example::
-
-  <dtml-call "REQUEST.SESSION.getBrowserIdManager().flushBrowserIdCookie()">
-
-If the::
-
-  cookies
-
-namespace isn't a valid browser id key namespace when this call is performed,
-an exception will be raised.
-
-Using Session Data with TAL
-+++++++++++++++++++++++++++
-
-Here's an example of using the session data object with TAL::
-
-  <span tal:define="a python:request.SESSION;
-                    dummy python:a.set('zopetime',context.ZopeTime())">
-      <p tal:content="python: a.get('zopetime')"></p>
-  </span>
-
-Using Session Data From Python
-++++++++++++++++++++++++++++++
-
-Here's an example of using a session data manager and session data object from
-a set of Python external methods::
-
-  import time
-  def setCurrentTime(self):
-      a = self.REQUEST.SESSION
-      a.set('thetime', time.time())
-
-  def getLastTime(self):
-      a = self.REQUEST.SESSION
-      return a.get('thetime')
-
-Calling the setCurrentTime will set the value of the current session's
-"thetime" key to an integer representation of the current time. Calling the
-getLastTime external method will return the integer representation of the last
-known value of "thetime".
-
-Interacting with Browser Id Data
-++++++++++++++++++++++++++++++++
-
-You can obtain the browser id value associated with the current request::
-
-  <dtml-var "REQUEST.SESSION.getBrowserIdManager().getBrowserId()">
-
-Another way of doing this, which returns the same value is::
-
-  <dtml-var "REQUEST.SESSION.getContainerKey()">
-
-If no browser id exists for the current request, a new browser id is created
-implicitly and returned.
-
-If you wish to obtain the current browser id value without implicitly creating
-a new browser id for the current request, you can ask the browser_id_manager
-object explicitly for this value with the `create=0` parameter::
-
-  <dtml-var "browser_id_manager.getBrowserId(create=0)">
-
-This snippet will print a representation of the None value if there isn't a
-browser id associated with the current request, or it will print the browser id
-value if there is one associated with the current request. Using `create=0` is
-useful if you do not wish to cause the sessioning machinery to attach a new
-browser id to the current request, perhaps if you do not wish a browser id
-cookie to be set.
-
-The browser id is either a string or an integer and has no business meaning. In
-your code, you should not rely on the browser id value composition, length, or
-type as a result, as it is subject to change.
-
-Determining Which Namespace Holds The Browser Id
-++++++++++++++++++++++++++++++++++++++++++++++++
-
-For some applications, it is advantageous to know from which namespace (
-"cookies", "form", or "url") the browser id has been gathered.
-
-It should be noted that you can configure the browser_id_manager (its in Zope
-root by default) so that it searches whatever combination of namespaces you
-select.
-
-There are three methods of browser id managers which allow you to accomplish
-this::
-
-  <dtml-if "REQUEST.SESSION.getBrowserIdManager().isBrowserIdFromCookie()">
-      The browser id came from a cookie.
-  </dtml-if>
-
-  <dtml-if "REQUEST.SESSION.getBrowserIdManager().isBrowserIdFromForm()">
-      The browser id came from a form.
-  </dtml-if>
-
-  <dtml-if "REQUEST.SESSION.getBrowserIdManager().isBrowserIdFromUrl()">
-      The browser id came from the URL.
-  </dtml-if>
-
-The::
-
-  isBrowserIdFromCookie()
-
-method will return true if the browser id in the current request comes from
-the::
-
-  REQUEST.cookies
-
-namespace. This is true if the browser id was sent to the Zope server as a
-cookie.
-
-The::
-
-  isBrowserIdFromForm()
-
-method will return true if the browser id in the current request comes from
-the::
-
-  REQUEST.form
-
-namespace. This is true if the browser id was sent to the Zope server encoded
-in a query string or as part of a form element.
-
-The::
-
-  isBrowserIdFromUrl()
-
-method will return true if the browser id in the current request comes from the
-leading elements of the URL.
-
-If a browser id doesn't actually exist in the current request when one of these
-methods is called, an error will be raised.
-
-During typical operations, you shouldn't need to use these methods, as you
-shouldn't care from which namespace the browser id was obtained. However, for
-highly customized applications, this set of methods may be useful.
-
-Obtaining the Browser Id Name/Value Pair and Embedding It Into A Form
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-You can obtain the browser id name from a browser id manager instance. We've
-already determined how to obtain the browser id itself. It is useful to also
-obtain the browser id name if you wish to embed a browser id name/value pair as
-a hidden form field for use in POST requests. Here's a TAL example::
-
-    <span tal:define="idManager python:request.SESSION.getBrowserIdManager()">
-        <form action="thenextmethod">
-            <input type=submit name="submit" value=" GO ">
-            <input type="hidden" name="name" value="value"
-                   tal:attributes="name python: idManager.getBrowserIdName();
-                                   value python: idManager.getBrowserId()">
-        </form>
-    </span>
-
-A convenience function exists for performing this action as a method of a
-browser id manager named "getHiddenFormField"::
-
-  <html>
-  <body>
-    <form action="thenextmethod">
-      <input type="submit" name="submit" value=" GO ">
-      <dtml-var "REQUEST.SESSION.getBrowserIdManager().getHiddenFormField()">
-    </form>
-  </body>
-  </html>
-
-When the above snippets are rendered, the resulting HTML will look something
-like this::
-
-  <html>
-  <body>
-    <form action="thenextmethod">
-      <input type="submit" name="submit" value=" GO ">
-      <input type="hidden" name="_ZopeId" value="9as09a7fs70y1j2hd7at8g">
-    </form>
-  </body>
-  </html>
-
-Note that to maintain state across requests when using a form submission, even
-if you've got
-
-- Automatically Encode
-- Zope-Generated URLs With a Browser Id
-
-checked off in your browser id manager, you'll either need to encode the form
-"action" URL with a browser id (see "Embedding A Browser Id Into An HTML Link"
-below) or embed a hidden form field.
-
-Using formvar-based sessioning.
-+++++++++++++++++++++++++++++++
-
-To use formvar-based sessioning, you need to encode a link to its URL with the
-browser id by using the browser id manager's::
-
-  encodeUrl()
-
-method.
-
-Determining Whether A Browser Id is "New"
-+++++++++++++++++++++++++++++++++++++++++
-
-A browser id is "new" if it has been set in the current request but has not yet
-been acknowledged by the client. "Not acknowledged by the client" means it has
-not been sent back by the client in a request. This is the case when a new
-browser id is created by the sessioning machinery due to a reference to
-REQUEST.SESSION or similar as opposed to being received by the sessioning
-machinery in a browser id name namespace. You can use the::
-
-  isBrowserIdNew()
-
-method of a browser id manager to determine whether the session is new::
-
-  <dtml-if "REQUEST.SESSION.getBrowserIdManager().isBrowserIdNew()">
-      Browser id is new.
-  <dtml-else>
-      Browser id is not new.
-  </dtml-if>
-
-This method may be useful in cases where applications wish to prevent or detect
-the regeneration of new browser ids when the same client visits repeatedly
-without sending back a browser id in the request (such as may be the case when
-a visitor has cookies "turned off" in their browser and the browser id manager
-only uses cookies).
-
-If there is no browser id associated with the current request, this method will
-raise an error.
-
-You shouldn't need to use this method during typical operations, but it may be
-useful in advanced applications.
-
-
-Determining Whether A Session Data Object Exists For The Browser Id Associated With This Request
-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-If you wish to determine whether a session data object with a key that is the
-current request's browser id exists in the session data manager's associated
-session data container, you can use the::
-
-  hasSessionData()
-
-method of the session data manager. This method returns true if there is
-session data associated with the current browser id::
-
-  <dtml-if "session_data_manager.hasSessionData()">
-    The sessiondatamanager object has session data for the browser id
-    associated with this request.
-  <dtml-else>
-    The sessiondatamanager object does not have session data for
-    the browser id associated with this request.
-  </dtml-if>
-
-The::
-
-  hasSessionData()
-
-method is useful in highly customized applications, but is probably less useful
-otherwise. It is recommended that you use REQUEST.SESSION instead, allowing the
-session data manager to determine whether or not to create a new data object
-for the current request.
-
-Embedding A Browser Id Into An HTML Link
-++++++++++++++++++++++++++++++++++++++++
-
-You can embed the browser id name/value pair into an HTML link for use during
-HTTP GET requests. When a user clicks on a link with a URL encoded with the
-browser id, the browser id will be passed back to the server in the
-REQUEST.form namespace. If you wish to use formvar-based session tracking, you
-will need to encode all of your "public" HTML links this way. You can use the::
-
-  encodeUrl()
-
-method of browser id managers in order to perform this encoding::
-
-  <html>
-  <body>
-    <a href="<dtml-var "REQUEST.SESSION.getBrowserIdManager().encodeUrl('/amethod')">">
-      Here
-    </a>
-    is a link.
-  </body>
-  </html>
-
-The above dtml snippet will encode the URL "/amethod" (the target of the word
-"Here") with the browser id name/value pair appended as a query string. The
-rendered output of this DTML snippet would look something like this::
-
-  <html>
-  <body>
-    <a href="/amethod?_ZopeId=7HJhy78978979JHK">Here</a>
-    is a link.
-  </body>
-  </html>
-
-You may successfully pass URLs which already contain query strings to the::
-
-  encodeUrl()
-
-method. The encodeUrl method will preserve the existing query string and append
-its own name/value pair.
-
-You may choose to encode the browser id into the URL using an "inline" style if
-you're checking for browser ids in the URL (e.g. if you've checked::
-
-  URLs
-
-in the "Look for Browser Id in" form element of your browser id manager)::
-
-  <html>
-  <body>
-    <a href="<dtml-var "REQUEST.SESSION.getBrowserIdManager().encodeUrl('/amethod', style='inline')">">Here</a>
-    is a link.
-  </body>
-  </html>
-
-The above dtml snippet will encode the URL "/amethod" (the target of the word
-"Here") with the browser id name/value pair embedded as the first two elements
-of the URL itself. The rendered output of this DTML snippet would look
-something like this::
-
-  <html>
-  <body>
-    <a href="/_ZopeId/7HJhy78978979JHK/amethod">Here</a>
-    is a link.
-  </body>
-  </html>
-
-Using Session onAdd and onDelete Events
-+++++++++++++++++++++++++++++++++++++++
-
-The configuration of a Transient Object Container (aka a session data
-container) allows a method to be called when a session data object is created
-(onAdd) or when it is invalidated or timed out (onDelete).
-
-The events are independent of each other. You might want an onAdd method but
-not an onDelete method. You may define one, both or none of the TOC event
-methods.
-
-Here are examples of the kinds of things Session onAdd and onDelete methods are
-used to do:
-
-- The onAdd method can be used to populate a session data object with "default"
-  values before it's used by application code.
-
-- The onDelete method can write the contents of a session data object out to a
-  permanent data store before it is timed out or invalidated.
-
-You can manually configure the onAdd and onDelete methods. Click the
-*management tab* of '\temp_folder\session_data. Enter "a physical path" to
-either a an external method or python script. NOTE: This configuration is only
-good until the next Zope shutdown because::
-
-  \temp_folder\session_data
-
-is in a RAM database, Configure the onAdd and onDelete methods for this data
-container via the::
-
-  zope.conf
-
-configuration file for your Zope instance. This is covered in some detail in
-*Setting Initial Transient Object Container Parameters* later in this document.
-
-Note: the onAdd and onDelete events do not raise exceptions if logic in the
-method code fails. Instead, an error is logged in the Zope event log. In recent
-versions of Zope, the event.log defaults to Zope-Instance/log/event.log. This
-is configurable in::
-
-  zope.conf
-
-Writing onAdd and onDelete Methods
-++++++++++++++++++++++++++++++++++
-
-Session data objects optionally call a Zope method when they are created and
-when they are timed out or invalidated.
-
-Specially-written Script (Python) scripts can be written to serve the purpose
-of being called on session data object creation and invalidation.
-
-The Script (Python) should define two arguments, "sdo" and "toc". "sdo"
-represents the session data object being created or terminated, and "toc"
-represents the transient object container in which this object is stored.
-
-For example, to create a method to handle a session data object onAdd event
-which prepopulates the session data object with a DateTime object, you might
-write a Script (Python) named::
-
-  onAdd
-
-which had function parameters "sdo" and "toc" and a body of::
-
-  sdo['date'] = context.ZopeTime()
-
-If you set the path to this method as the onAdd event, before any application
-handles the new session data object, it will be prepopulated with a key::
-
-  date
-
-that has the value of a DateTime object set to the current time.
-
-To create a method to handle a session onDelete event which writes a log
-message, you might write an External Method with the following body::
-
-  from zLOG import LOG, WARNING
-  def onDelete(sdo, toc):
-      logged_out = sdo.get('logged_out', None)
-      if logged_out is None:
-          LOG('session end', WARNING,
-              'session ended without user logging out!')
-
-If you set the path to this method as the onDelete event, a message will be
-logged if the::
-
-  logged_out
-
-key is not found in the session data object.
-
-Note that for onDelete events, there is no guarantee that the onDelete event
-will be called in the context of the user who originated the session! Due to
-the "expire-after-so-many-minutes-of-inactivity" behavior of session data
-containers, a session data object onDelete event initiated by one user may be
-called while a completely different user is visiting the application. Your
-onDelete event method should not naively make any assumptions about user state.
-For example, the result of the Zope call "getSecurityManager().getUser()" in an
-onDelete session event method will almost surely *not* be the user who
-originated the session.
-
-The session data object onAdd method will always be called in the context of
-the user who starts the session.
-
-For both onAdd and onDelete events, it is almost always desirable to set proxy
-roles on event methods to replace the roles granted to the executing user when
-the method is called because the executing user will likely not be the user for
-whom the session data object was generated. For more information about proxy
-roles, see the chapter entitled `Users and Security <Security.stx>`_.
-
-For additional information about using session onDelete events in combination
-with data object timeouts, see the section entitled "Session Data Object
-Expiration Considerations" in the Concepts and Caveats section below.
-
-
-Configuration and Operation
-===========================
-
-Setting the default Transient Object Container Parameters
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-Click on::
-
-  /temp_folder/session_data
-
-and you'll see options to control inactivity time-outs and the maximum
-allowable number of Session objects. You can even include paths to python
-scripts that handle a Session's after-add and before-delete events.
-
-Because::
-
-  /temp_folder/session_data
-
-is stored in a RAM database, it disappears and is recreated after each restart
-of your Zope server. This means that any changes to parameters will be lost the
-next time you restart your Zope server.
-
-If you need to permanently alter the default Transient Object Container's
-configuration you must edit Zope's startup configuration file::
-
-  zope.conf
-
-Note that additional Transient Object Containers can be instantiated in
-permanent storage. They are rarely needed. If you do need this its covered in
-detail later in this document.
-
-Here is the relevant portion of zope.conf::
-
-  # Directive: maximum-number-of-session-objects
-  # Description: An integer value representing the maximum number 
-  #              of subobjects" 
-  # allowable in the '/temp_folder/session_data' transient object container.
-  #         
-  # Default: 1000
-  # Example: maximum-number-of-session-objects 10000
-
-  # Directive: session-add-notify-script-path
-  #
-  # Description:
-  #     An optional fill Zope path name of a callable object to be set as the
-  #     "script to call on object addition" of the session_data transient
-  #     object container created in the /temp_folder folder at startup.
-  #
-  # Default: unset
-  # Example: session-add-notify-script-path /scripts/add_notifier
-
-  # Directive: session-delete-notify-script-path
-  #
-
-  # Description:
-  #     An optional fill Zope path name of a callable object to be set as the
-  #     "script to call on object deletion" of the session_data transient
-  #     object container created in the /temp_folder folder at startup.
-  #
-  # Default: unset
-  # Example: session-delete-notify-script-path /scripts/del_notifier
-
-  # Directive: session-timeout-minutes
-  #
-  # Description:
-  #     An integer value representing the number of minutes to be used as the
-  #     "data object timeout" of the '/temp_folder/session_data' transient
-  #     object container.
-  #
-  # Default: 20
-  # Example: session-timeout-minutes 30
-
-  # Directive: session-resolution-seconds
-  #
-  # Description:
-  #    An integer value representing the number of seconds to be used as the
-  #    "timeout resolution" of the '/temp_folder/session_data' transient
-  #    object container.
-  #
-  # Default: 20
-  # Example: session-resolution-seconds 60
-
-Instantiating Multiple Browser Id Managers (Optional)
-+++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-Transient data objects depend on a session data manager, which in turn depends
-on a browser id manager. A browser id manager doles out and otherwise manages
-browser ids. All session data managers need to talk to a browser id manager to
-get browser id information.
-
-You needn't create a browser id manager to use sessioning. One is already
-created as a result of the initial Zope installation. If you've got special
-needs, you may want to instantiate more than one browser id manager. Having
-multiple browser id managers may be useful in cases where you have a "secure"
-section of a site and an "insecure" section of a site, each using a different
-browser id manager with respectively restrictive security settings.
-
-In the container of your choosing, select "Browser Id Manager" from the add
-drop-down list in the Zope management interface. When you add a new browser id
-manager, the form options available are:
-
-Id
-  You cannot choose an id for your browser id manager. It must always be
-  "browser_id_manager". Additionally, you cannot rename a browser id manager.
-  This is required in the current implementation so that session data managers
-  can find session id managers via Zope acquisition.
-
-Title
-  the browser id manager title.
-
-Browser Id Name
-  the name used to look up the value of the browser id. This will be the name
-  looked up in the `cookies` or `form` REQUEST namespaces when the browser id
-  manager attempts to find a cookie, form variable, or URL with a browser id in
-  it.
-
-Look for Browser Id Name In
-  choose the request elements to look in when searching for the browser id
-  name. You may choose "cookies", "Forms and Query Strings", and "URLs".
-
-Automatically Encode Zope-Generated URLs With A Browser Id
-
-  if this option is checked, all URLs generated by Zope (such as URLs obtained
-  via the `absolute_url` method of all Zope objects) will have a browser id
-  name/value pair embedded within them. This typically only make sense if
-  you've also got the `URLs` setting of "Look for Browser Id in" checked off.
-
-Cookie Path
-  this is the `path` element which should be sent in the browser id cookie.
-
-Cookie Domain
-  this is the "domain" element which should be sent in the browser id cookie.
-  Leaving this form element blank results in no domain element in the cookie.
-  If you change the cookie domain here, the value you enter must have at least
-  two dots (as per the cookie spec).
-
-Cookie Lifetime In Days
-  browser id cookies sent to browsers will last this many days on a remote
-  system before expiring if this value is set. If this value is 0, cookies will
-  persist on client browsers for only as long as the browser is open.
-
-Only Send Cookie Over HTTPS
-
-  if this flag is set, only send cookies to remote browsers if they're
-  communicating with us over https. The browser id cookie sent under this
-  circumstance will also have the `secure` flag set in it, which the remote
-  browser should interpret as a request to refrain from sending the cookie back
-  to the server over an insecure (non-https) connection. NOTE: In the case you
-  wish to share browser id cookies between https and non-https connections from
-  the same browser, do not set this flag.
-
-After reviewing and changing these options, click the "Add" button to
-instantiate a browser id manager. You can change any of a browser id manager's
-initial settings by visiting it in the management interface.
-
-Instantiating A Session Data Manager (Optional)
-+++++++++++++++++++++++++++++++++++++++++++++++
-
-After instantiating at least one browser id manager, it's possible to
-instantiate a session data manager. You don't need to do this in order to begin
-using Zope's sessioning machinery, as a default session data manager is created
-as::
-
-  /session_data_manager
-
-You can place a session data manager in any Zope container,as long as a browser
-id manager object named::
-
-  browser_id_manager
-
-can be acquired from that container. The session data manager will use the
-first acquired browser id manager.
-
-Choose "Session Data Manager" within the container you wish to house the
-session data manager from the "Add" drop-down box in the Zope management
-interface.
-
-The session data manager add form displays these options:
-
-Id
-  choose an id for the session data manager
-
-Title
-  choose a title for the session data manager
-
-Transient Object Container Path
-  enter the Zope path to a Transient Object Container in this text box in order
-  to use it to store your session data objects. Note: session manager's should
-  not share transient object paths. This is an example path:
-
-  Zope transient object container is::
-
-    /MyTransientSessionFolder
-
-After reviewing and changing these options, click the "Add" button to
-instantiate a session data manager.
-
-You can manage a session data manager by visiting it in the management
-interface. You may change all options available during the add process by doing
-this.
-
-Instantiating a Transient Object Container
-++++++++++++++++++++++++++++++++++++++++++
-
-The default transient object container at::
-
-  /temp_folder/session_data
-
-stores its objects in RAM, so these objects and their data disappear when you
-restart Zope.
-
-If you want your session data to persist across server reboots, or if you have
-a very large collection of session data objects, or if you'd like to share
-sessions between ZEO clients, you will want to instantiate a transient data
-container in a more permanent storage.
-
-A heavily-utilized transient object container *should be instantiated inside a
-database which is nonundoing*! Although you may instantiate a transient data
-container in any storage, if you make heavy use of an external session data
-container in an undoing database (such as the default Zope database which is
-backed by "FileStorage", an undoing and versioning storage), your database will
-grow in size very quickly due to the high-write nature of session tracking,
-forcing you to pack very often. You can "mount" additional storages within the
-`zope.conf` file of your Zope instance. The default `temp_folder` is mounted
-inside a `TemporaryStorage` , which is nonundoing and RAM-based. There are
-other nonundoing storages, such as BerkeleyStorage, although none quite as
-well-supported as TemporaryStorage.
-
-Here are descriptions of the add form of a Transient Object Container, which
-may be added by selecting "Transient Object Container" for the Zope Add list.:
-
-  Special note: When you add a transient object container to a non-RAM-based
-  storage, unlike the the default transient objects contained in temp_folder,
-  these instances of TOC maintain their parameter settings between Zope
-  Restarts. Importantly, they *do not* read zope.conf.
-
-Id
-  the id of the transient object container
-
-Title (optional)
-  the title of the transient object container
-
-Data object timeout in minutes
-  enter the number of minutes of inactivity which causes a contained transient
-  object be be timed out. "0" means no expiration.
-
-Maximum number of subobjects
-  enter the maximum number of transient objects that can be added to this
-  transient object container. This value helps prevent "denial of service"
-  attacks to your Zope site by effectively limiting the number of concurrent
-  sessions.
-
-Script to call upon object add (optional)
-  when a session starts, you may call an external method or Script (Python).
-  This is the Zope path to the external method or Script (Python) object to be
-  called. If you leave this option blank, no onAdd function will be called. An
-  example of a method path is `/afolder/amethod`.
-
-Script to call upon object delete (optional)
-  when a session ends, you may call an external method or Script (Python). This
-  is the Zope path to the external method or Script (Python) object to be
-  called. If you leave this option blank, no onDelete function will be called.
-  An example of a method path is `/afolder/amethod`.
-
-
-Multiple session data managers can make use of a single transient object
-container to the extent that they may share the session data objects placed in
-the container between them. This is not a recommended practice, however, as it
-has not been tested at all.
-
-The `data object timeout in minutes` value is the number of minutes that
-session data objects are to be kept since their last-accessed time before they
-are flushed from the data container. For instance, if a session data object is
-accessed at 1:00 pm, and if the timeout is set to 20 minutes, if the session
-data object is not accessed again by 1:19:59, it will be flushed from the data
-container at 1:20:00 or a time shortly thereafter. "Accessed", in this
-terminology, means "pulled out of the container" by a call to the session data
-manager's getSessionData() method or an equivalent (e.g. a reference to
-REQUEST.SESSION). See "Session Data Object Expiration Considerations" in the
-*Concepts and Caveats* section below for details on session data expiration.
-
-Configuring Sessioning Permissions
-++++++++++++++++++++++++++++++++++
-
-You need only configure sessioning permissions if your requirements deviate
-substantially from the norm. In this case, here is a description of the
-permissions related to sessioning.
-
-Permissions related to browser id managers
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Add Browser Id Manager
-  allows a role to add browser id managers. By default, enabled for `Manager`.
-
-Change Browser Id Manager
-  allows a role to change an instance of a browser id manager. By default,
-  enabled for `Manager`.
-
-Access contents information
-  allows a role to obtain data about browser ids. By default, enabled for
-  `Manager` and `Anonymous`.
-
-
-Permissions related to session data managers:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Add Session Data Manager
-  allows a role to add session data managers. By default, enabled for
-  `Manager`.
-
-Change Session Data Manager
-  allows a role to call management-related methods of a session data manager.
-  By default, enabled for `Manager`.
-
-Access session data
-  allows a role to obtain access to the session data object related to the
-  current browser id. By default, enabled for `Manager` and `Anonymous`. You
-  may wish to deny this permission to roles who have DTML or Web-based Python
-  scripting capabilities who should not be able to access session data.
-
-Access arbitrary user session data
-  allows a role to obtain and otherwise manipulate any session data object for
-  which the browser id is known. By default, enabled for `Manager`.
-
-Access contents information
-  allows a role to obtain data about session data. By default, enabled for
-  `Manager` and `Anonymous`.
-
-Permissions related to transient object containers:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Add Transient Object Container
-  allows a role to add transient objects containers. By default, enabled for
-  `Manager`.
-
-Change Transient Object Container
-  allows a role to make changes to a transient object container.
-
-Access Transient Objects
-  allows a role to obtain and otherwise manipulate the transient object related
-  to the current browser id.
-
-Concepts and Caveats
-====================
-
-Security Considerations
-+++++++++++++++++++++++
-
-Sessions are insecure by their very nature. If an attacker gets a hold of
-someone's browser id, and if they can construct a cookie or use form elements
-or URL elements to pose as that user from their own browser, they will have
-access to all information in that user's session. Sessions are not a
-replacement for authentication for this reason.
-
-Ideally, you'd like to make certain that nobody but the user its intended for
-gets a hold of his browser id. To take steps in this direction, and if you're
-truly concerned about security, you will ensure that you use cookies to
-maintain browser id information, and you will secure the link between your
-users and your site using SSL. In this configuration, it is more difficult to
-"steal" browser id information as the browser id will not be evident in the URL
-and it will be very difficult for attackers to "tap" the encrypted link between
-the browser and the Zope site.
-
-There are significant additional risks to user privacy in employing sessions in
-your application, especially if you use URL-based or formvar-based browser ids.
-Commonly, a browser id is embedded into a form/querystring or a URL in order to
-service users who don't have cookies turned on.
-
-For example, this kind of bug was present until recently in a lot of webmail
-applications: if you sent a mail to someone that included a link to a site
-whose logs you could read, and the user clicked on the link in his webmail
-page, the full URL of the page, including the authentication (stored as session
-information in the URL) would be sent as a HTTP REFERER to your site.
-
-Nowadays all serious webmail applications either choose to store at least some
-of the authentication information outside of the URL (in a cookie for
-instance), or process all the user-originated URLs included in the mail to make
-them go through a redirection that sanitizes the HTTP REFERER.
-
-The moral of the story is: if you're going to use sessions to store sensitive
-information, and you link to external sites within your own site, you're best
-off using *only* cookie-based browser ids.
-
-Browser Id (Non-)Expiration
-+++++++++++++++++++++++++++
-
-A browser id will last as long as the browser id cookie persists on the client,
-or for as long as someone uses a bookmarked URL with a browser id encoded into
-it.
-
-The same id will be obtained by a browser id manager on every visit by that
-client to a site - potentially indefinitely depending on which conveyance
-mechanisms you use and your configuration for cookie persistence.
-
-The transient object container implements a policy for data object expiration.
-If asked for a session data object related to a particular browser id which has
-been expired by a session data container, a session data manager will a return
-a new session data object.
-
-Session Data Object Expiration Considerations
-+++++++++++++++++++++++++++++++++++++++++++++
-
-Session data objects expire after the period between their last access and
-"now" exceeds the timeout value provided to the session data container which
-hold them. No special action need be taken to expire session data objects.
-
-However, because Zope has no scheduling facility, the sessioning machinery
-depends on the continual exercising of itself to expire session data objects.
-If the sessioning machinery is not exercised continually, it's possible that
-session data objects will stick around longer than the time specified by their
-data container timeout value. For example:
-
-- User A exercises application machinery that generates a session data object.
-  It is inserted into a session data container which advertises a 20-minute
-  timeout.
-
-- User A "leaves" the site.
-
-- 40 minutes go by with no visitors to the site.
-
-- User B visits 60 minutes after User A first generated his session data
-  object, and exercises app code which hands out session data objects. - *User
-  A's session is expired at this point, 40 minutes "late".*
-
-As shown, the time between a session's onAdd and onDelete is not by any means
-*guaranteed* to be anywhere close to the amount of time represented by the
-timeout value of its session data container. The timeout value of the data
-container should only be considered a "target" value.
-
-Additionally, even when continually exercised, the sessioning machinery has a
-built in error potential of roughly 20% with respect to expiration of session
-data objects to reduce resource requirements. This means, for example, if a
-transient object container timeout is set to 20 minutes, data objects added to
-it may expire anywhere between 16 and 24 minutes after they are last accessed.
-
-Sessioning and Transactions
-+++++++++++++++++++++++++++
-
-Sessions interact with Zope's transaction system. If a transaction is aborted,
-the changes made to session data objects during the transaction will be rolled
-back.
-
-Mutable Data Stored Within Session Data Objects
-+++++++++++++++++++++++++++++++++++++++++++++++
-
-If you mutate an object stored as a value within a session data object, you'll
-need to notify the sessioning machinery that the object has changed by calling
-`set` or `__setitem__` on the session data object with the new object value.
-For example::
-
-  session = self.REQUEST.SESSION
-  foo = {}
-  foo['before'] = 1
-  session.set('foo', foo)
-
-  # mutate the dictionary
-
-  foo['after'] = 1
-
-  # performing session.get('foo') 10 minutes from now will likely
-  # return a dict with only 'before' within!
-
-You'll need to treat mutable objects immutably, instead. Here's an example that
-makes the intent of the last example work by doing so::
-
-  session = self.REQUEST.SESSION
-  foo = {}
-  foo['before'] = 1
-  session.set('foo', foo)
-
-  # mutate the dictionary
-  foo['after'] = 1
-
-  # tickle the persistence machinery
-  session.set('foo', foo)
-
-An easy-to-remember rule for manipulating data objects in session storage:
-always explicitly place an object back into session storage whenever you change
-it. For further reference, see the "Persistent Components" chapter of the Zope
-Developer's Guide at http://www.zope.org/Documentation/ZDG.
-
-session.invalidate() and stale references to the session object
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-This Python Script illustrates an issue with using the invalidate method of a
-session object::
-
-  request = container.REQUEST
-  session = request.SESSION
-  session.set('foo','bar')
-  session.invalidate() 
-  # ............................................
-  # we expect that invalidate() flushes the session 
-  # ............................................
-  print 'after invalidate()',session.get('foo') # 'bar' still prints!
-
-  # ............................................
-  # Even this isn't enough
-  # ............................................
-  session = request.SESSION
-  print 'after invalidate()', session.get('foo') # 'bar' still prints!
-
-  # ............................................
-  # Here's the work-around
-  # ............................................
-  session = context.session_data_manager.getSessionData()
-  print 'after getSessionData', session.get('foo') # 'bar' is GONE which is good
-  return printed
-
-In short, after using the `invalidate` method of a session object, the next
-reference to the session object you obtain should be through "getSessionData"
-rather than `REQUEST.SESSION`.
-
-Session Data Object Keys
-++++++++++++++++++++++++
-
-A session data object has essentially the same restrictions as a Python
-dictionary. Keys within a session data object must be hashable (strings,
-tuples, and other immutable basic Python types; or instances which have a
-__hash__ method). This is a requirement of all Python objects that are to be
-used as keys to a dictionary. For more information, see the associated Python
-documentation at http://www.python.org/doc/current/ref/types.html (Mappings ->
-Dictionaries).
-
-In-Memory Session Data Container RAM Utilization
-++++++++++++++++++++++++++++++++++++++++++++++++
-
-Each session data object which is added to an "internal" (RAM-based) session
-data container will consume at least 2K of RAM.
-
-Mounted Transient Object Container Caveats
-++++++++++++++++++++++++++++++++++++++++++
-
-Mounted TOC's do not acquire parameter's from zope.conf (which is the case for
-the default transient object container). Therefore you set parameters directly
-on the object in ZMI.
-
-Persistent objects which have references to other persistent objects in the
-same database cannot be committed into a mounted database because the ZODB does
-not currently handle cross-database references.
-
-Transient object containers which are sometimes stored in a "mounted" database
-(as is currently the case for the default ::
-
-  /temp_folder/session_data
-
-TOC. If you use a transient object container that is accessed via a "mounted"
-database, you cannot store persistent object instances which have already been
-stored in the "main" database as keys or values in a session data object. If
-you try to do so, it is likely that an ::
-
-  InvalidObjectReference
-
-exception will be raised by the ZODB when the transaction involving the object
-attempts to commit. As a result, the transaction will fail and the session data
-object (and other objects touched in the same transaction) will fail to be
-committed to storage.
-
-If your "main" ZODB database is backed by a nonundoing storage, you can avoid
-this condition by storing session data objects in an transient object container
-instantiated within the "main" ZODB database. If this is not an option, you
-should ensure that objects you store as values or keys in a session data object
-held in a mounted session data container are instantiated "from scratch" (via
-their constructors), as opposed to being "pulled out" of the main ZODB.
-
-Conflict Errors
-+++++++++++++++
-
-This session tracking software stores all session state in Zope's ZODB. The
-ZODB uses an optimistic concurrency strategy to maintain transactional
-integrity for simultaneous writes. This means that if two objects in the ZODB
-are changed at the same time by two different connections (site visitors) that
-a "ConflictError" will be raised. Zope retries requests that raise a
-ConflictError at most 3 times. If your site is extremely busy, you may notice
-ConflictErrors in the Zope debug log (or they may be printed to the console
-from which you run Zope). An example of one of these errors is as follows::
-
-  2009-01-16T04:26:58 INFO(0) Z2 CONFLICT Competing writes at, /getData
-  Traceback (innermost last):
-  File /zope/lib/python/ZPublisher/Publish.py, line 175, in publish
-  File /zope/lib/python/Zope/__init__.py, line 235, in commit
-  File /zope/lib/python/ZODB/Transaction.py, line 251, in commit
-  File /zope/lib/python/ZODB/Connection.py, line 268, in commit
-  ConflictError: '\000\000\000\000\000\000\002/'
-
-Errors like this in your debug log (or console if you've not redirected debug
-logging to a file) are normal to an extent. If your site is undergoing heavy
-load, you can expect to see a ConflictError perhaps every 20 to 30 seconds. The
-requests which experience conflict errors will be retried automatically by
-Zope, and the end user should *never* see one. Generally, session data objects
-attempt to provide application-level conflict resolution to reduce the
-limitations imposed by conflict errors NOTE: to take advantage of this feature,
-you must store your transient object container in a storage such as FileStorage
-or TemporaryStorage which supports application-level conflict resolution.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/SimpleExamples.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/SimpleExamples.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/SimpleExamples.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,749 +0,0 @@
-Creating Basic Zope Applications
-================================
-
-.. todo:
-   
-   - add new screen shots
-
-This chapter will take you, step by step, through building a basic web
-application in Zope.  As we go through the chapter, we will examine some of
-Zope's main concepts at work.  Using Zope *Folder*, *Script (Python)*, and
-*Page Template* objects, we'll create a simple website for an imaginary
-zoo: the "Zope Zoo", of course!
-
-We will develop the website as a Zope "instance-space" application.  A
-discussion of instance space is at the end of this chapter, but for now it
-is enough to know that instance-space applications are the easiest and
-fastest kind to build, because we can do everything in our favorite web
-browser.
-
-Goals for the Zope Zoo Web Site
--------------------------------
-
-As with any project, we first need to clarify our goals for the Zope Zoo
-application.  The application's primary goal is to create a website for
-the world-renowned Zope Zoo.  Furthermore, we want to make the website
-easy to use and manage.  Here are some things we'll do:
-
-- Enable web users to navigate the site easily, as if they were moving
-  around a real zoo.
-
-- Keep all our shared web layout tools, like a Cascading Style Sheet
-  (CSS), in a single, easy-to-manage location.
-
-- Design the website so that future site-wide changes are quick and easy
-  to implement.
-
-- Take advantage of Zope to create a dynamic website in which web pages
-  build themselves "on the fly" when requested so that they are always up
-  to date.
-
-- Provide a simple file library of various documents that describe the
-  animals.
-
-Beginning with a Folder
------------------------
-
-Zope *Folder* objects provide natural containers and organizers for web
-applications.  A good way to start building an application is to create a
-new *Folder* to hold all the objects and subfolders related to the
-application.
-
-Consider, for example, a Zope folder named *Invoices* to hold an
-application for managing invoices through the Web.  The *Invoices* folder
-could contain both the logic objects - or "methods" - which allow you to
-add and edit invoices, as well as the actual data of the invoices.  The
-*Invoices* folder thus becomes a small Zope application.
-
-We begin building our Zope Zoo website application by creating a Zope
-*Folder* object to hold it all together in one place.
-
-Step 1: Create *ZopeZoo* Folder
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you haven't already, start your Zope installation and log into the Zope
-Management Interface (ZMI) using your favorite browser.  (If you are not
-familiar with the ZMI, refer to the `Installing and Starting Zope
-<InstallingZope.html>`_ chapter.)
-
-1. Navigate to Zope's top-level *root* folder.
-
-2. Use the *Add* list to create a new *Folder*.
-
-3. Give the new folder the *Id* 'ZopeZoo'.
-
-4. Check *Create public interface*.
-
-5. Click *Add*.
-
-(For now, we will ignore the optional *Title* fields.)
-
-Designing a Navigable Zoo
--------------------------
-
-One of our goals is to enable easy user movement around the website.  A key
-to this easy movement is a navigation interface that is consistent among
-the site's pages.  In other words, every web page in the site should
-present a similar set of hyperlinks, in a similar place on the page, on
-which users can rely to guide them through the site.
-
-We also want to make sure the navigation links are always correct,
-regardless of how the structure of the site changes.  The solution is to
-design a meaningful site structure, and then create the Zope methods that
-will dynamically present the current structure to web users in the form of
-navigation links.
-
-First, let's define the site structure.  If the Zope Zoo was real, we might
-model the website's organization on the zoo's physical or logical design.
-For our purposes, we will pretend that the zoo houses three classes of
-animals.  We'll organize the website by adding folders inside our *ZopeZoo*
-folder.
-
-Step 2: Create Site Organization
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Enter the *ZopeZoo* folder and create three subfolders with *Ids*:
-   'Reptiles', 'Mammals' and 'Fish'.
-
-2. Inside the *Mammals* folder, add one folder named 'Whales'.
-
-3. Navigate to the *Reptiles* folder and create two folders there:
-   'Lizards' and 'Snakes'.
-
-In Zope's Navigator frame on the left side, you should see an icon for the
-*ZopeZoo* folder.  (If you don't see it, click *Refresh* in the Navigator).
-To view the *ZopeZoo* folder hierarchy - i.e. our nascent web site's
-structure - expand the *ZopeZoo* folder by clicking the little plus sign
-next to the icon.  Similarly expand the zoo subfolders.  You'll see
-something like the figure below.
-
-.. figure:: ../Figures/zoo1.png
-
-   Zoo folder structure
-
-Now we create the basic presentation objects:  The main template and the
-style sheet *z_zoo.css*.  To get started, we ask a web designer to create a
-HTML mockup and a CSS file that together represent the web page layout
-shared throughout the site.
-
-For the style sheet we create a simple *File* object in Zope.  No need to
-make it dynamic.
-
-Step 3: Create the Style Sheet
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Go to the top level of our zoo website, the *ZopeZoo* folder.
-
-2. Select *File* from the *Add* list.
-
-3. Give the file an *Id* of 'z_zoo.css'.
-
-4. Click *Add*.
-
-5. Select *z_zoo.css* to get its *Edit* view.
-
-6. Copy and paste these style definitions into the *File Data* area::
-
-    body, p, th, td {
-      font-family: Verdana, Arial, Helvetica, sans-serif;
-      font-size: 10pt;
-    }
-    h1 {
-      color: #6699cc;
-      font-family: Verdana, Arial, Helvetica, sans-serif;
-      font-size: 18pt;
-      font-weight: bold;
-    }
-    p {
-      color: #660000;
-    }
-    .status_message{
-      background: #ffffaa;
-      border-style: solid;
-      border-width: thin;
-      font-weight: bold;
-      padding: 4pt;
-    }
-    th {
-      background: #dee7ec;
-      text-align: left;
-    }
-
-At this stage, the HTML page the web designer created for us is valid XHTML
-1.0 Strict and could also live in a static *File* object.  But in the next
-steps we will convert the page into a dynamic template by adding TAL and
-METAL statements, so we need a *Page Template* object.  For now we use the
-*index_html* method already added by selecting *Create public interface* in
-step 1.
-
-Step 4: Create the Main Template
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Select *index_html* to get its *Edit* view.
-
-2. Replace all of the stock template code with this::
-
-    <!DOCTYPE html PUBLIC
-        "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
-    <html>
-    <head>
-
-    <title>PAGE TITLE OR ID</title>
-    <link rel="stylesheet" href="z_zoo.css" type="text/css" />
-
-    </head>
-    <body>
-
-    <div>&gt; <a href="ABSOLUTE_URL">PARENT TITLE OR ID</a> </div>
-
-    <ul>
-      <li><a href="ABSOLUTE_URL">SUB-OBJECT TITLE OR ID</a></li>
-    </ul>
-
-    <h1>PAGE TITLE OR ID</h1>
-
-    <p class="status_message">STATUS MESSAGE</p>
-
-    <p>THIS IS WHERE THE PAGE'S CONTENT GOES.</p>
-
-    </body>
-    </html>
-
-Our web designer marked placeholders for dynamic elements with UPPERCASE
-letters.  Using the *Test* tab of the new template, we can see the static
-HTML page.  Don't blame the web designer for the spartan layout.  It's for
-the sake of an easy example.  If you don't understand the XHTML and CSS
-code you might want to learn more about HTML first.  This chapter shows you
-how to make that code dynamic.
-
-Step 5: Dynamic Title and Headline
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Go to the *Edit* tab of *index_html*.
-
-2. Find these two lines::
-
-    <title>PAGE TITLE OR ID</title>
-    ...
-    <h1>PAGE TITLE OR ID</h1>
-
-3. Change them to look like that::
-
-    <title tal:content="context/title_or_id">PAGE TITLE OR ID</title>
-    ...
-    <h1 tal:content="context/title_or_id">PAGE TITLE OR ID</h1>
-
-The *path expression* 'context/title_or_id' returns the *title* of the
-context object or - if that doesn't exist - its *id*.  We work in the
-context of the *ZopeZoo* folder, which has no title.  So clicking again on
-the *Test* tab you'll see that title and headline are replaced by the id
-*ZopeZoo*.  (You might want to open the *Test* tab in a new window to see
-the title of the browser window.)  After completing the next step you'll be
-able to navigate to subfolders and see title and headline change depending
-on the context.
-
-Step 6: Generate Subfolder Menu Dynamically
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Find the example menu item::
-
-    <ul>
-      <li><a href="ABSOLUTE_URL">SUB-OBJECT TITLE OR ID</a></li>
-    </ul>
-
-2. Extend it like this::
-
-    <ul tal:condition="python: context.objectValues(['Folder'])">
-      <li tal:repeat="item python: context.objectValues(['Folder'])">
-        <a href="ABSOLUTE_URL"
-           tal:attributes="href item/absolute_url"
-           tal:content="item/title_or_id">SUB-OBJECT TITLE OR ID</a></li>
-    </ul>
-
-The *Python expression* 'context.objectValues(['Folder'])' returns all the
-subfolders in our context.  The 'tal:condition' statement checks if any
-subfolders exist.  If not, the complete 'ul' element is removed.  That
-means we have reached a *leaf* of the navigation tree and don't need a
-subfolder menu.
- 
-Otherwise, the same expression in the 'tal:repeat' statement of the 'li'
-element will return a list of subfolders.  The 'li' element will be
-repeated for each *item* of this list.  In step 3 we created three
-subfolders in the *ZopeZoo* folder, so using again the *Test* tab we will
-see three list items, each with the correct id and link URL.  For now there
-are no links back, so use the back button of your browser if you can't wait
-exploring the site.
-
-Step 7: Generate Breadcrumbs Dynamically
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Look for this line::
-
-    <div>&gt; <a href="ABSOLUTE_URL">PARENT TITLE OR ID</a> </div>
-
-2. Replace it by::
-
-    <div><tal:loop tal:repeat="item python: request.PARENTS[-2::-1]">&gt;
-      <a href="ABSOLUTE_URL"
-         tal:attributes="href item/absolute_url"
-         tal:content="item/title_or_id">PARENT TITLE OR
-                                        ID</a> </tal:loop></div>
-
-Using a trail of bread crumbs for navigation is quite an old idea, you
-might remember Hansel and Gretel tried that to find their way home.  In our
-days, breadcrumbs are used for site navigation and show the path back to
-the root (or home) of the site.
-
-The folder that contains the current object is also called its *parent*.
-As long as we have not reached the root object, each folder has again a
-*parent* folder.  'request.PARENTS' is a list of all these parents from the
-current object down to the root object of the Zope application.
-'request.PARENTS[-2::-1]' returns a copy of that list in reverse order,
-starting with the second last element.  We don't need the last value
-because 'ZopeZoo' is located in the second level of our Zope application
-and we just want to navigate within the zoo.
-
-We use again a 'tal:repeat' statement to display the list.  Because we
-don't want to repeat the 'div' element, we add a dummy TAL element that
-doesn't show up in the rendered HTML page.  Now our site navigation is
-complete and you can explore the sections of the zoo.
-
-Step 8: Dynamic Status Bar
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Go to this line::
-
-    <p class="status_message">STATUS MESSAGE</p>
-
-2. Extend it by two tal attributes::
-
-    <p class="status_message"
-       tal:condition="options/status_message | nothing"
-       tal:content="options/status_message">STATUS MESSAGE</p>
-
-We need the status bar later in this chapter.  For now all we need is to
-make it invisible.  'options/status_message' will later be used for some
-messages.  But most pages don't have that variable at all and this path
-expression would raise an error.  'options/status_message | nothing'
-catches that error and falls back to the special  value *nothing*.  This is
-a common pattern to test if a value exists **and** is true.
-
-Step 9: Improve Style Sheet Link
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Find this line in the HTML head::
-
-    <link rel="stylesheet" href="z_zoo.css" type="text/css" />
-
-2. Replace it by::
-
-    <link rel="stylesheet" href="z_zoo.css" type="text/css"
-          tal:attributes="href context/z_zoo.css/absolute_url" />
-
-While the relative URI of the *href* attribute works thanks to acquisition,
-this isn't a good solution.  Using the *index_html* method for different
-folders, the browser can't know that all the *z_zoo.css* files are in fact
-one and the same.  Besides the CSS file the basic layout often contains a
-logo and other images, so making sure they are requested only once makes
-your site faster and you waste less bandwidth.  The *path expression*
-'context/z_zoo.css/absolute_url' returns the absolute url of the CSS file.
-Using it in the *href* attribute we have a unique URI independent of the
-current context.
-
-Step 10: Factor out Basic Look and Feel
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Rename *index_html* to 'z_zoo.pt'.
-
-2. Wrap a 'metal:define-macro' statement around the whole page and add
-   two 'metal:define-slot' statements for headline and content.  After
-   all these changes our main template - now called *z_zoo.pt* - looks
-   like this::
-
-    <metal:macro metal:define-macro="page"><!DOCTYPE html PUBLIC
-        "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
-    <html>
-    <head>
-
-    <title tal:content="context/title_or_id">PAGE TITLE OR ID</title>
-    <link rel="stylesheet" href="z_zoo.css" type="text/css"
-          tal:attributes="href context/z_zoo.css/absolute_url" />
-
-    </head>
-    <body>
-
-    <div><tal:loop tal:repeat="item python: request.PARENTS[-2::-1]">&gt;
-      <a href="ABSOLUTE_URL"
-         tal:attributes="href item/absolute_url"
-         tal:content="item/title_or_id">PARENT TITLE OR
-                                        ID</a> </tal:loop></div>
-
-    <ul tal:condition="python: context.objectValues(['Folder'])">
-      <li tal:repeat="item python: context.objectValues(['Folder'])">
-        <a href="ABSOLUTE_URL"
-           tal:attributes="href item/absolute_url"
-           tal:content="item/title_or_id">SUB-OBJECT TITLE OR ID</a></li>
-    </ul>
-
-    <metal:slot metal:define-slot="headline">
-
-      <h1 tal:content="context/title_or_id">PAGE TITLE OR ID</h1>
-
-    </metal:slot>
-
-    <p class="status_message"
-       tal:condition="options/status_message | nothing"
-       tal:content="options/status_message">STATUS MESSAGE</p>
-
-    <metal:slot metal:define-slot="content">
-
-      <p>THIS IS WHERE THE PAGE'S CONTENT GOES.</p>
-
-    </metal:slot>
-
-    </body>
-    </html>
-    </metal:macro>
-
-3. Add again a new *Page Template* with the *id* 'index_html'.
-
-4. Replace the example code of *index_html* with these two lines::
-
-    <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
-    </metal:macro>
-
-Transforming our main template into an external macro and including it
-again using the 'metal:use-macro' statement doesn't change the resulting
-HTML page in any way.  But in the next step we can add code we only want to
-use in *index_html* without changing the main template.
-
-The 'metal:define-macro' statement in *z_zoo.pt* marks the complete
-template as reuseable macro, giving it the *id* *page*.  The expression
-'context/z_zoo.pt/macros/page' in *index_html* points to that macro.
-
-For later use we also added two 'metal:define-slot' statements within the
-macro.  That allows to override *headline* and *body* while reusing the
-rest of the macro.
-
-Step 11: Add Special Front Page Code
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Go to the *Edit* tab of the new *index_html*.
-
-2. Replace it by this code::
-
-    <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
-    <metal:slot metal:fill-slot="headline">
-
-      <h1>Welcome to the Zope Zoo</h1>
-
-    </metal:slot>
-    <metal:slot metal:fill-slot="content">
-
-      <p>Here you will find all kinds of cool animals. You are in the
-        <b tal:content="context/title_or_id">TITLE OR ID</b> section.</p>
-
-    </metal:slot>
-    </metal:macro>
-
-The *index_html* should serve as the welcome screen for zoo visitors.  In
-order to do so, we override the default slots.  Take a look at how your
-site appears by clicking on the *View* tab of the *ZopeZoo* folder.
-
-You can use the navigation links to travel through the various sections of
-the Zoo.  Use this navigation interface to find the reptiles section.  Zope
-builds this page to display a folder by looking for the default folder view
-method, *index_html*.  It walks up the zoo site folder by folder until it
-finds the *index_html* method in the *ZopeZoo* folder.  It then calls this
-method on the *Reptiles* folder.
-
-Modifying a Subsection of the Site
-----------------------------------
-
-What if you want the reptile page to display something besides the welcome
-message?  You can replace the *index_html* method in the reptile section
-with a more appropriate display method and still take advantage of the main
-template including navigation.
-
-Step 12: Create *index_html* for the Reptile House
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Go to the *Reptile* folder.
-
-2. Add a new *Page Template* named 'index_html'.
-
-3. Give it some content more appropriate to reptiles::
-
-    <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
-    <metal:slot metal:fill-slot="headline">
-
-      <h1>The Reptile House</h1>
-
-    </metal:slot>
-    <metal:slot metal:fill-slot="content">
-
-      <p>Welcome to the Reptile House.</p>
-
-      <p>We are open from 6pm to midnight Monday through Friday.</p>
-
-    </metal:slot>
-    </metal:macro>
-
-Now take a look at the reptile page by going to the *Reptile* folder and
-clicking the *View* tab.
-
-Since the *index_html* method in the *Reptile* folder uses the same macro
-as the main *index_html*, the reptile page still includes your navigation
-system.
-
-Click on the *Snakes* link on the reptile page to see what the Snakes
-section looks like.  The snakes page looks like the *Reptiles* page because
-the *Snakes* folder acquires its *index_html* display method from the
-*Reptiles* folder instead of from the *ZopeZoo* folder.
-
-Creating a File Library
------------------------
-
-File libraries are common on websites since many sites distribute files of
-some sort.  The old fashioned way to create a file library is to upload
-your files, then create a web page that contains links to those files.
-With Zope you can dynamically create links to files.  When you upload,
-change or delete files, the file library's links can change automatically.
-
-Step 13: Creating Library Folder and some Files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Add a new *Folder* to *ZopeZoo* with *Id* 'Files' and *Title* 'File
-   Library'.
-
-2. Within that folder, add two *File* objects called 'DogGrooming' and
-   'HomeScienceExperiments'.
-
-We don't need any content within the files to test the library.  Feel
-free to add some more files and upload some content.
-
-Step 14: Adding *index_html* Script and Template
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Within the *Files* folder, add this new *Script (Python)* with the
-   *Id* 'index_html'::
-
-    ## Script (Python) "index_html"
-    ##parameters=
-    ##
-    library_items = []
-    items = context.objectValues(['File'])
-    for item in items:
-        library_items.append(
-                { 'title': item.title_or_id(),
-                  'url': item.absolute_url(),
-                  'modified': item.bobobase_modification_time().aCommon()
-                  } )
-
-    options = { 'library_items': tuple(library_items) }
-
-    return options
-
-2. Also add a new *Page Template* named 'index_html.pt' with this
-   content::
-
-    <metal:macro metal:use-macro="context/z_zoo.pt/macros/page">
-    <metal:slot metal:fill-slot="content">
-
-      <table>
-        <tr>
-          <th width="300">File</th>
-          <th>Last Modified</th>
-        </tr>
-        <tr>
-          <td><a href="URL">TITLE</a></td>
-          <td>MON DD, YYYY H:MM AM</td>
-        </tr>
-      </table>
-
-    </metal:slot>
-    </metal:macro>
-
-This time the logic for our 'index_html' method will be more complex, so we
-should separate logic from presentation.  We start with two unconnected
-objects:  A *Script (Python)* to generate the results and a *Page Template*
-to present them as HTML page.
-
-The script loops over 'context.objectValues(['File'])', a list of all
-*File* objects in our *Files* folder, and appends for each file the needed
-values to the library_items list.  Again the dynamic values are UPPERCASE
-in our mockup, so what we need are the file *title*, the *url* and the last
-*modified* date in a format like this: Mar 1, 1997 1:45 pm.  Most Zope
-objects have the *bobobase_modification_time* method that returns a
-*DateTime* object.  Looking at the API of *DateTime*, you'll find that the
-*aCommon* method returns the format we want.
-
-Later we will have more return values, so we store them in the *options*
-dictionary.  Using the *Test* tab of the script you will see the returned
-dictionary contains all the dynamic content needed by our template.
-
-The template uses again the *page* macro of *z_zoo.pt*.  Unlike before
-there is only one 'metal:fill-slot' statement because we don't want to
-override the *headline* slot.  Go to the *Test* tab of the template to see
-how our file library will look like.
-
-Step 15: Bringing Things Together
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Replace the last line of the *index_html* script by this one::
-
-    return getattr(context, 'index_html.pt')(**options)
-
-2. Look for this example table row in *index_html.pt*::
-
-      <tr>
-        <td><a href="URL">TITLE</a></td>
-        <td>MON DD, YYYY H:MM AM</td>
-      </tr>
-
-3. Replace it by that code::
-
-      <tr tal:repeat="item options/library_items">
-        <td><a href="URL"
-               tal:attributes="href item/url"
-               tal:content="item/title">TITLE</a></td>
-        <td tal:content="item/modified">MON DD, YYYY H:MM AM</td>
-      </tr>
-
-Now our script calls the *index_html.pt* after doing all the computing and
-passes the resulting *options* dictionary to the template, which creates
-the HTML presentation of *options*.  The *Test* tab of the template no
-longer works because it now depends on the script.  Go to the *Test* tab of
-the script to see the result: The file library!
-
-If you add another file, Zope will dynamically adjust the file library
-page.  You may also want to try changing the titles of the files, uploading
-new files, or deleting some of the files.
-
-Step 16: Making the Library Sortable
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Find the table headers in *index_html.pt*::
-
-        <th width="300">File</th>
-        <th>Last Modified</th>
-
-2. Replace them with these dynamic table headers::
-
-        <th width="300"><a href="SORT_TITLE_URL"
-               tal:omit-tag="not: options/sort_title_url"
-               tal:attributes="href options/sort_title_url"
-               >File</a></th>
-        <th><a href="SORT_MODIFIED_URL"
-               tal:omit-tag="not: options/sort_modified_url"
-               tal:attributes="href options/sort_modified_url"
-               >Last Modified</a></th>
-
-3. Extend *index_html* to make it look like this::
-
-    ## Script (Python) "index_html"
-    ##parameters=sort='title'
-    ##
-    library_items = []
-    items = context.objectValues(['File'])
-    if sort == 'title':
-        sort_on = ( ('title_or_id', 'cmp', 'asc'), )
-        sort_title_url = ''
-        sort_modified_url = '%s?sort=modified' % context.absolute_url()
-    else:
-        sort_on = ( ('bobobase_modification_time', 'cmp', 'desc'), )
-        sort_title_url = '%s?sort=title' % context.absolute_url()
-        sort_modified_url = ''
-    items = sequence.sort(items, sort_on)
-    for item in items:
-        library_items.append(
-                { 'title': item.title_or_id(),
-                  'url': item.absolute_url(),
-                  'modified': item.bobobase_modification_time().aCommon()
-                  } )
-
-    options = { 'sort_title_url': sort_title_url,
-                'sort_modified_url': sort_modified_url,
-                'library_items': tuple(library_items) }
-
-    return getattr(context, 'index_html.pt')(**options)
-
-The changes in the template are quite simple.  If an url is provided, the
-column header becomes a link.  If not, the 'not:' expression of the
-'tal:omit-tag' statement is true and the 'a' tag is omitted.  The script
-will always provide an url for the column that isn't currently sorted.
-
-Basically we have to extend the logic, so most changes are in the script.
-First of all we define an optional parameter *sort*.  By default it is
-'title', so if no value is passed in we sort by title.  Sort criteria and
-urls depend on the sort parameter.  We use the sort function of the built
-in *sequence* module to apply the sort criteria to the *items* list.
-
-Now view the file library and click on the *File* and *Last Modified* links
-to sort the files.  If there is a *sort* variable and if it has a value of
-*modified* then the files are sorted by modification time.  Otherwise the
-files are sorted by *title*.
-
-Building "Instance-Space" Applications
---------------------------------------
-
-In Zope, there are a few ways to develop a web application.  The simplest
-and fastest way, and the one we've been concentrating on thus far in this
-book, is to build an application in *instance space*.  To understand the
-term "instance space", we need to once again put on our "object orientation
-hats".
-
-When you create Zope objects by selecting them from the Zope "Add" list,
-you are creating *instances* of a *class* defined by someone else (see the
-`Object Orientation <ObjectOrientation.html>`_ chapter if you need to brush
-up on these terms).  For example, when you add a Script (Python) object to
-your Zope database, you are creating an instance of the Script (Python)
-class.  The Script (Python) class was written by a Zope Corporation
-engineer.  When you select "Script (Python)" from the Add list, and you
-fill in the form to give an id and title and whatnot, and click the submit
-button on the form, Zope creates an *instance* of that class in the Folder
-of your choosing.  Instances such as these are inserted into your Zope
-database and they live there until you delete them.
-
-In the Zope application server, most object instances serve to perform
-presentation duties, logic duties, or content duties.  You can "glue" these
-instances together to create basic Zope applications.  Since these objects
-are really instances of a class, the term "instance space" is commonly used
-to describe the Zope root folder and all of its subfolders.  "Building an
-application in instance space" is defined as the act of creating Zope
-object instances in this space and modifying them to act a certain way when
-they are executed.
-
-Instance-space applications are typically created from common Zope objects.
-Script (Python) objects, Folders, Page Templates, and other Zope services can
-be glued together to build simple applications.
-
-Instance-Space Applications vs. Python packages
------------------------------------------------
-
-In contrast to building applications in instance space, you may also build
-applications in Zope by building them as Python packages.  Building an
-application as a package differs from creating applications in instance
-space inasmuch as the act of creating a package typically is more familiar to
-developers and does not constrain them in any way.
-
-Building a package also typically allows you to more easily distribute an
-application to other people, and allows you to build objects that may more
-closely resemble your "problem space".
-
-Building a package is typically more complicated than building an
-"instance-space" application, so we get started here by describing how to
-build instance-space applications.  When you find that it becomes difficult
-to maintain, extend, or distribute an instance-space application you've
-written, it's probably time to reconsider rewriting it as a package.
-
-The Next Step
--------------
-
-This chapter shows how simple web applications can be made.  Zope has many
-more features in addition to these, but these simple examples should get
-you started on create well managed, complex websites.
-
-In the next chapter, we'll see how the Zope security system lets Zope work
-with many different users at the same time and allows them to collaborate
-together on the same projects.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/UsingZope.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/UsingZope.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/UsingZope.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,429 +0,0 @@
-Using the Zope Management Interface
-===================================
-
-Introduction
-------------
-
-When you log in to Zope, you are presented with the Zope Management
-Interface (ZMI).  The ZMI is a management and configuration environment that
-allows you to control Zope, manipulate Zope objects, and configure web
-applications.
-
-The Zope Management Interface represents a view into the Zope *object
-hierarchy*.  Almost every link or button in the ZMI represents an action
-that is taken against an *object*.  When you build web applications with
-Zope, you typically spend some of your time creating and managing objects.
-
-Don't be frightened if you don't understand the word "object" just yet.
-For the purposes of this chapter, the definition of an "object" is *any
-discrete item that is manageable through the ZMI*.  In fact, for the
-purposes of this chapter, you can safely replace the word "object" with the
-word "thing" with no ill effects.  If you do find something confusing,
-however, you may want to review the `Object
-Orientation <ObjectOrientation.html>`_ chapter for more detail on objects.
-
-How the Zope Management Interface Relates to Objects
-----------------------------------------------------
-
-Unlike web server applications like Apache or Microsoft IIS, Zope does not
-"serve up" HTML files that it finds on your server's hard drive.
-Similarly, the objects that Zope creates are not stored in ".html" files on
-your server.  There is no file hierarchy on your server's computer that
-contains all of your Zope objects.
-
-Instead, the objects that Zope creates are stored in a database called the
-"Zope Object DataBase", or the *ZODB*.  In default configurations, the ZODB
-creates a file named "Data.fs" in which Zope stores its objects.  The ZMI
-is the primary way by which you interact with Zope objects stored in this
-database.  Note that there are other methods of interacting with objects
-stored in the ZODB, including FTP and WebDAV, which are detailed in the
-chapter in this book entitled `Managing Zope Using External
-Tools <ExternalTools.stx>`_, but the ZMI is the primary management
-tool.
-
-ZMI Frames
-----------
-
-The ZMI uses three browser frames:
-
-- The left frame is called the *Navigator Frame*, which can be used to
-  expand or collapse a view into the Zope object hierarchy, much like you
-  would expand and collapse a view of files using a file tree widget like
-  the one in Windows Explorer.
-
-- The right frame is called the *Workspace Frame*, which displays a
-  particular view of the object you're currently managing.    
-
-- The top frame is called the *Status Frame*, which displays your user name
-  (when logged in), as well as a drop-down list that performs various
-  actions.
-
-The Navigator Frame
-~~~~~~~~~~~~~~~~~~~
-
-In the left-hand, or *Navigator*, frame, you have a view into the *root
-folder* and all of its subfolders.  The *root folder* is in the upper-left
-corner of the tree. The root folder is the "topmost" container of Zope
-objects: almost everything meaningful in your Zope instance lives inside
-the root folder.
-
-.. figure:: ../Figures/navigator.jpg
-  
-   The Navigator Frame
-
-Some of the folders in the Navigator are displayed with "plus mark" icons
-to their left.  These icons let you expand the folders to see the
-sub-folders inside them.
-
-When you click on an object icon or name in the Navigator, the *Workspace*
-frame will refresh with a view of that object.
-
-The Workspace Frame
-~~~~~~~~~~~~~~~~~~~
-
-The right-hand frame of the management interface shows the object you are
-currently managing.  When you first log into Zope, the root folder is
-displayed as the current object.  The workspace gives you information about
-the current object and lets you manage it.
-
-.. figure:: ../Figures/workspace.jpg
-
-   The Workspace Frame
-
-A series of tabs is displayed across the top of the screen. The tab that is
-currently active is highlighted in a lighter color.  Each tab takes you to
-a different *view* of the current object, and each view lets you perform a
-different management function on that object.
-
-When you first log into Zope, you are looking at the *Contents* view of the
-root folder object.
-
-At the top of the workspace, just below the tabs, is a description of the
-current object's type and URL. On the left is an icon representing the
-current object's type, and to the right of that is the object's URL.
-
-At the top of the page, 'Folder at /' tells you that the current object is
-a folder and that its path is "/".  Note that this path is the object's
-place relative to Zope's "root" folder. The root folder's path is expressed
-as "/" , and since you are looking at the root when you first log in, the
-path displayed at the the top of the workspace is simply "/".
-
-Zope object paths are typically mirrored in the URLs that are used to
-access a Zope object.  For instance, if the main URL of your Zope site was
-http://mysite.example.com:8080, then the URL of the root folder would be
-http://mysite.example.com:8080/ and the URL of 'Folder at /myFolder' would
-be 'http://mysite.example.com:8080/myFolder'.
-
-As you explore different Zope objects, you'll find that the links displayed
-at the top of the workspace frame can be used to navigate between objects'
-management views.  For example, if you are managing a folder at
-*/Zoo/Reptiles/Snakes*, you can return to the folder at */Zoo* by clicking
-on the word *Zoo* in the folder's URL.
-
-The Status Frame
-~~~~~~~~~~~~~~~~
-
-The "status frame" at the top of the management interface displays your
-current login name, along with a pull-down box that lets you select:
-
-- *Preferences*: By selecting this menu item, you can set default
-  preferences for your Zope management interface experience.  You can
-  choose to turn off the status frame.  You can also choose whether you
-  want the management interface to try to use style sheets.  Additionally,
-  you can change the default height and width of text-area boxes displayed
-  in the ZMI.  This information is associated with your browser via a
-  cookie.  It is not associated in any way with your Zope user account.
-
-- *Logout*: Selecting this menu item will log you out of Zope.
-  Due to the way that the HTTP "basic authentication" protocol works, this
-  may not behave properly with all browsers.  If you experience problems
-  logging out using this method, try closing and reopening your browser to
-  log out.
-
-.. figure:: ../Figures/statusframe.jpg
- 
-   The Status Frame
-
-Creating Objects
-----------------
-
-The Zope Management Interface allows you to create new objects in your Zope
-instance.  To add a new object, select an entry from the pull-down menu in
-the Workspace labeled "Select type to add...".  This pull-down menu is
-called the *add list*.
-
-The first kind of object you'll want to add in order to "try out" Zope is a
-"Folder".  To create a Zope Folder object, navigate to the root folder and
-select *Folder* from the add list.  At this point, you'll be taken to an
-add form that collects information about the new folder, as shown in the
-figure below.
-
-.. figure:: ../Figures/addfolder.jpg
-
-   Folder add form
-
-Type "zoo" in the *Id* field, and "Zope Zoo" in the *Title* field.  Then
-click the *Add* button.
-
-Zope will create a new Folder object in the current folder named *zoo*. You
-can verify this by noting that there is now a new folder named *zoo* inside
-the root folder.
-
-Click on *zoo* to "enter" it. The Workspace frame will switch to the
-contents view of *zoo* (which is currently an "empty" folder, as it has no
-sub-objects or contents).  Note that the URL of the *zoo* folder is based
-on the folder's *id*.
-
-You can create more folders inside your new folder if you wish. For
-example, create a folder inside the *zoo* folder with an id of *arctic*.
-Enter the *zoo* folder and choose *Folder* from the pull-down menu. Then
-type in "arctic" for the folder id, and "Arctic Exhibit" for the title. Now
-click the *Add* button.
-
-When you use Zope, you create new objects by following these
-steps:
-
-1. Enter the folder where you want to add a new object.
-
-2. Choose the type of object you want to add from the add list.
-
-3. Fill out the resulting add form and submit it. As a result, Zope will
-   create a new object in the folder.
-
-Notice that every Zope object has an *id* that you need to specify in the
-add form when you create the object. The id is how Zope names objects.
-Objects also use their ids as a part of their *URL*.  The URL of any given
-Zope object is typically a URL consisting of the folders in which the
-object lives plus its name.  For example, we created a folder named "zoo"
-in the root folder.  If our site were called "mysite.example.com", the new
-folder's URL would be "http://mysite.example.com/zoo".
-
-Moving and Renaming Objects
----------------------------
-
-Most computer systems let you move files around in directories with cut,
-copy, and paste actions. The ZMI uses a similar system that lets you move
-objects around in folders by cutting or copying them, and then pasting them
-to a new location.
-
-.. Note:
-   Zope move and rename options require that you have cookies enabled in
-   your browser.
-
-To experiment with copy and paste, create a new Folder object in the root
-folder with an id of *bears*.  Then select *bears* by checking the check
-box just to the left of the folder. Then click the *Cut* button. Cut
-selects the selected objects from the folder and places them on Zope's
-"clipboard".  The object will *not*, however, disappear from its location
-until it is pasted somewhere else.
-
-Now enter the *zoo* folder by clicking on it. Click the *Paste* button to
-paste the cut object into the *zoo* folder. You should see the *bears*
-folder appear in its new location. You can verify that the folder has been
-moved by going to the root folder and confirming that *bears* is no longer
-visible there.
-
-Copy works similarly to cut, in that, when you paste copied objects, the
-original objects are not removed.  Select the object(s) you want to copy
-and click the *Copy* button. Then navigate to another folder and click the
-*Paste* button.
-
-You can cut and copy folders that contain other objects and move many
-objects at one time with a single cut and paste.  For example, go to the
-root folder, and copy the *zoo* folder. Now paste it into the root folder.
-You will now have two folders inside the root folder: *zoo* and
-*copy_of_zoo*. If you paste an object into the same folder where you copied
-it, Zope will change the id of the pasted object. This is a necessary step,
-as you cannot have two objects with the same id in the same folder.
-
-To rename the *copy_of_zoo* folder, select the folder by checking the check
-box to the left of the folder. Then click the *Rename* button.  This will
-take you to the rename form.
-
-.. figure:: ../Figures/renamezoo.jpg
-
-   Renaming an Object
-
-Type in the new id value "zoo2" and click *OK*. Zope ids can consist of
-letters, numbers, spaces, dashes, underscores, and periods, and they are
-case-sensitive. Here are some legal Zope ids: *index.html*, *42*,
-*Lucky13*, and *Snake-Pit*.
-
-Now your root folder contains *zoo* and *zoo2* folders. Each of these
-folders contains a *bears* folder. This is because when we made a copy of
-the *zoo* folder, we also copied the *bears* folder that it contained.
-Copying an object also copies all of the objects it contains.
-
-If you want to delete an object, select it and then click the *Delete*
-button. Unlike cut objects, deleted objects are not placed on the clipboard
-and cannot be pasted. In the next section, we'll see how we can retrieve
-deleted objects using Undo.
-
-Zope will not let you cut, delete, or rename a few particular objects in
-the root folder. These objects include *Control_Panel*,
-*browser_id_manager*, and *temp_folder*.  These objects are necessary for
-Zope's operation.  It is possible to delete other root objects, such as
-*index_html*, *session_data_manager* and *standard_error_message*,
-but it is not recommended to do so unless you have a very good reason.
-
-Transactions and Undoing Mistakes
----------------------------------
-
-All objects you create in Zope are stored in Zope's "object database".
-Unlike other web application servers, Zope doesn't store its objects in
-files on a filesystem.  Instead, all Zope objects are stored by default in
-a single special file on the filesystem named 'Data.fs'.  This file is
-stored in the 'var' directory of your Zope instance.  Using an object
-database rather than storing objects on the file system allows operations
-to Zope objects to be *transactional*.
-
-A transactional operation is one in which all changes to a set of objects
-are committed as a single "batch".  In Zope, a single web request initiates
-a transaction.  When the web request is finished, Zope commits the
-transaction unless an error occurs during the processing of the request.
-If there is an error, Zope refrains from committing the transaction. Each
-transaction describes all of the changes that happen in the course of
-performing a web request.
-
-Most actions in Zope that causes a transaction can be undone via the *Undo*
-tab.  You can recover from mistakes by undoing the transaction that
-represents the mistake.  This includes undo actions themselves, which can
-also be undone to restore an object to its state before the undo action.
-
-Select the *zoo* folder that we created earlier and click *Delete*. The
-folder disappears. You can get it back by undoing the delete action.
-
-Click the *Undo* tab, as shown in the figure below.
-
-.. figure:: ../Figures/delzoo.jpg
-
-   The Undo view
-
-Transactions are named after the Zope action, or "method", that initiated
-them.  In this case, the initiating method was one named
-``/manage_delObjects``, which is the name of the Zope action that deletes
-Zope objects.
-
-Select the first transaction labeled */manage_delObjects*, and click the
-*Undo* button at the bottom of the form.  Doing so instructs Zope to undo
-the last transaction. You can verify that the task has been completed by
-visiting the root folder to confirm that the *zoo* folder has returned.  If
-you use the "Back" button to revisit the root folder, you may need to
-refresh your browser to see the proper results.  To see the effect in the
-*Navigator* pane, click the "Refresh" link within the pane.
-
-You may "undo an undo" action, or "redo" the action, and you can undo and
-redo actions as many times as you like.  When you perform a "redo", Zope
-inserts a transaction into the undo log describing the redo action.
-
-The Undo tab is available on most Zope objects.  When viewing the Undo tab
-of a particular object, the list of undoable transactions is filtered down
-to the transactions that have recently affected the current object and its
-sub-objects.
-
-Undo Details and Gotchas
-------------------------
-
-You cannot undo a transaction upon which a later transaction depends.  For
-example, if you paste an object into a folder, and then delete an object in
-the same folder, pasting the first object cannot be undone, as both
-transactions affect the contents of a single object: the folder. The
-solution is to undo both transactions. You can undo more than one
-transaction at a time by selecting multiple transactions on the *Undo* tab
-and then clicking *Undo*.  
-
-Only changes to objects stored in Zope's object database can be undone.  If
-you have integrated data into a relational database server, such as Oracle
-or MySQL (as discussed in the chapter entitled "Relational Database
-Connectivity"), changes to data stored there cannot be undone.
-
-Reviewing Change History
-------------------------
-
-The Undo tab will provide you with enough information to know that a change
-has occurred.  However, it will not tell you much about the effect of the
-transaction on the objects that were changed during the transaction.
-
-Using Object Properties
------------------------
-
-*Properties* are ways of associating information with many objects in Zope,
-including folders.  For example, many Zope content objects have a content
-type property, and others contain metadata about the object, such as its
-author, title, or status.
-
-Properties can provide more complex data than strings, such as numbers,
-lists, and other data structures.  All properties are managed via the
-*Properties* view.  Click on the *Properties* tab of the "root" object, and
-you will be taken to the properties management view, as seen in the figure
-below.
-
-.. figure:: ../Figures/rootproperties.jpg
-
-   The Properties Management View
-
-A property consists of a name, a value, and a type.  A property's type
-defines what kind of value or values it can have.
-
-In the figure above, you can see that the folder has a single string
-property *title*, which has the value 'Zope'.  You may change any
-predefined property by changing its value in the Value box, and then
-clicking *Save Changes*.  You may add additional properties to an object by
-entering a name, value, and type into the bottom-most field in the
-Properties view.
-
-Zope supports a number of property types and each type is suited to a
-specific task.  This list gives a brief overview of the kinds of properties
-you can create from the management interface:
-
-string
-  A string is a sequence of characters of arbitrary length.
-  Strings are the most basic and useful type of property in Zope.
-
-int
-  An int property is an integer, which can be any positive or
-  negative number that is not a fraction.  An int is guaranteed to be
-  at least 32 bits long.
-
-long
-  A long is an integer that has no range limitation.
-
-float
-  A float holds a floating point, or decimal number.
-  Monetary values, for example, often use floats.
-
-lines
-  A lines property is a sequence of strings.
-
-tokens
-  A tokens property is a list of words separated by spaces.
-
-text
-  A text property is just like a string property, except that
-  Zope normalizes the line ending characters (different browsers use
-  different line ending conventions).
-
-selection
-  A selection property is special, in that it is used to render
-  an HTML single selection input widget.
-
-multiple selection
-  A multiple selection property is special, in that it
-  is used to render an HTML multiple selection form input widget.
-
-Properties are very useful tools for tagging your Zope objects with bits of
-metadata.  Properties are supported by most Zope objects and are often
-referenced by your application logic for purposes of data display.
-
-Logging Out
------------
-
-You may choose *Logout* from the Status Frame drop-down box to attempt to
-log out of Zope.  Doing so will cause your browser to "pop up" an
-authentication dialog.  Due to the way most web browsers work, you may
-actually need to click on the "OK" button with an *incorrect* user name and
-password in the authentication dialog in order to effectively log out of
-the ZMI.  If you do not do so, you may find even after selecting "Logout"
-that you are still logged in.  This is an intrinsic limitation of the HTTP
-Basic Authentication protocol, which Zope's stock user folder employs.
-Alternately, you may close and reopen your browser to log out of Zope.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/VirtualHosting.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/VirtualHosting.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/VirtualHosting.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,503 +0,0 @@
-Virtual Hosting Services
-========================
-
-Zope comes with one object that help you do virtual hosting:
-*Virtual Host Monster*. Virtual hosting is a way to
-serve many websites with one Zope server.
-
-Virtual Host Monster
---------------------
-
-Zope objects need to generate their own URLs from time to time.
-For instance, when a Zope object has its "absolute_url" method
-called, it needs to return a URL which is appropriate for
-itself.  This URL typically contains a hostname, a port, and a
-path.  In a "default" Zope installation, this hostname, port,
-and path is typically what you want.  But when it comes time to
-serve multiple websites out of a single Zope instance, each with
-their own "top-level" domain name, or when it comes time to
-integrate a Zope Folder within an existing website using Apache
-or another webserver, the URLs that Zope objects generate need
-to change to suit your configuration.
-
-A Virtual Host Monster's only job is to change the URLs which
-your Zope objects generate.  This allows you to customize the
-URLs that are displayed within your Zope application, allowing
-an object to have a different URL when accessed in a different
-way.  This is most typically useful, for example, when you wish
-to "publish" the contents of a single Zope Folder
-(e.g. '/FooFolder') as a URL that does not actually contain this
-Folder's name (e.g as the hostname 'www.foofolder.com').
-
-The Virtual Host Monster performs this job by intercepting and
-deciphering information passed to Zope within special path
-elements encoded in the URLs of requests which come in to Zope.
-If these special path elements are absent in the URLs of
-requests to the Zope server, the Virtual Host Monster does
-nothing.  If they are present, however, the Virtual Host Monster
-deciphers the information passed in via these path elements and
-causes your Zope objects to generate a URL that is different
-from their "default" URL.
-
-The Zope values which are effected by the presence of a Virtual
-Host Monster include REQUEST variables starting with URL or BASE
-(such as URL1, BASE2, URLPATH0), and the absolute_url() methods
-of objects.
-
-Virtual Host Monster configuration can be complicated, because
-it requires that you *rewrite* URLs "on the way in" to Zope.  In
-order for the special path elements to be introduced into the
-URL of the request sent to Zope, a front-end URL "rewriting"
-tool needs to be employed.  Virtual Host Monster comes with a
-simple rewriting tool in the form of its *Mappings* view, or
-alternately you can use Apache or another webserver to rewrite
-URLs of requests destined to Zope for you.
-
-Adding a Virtual Host Monster to your Zope
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-VirtualHostMonster is one of the add menu items supplied by the
-stock Zope Product, 'SiteAccess'.  You can add one to any folder
-by selecting its entry from the add menu and supplying an ID for
-it (the ID you choose doesn't matter, except that it must not
-duplicate the ID of another object in that folder).
-
-Where to Put a Virtual Host Monster And What To Name It
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A single Virtual Host Monster in your Zope root can handle all
-of your virtual hosting needs. It doesn't matter what 'id' you
-give it, as long as nothing else in your site has the same
-'id'.
-
-Configuring the VirtualHostMonster
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The default mode for configuring the VirtualHostMonster is not
-to do any configuration at all!  Rather, the external webserver
-modifies the request URL to signal what the *real* public URL for
-the request is (see "Apache Rewrite Rules" below).
-
-If you *do* choose to change the settings of your VHM, the easiest
-method to do so is to use the VHM's ZMI interface (as explained in
-the "Virtual Host Monster *Mappings* Tab" and "Inside-Out Virtual
-Hosting" sections below.
-
-It is possible to modify the VHM settings from the command line
-via Zope debugger;  no documentation for the low-level API
-exists, however, except "the source",
-'Products.SiteAccess.VirtualHostMonster.py,
-which makes it an inadvisable choice for anyone but an experienced
-Zope developer.
-
-Special VHM Path Elements 'VirtualHostBase' and 'VirtualHostRoot'
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A Virtual Host Monster doesn't do anything unless it sees one
-of the following special path elements in a URL:
-
-'VirtualHostBase'
-  if a VirtualHostMonster "sees" this name in the incoming URL, it causes
-   Zope objects to generate URLs with a potentially different protocol, a
-   potentially different hostname, and a potentially different port number.
-
-'VirtualHostRoot'
-  if a VirtualHostMonster "sees" this name in the incoming URL, it causes
-   Zope objects to generate URLs which have a potentially different "path
-   root"
-
-'VirtualHostBase'
-%%%%%%%%%%%%%%%%%
-
-The 'VirtualHostBase' declaration is typically found at the
-beginning of an incoming URL.  A Virtual Host Monster will
-intercept two path elements following this name and will use
-them to compose a new protocol, hostname, and port number.
-
-The two path elements which must follow a 'VirtualHostBase'
-declaration are 'protocol' and 'hostname:portnumber'.  They
-must be separated by a single slash.  The colon and
-portnumber parts of the second element are optional, and if
-they don't exist, the Virtual Host Monster will not change
-the port number of Zope-generated URLs.
-
-Examples:
-
-- If a VHM is installed in the root folder, and a request comes in to
-  your Zope with the URL:
-
-   'http://zopeserver:8080/VirtualHostBase/http/www.buystuff.com'
-
-  URLs generated by Zope objects will start with
-  'http://buystuff.com:8080'.
-
-- If a VHM is installed in the root folder, and a request comes in to
-  your Zope with the URL:
-
-   'http://zopeserver:8080/VirtualHostBase/http/www.buystuff.com:80'
-
-  URLs generated by Zope objects will start with 'http://buystuff.com'
-  (port 80 is the default port number so it is left out).
-
-- If a VHM is installed in the root folder, and a request comes in to
-  your Zope with the URL:
-
-   'http://zopeserver:8080/VirtualHostBase/https/www.buystuff.com:443'
-
-  URLs generated by Zope objects will start with 'https://buystuff.com/'.
-  (port 443 is the default https port number, so it is left off.
-
-One thing to note when reading the examples above is that if
-your Zope is running on a port number like 8080, and you
-want generated URLs to not include this port number and
-instead be served on the standard HTTP port (80), you must
-specifically include the default port 80 within the
-VirtualHostBase declaration, e.g.
-'/VirtualHostBase/http/www.buystuff.com:80'.  If you don't
-specify the ':80', your Zope's HTTP port number will be used
-(which is likely not what you want).
-
-'VirtualHostRoot'
-%%%%%%%%%%%%%%%%%
-
-The 'VirtualHostRoot' declaration is typically found near
-the end of an incoming URL.  A Virtual Host Monster will
-gather up all path elements which *precede* and *follow* the
-'VirtualHostRoot' name, traverse the Zope object hierarchy
-with these elements, and publish the object it finds with
-the path rewritten to the path element(s) which *follow*
-the 'VirtualHostRoot' name.
-
-This is easier to understand by example.  For a URL
-'/a/b/c/VirtualHostRoot/d', the Virtual Host Monster will
-traverse "a/b/c/d" and then generate a URL with path /d.
-
-Examples:
-
-- If a VHM is installed in the root folder, and a request comes in to
-  your Zope with the URL:
-
-   'http://zopeserver:8080/Folder/VirtualHostRoot/
-
-  The object 'Folder' will be traversed to and published,
-  URLs generated by Zope will start with
-  'http://zopeserver:8080/', and when they are visited, they
-  will be considered relative to 'Folder'.
-
-- If a VHM is installed in the root folder, and a request comes in to
-  your Zope with the URL:
-
-   'http://zopeserver:8080/HomeFolder/VirtualHostRoot/Chris
-
-  The object '/Folder/Chris' will be traversed to and
-  published, URLs generated by Zope will start with
-  'http://zopeserver:8080/Chris', and when they are visited,
-  they will be considered relative to '/HomeFolder/Chris'.
-
-Using 'VirtualHostRoot' and 'VirtualHostBase' Together
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The most common sort of virtual hosting setup is one in which
-you create a Folder in your Zope root for each domain that you
-want to serve. For instance the site http://www.buystuff.com
-is served from a Folder in the Zope root named /buystuff while
-the site http://www.mycause.org is served from a Folder in the
-Zope root named /mycause.  In order to do this, you need to
-generate URLs that have both 'VirtualHostBase' and
-'VirtualHostRoot' in them.
-
-To access /mycause as http://www.mycause.org/, you would cause
-Zope to be visited via the following URL::
-
-  /VirtualHostBase/http/www.mycause.org:80/mycause/VirtualHostRoot/
-
-In the same Zope instance, to access /buystuff as
-http://www.buystuff.com/, you would cause Zope to be visited
-via the following URL::
-
-  /VirtualHostBase/http/www.buystuff.com:80/buystuff/VirtualHostRoot/
-
-Testing a Virtual Host Monster
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Set up a Zope on your local machine that listens on HTTP port
-8080 for incoming requests.
-
-Visit the root folder, and select *Virtual Host Monster* from
-the Add list.  Fill in the 'id' on the add form as 'VHM' and
-click 'Add.'
-
-Create a Folder in your Zope root named 'vhm_test'.  Within the
-newly-created 'vhm_test' folder, create a DTML Method named
-'index_html' and enter the following into its body::
-
-   <html>
-   <body>
-   <table border="1">
-     <tr>
-       <td>Absolute URL</td>
-       <td><dtml-var absolute_url></td>
-     </tr>
-     <tr>
-       <td>URL0</td>
-       <td><dtml-var URL0></td>
-     </tr>
-     <tr>
-       <td>URL1</td>
-       <td><dtml-var URL1></td>
-     </tr>
-   </table>
-   </body>
-   </html>
-
-View the DTML Method by clicking on its View tab, and you will
-see something like the following::
-
-  Absolute URL   http://localhost:8080/vhm_test 
-  URL0           http://localhost:8080/vhm_test/index_html
-  URL1           http://localhost:8080/vhm_test 
-
-Now visit the URL 'http://localhost:8080/vhm_test'.  You will be
-presented with something that looks almost exactly the same.
-
-Now visit the URL
-'http://localhost:8080/VirtualHostBase/http/zope.com:80/vhm_test'.
-You will be presented with something that looks much like this::
-
-  Absolute URL   http://zope.com/vhm_test 
-  URL0           http://zope.com/vhm_test/index_html
-  URL1           http://zope.com/vhm_test
-
-Note that the URLs that Zope is generating have changed.
-Instead of using 'localhost:8080' for the hostname and path,
-we've instructed Zope, through the use of a VirtualHostBase
-directive to use 'zope.com' as the hostname.  No port is shown
-because we've told Zope that we want to generate URLs with a
-port number of 80, which is the default http port.
-
-Now visit the URL
-'http://localhost:8080/VirtualHostBase/http/zope.com:80/vhm_test/VirtualHostRoot/'.
-You will be presented with something that looks much like this::
-
-  Absolute URL   http://zope.com
-  URL0           http://zope.com/index_html
-  URL1           http://zope.com
-
-Note that we're now publishing the 'vhm_test' folder as if it
-were the root folder of a domain named 'zope.com'.  We did this
-by appending a VirtualHostRoot directive to the incoming URL,
-which essentially says "traverse to the vhm_root folder as if it
-were the root of the site."
-
-Arranging for Incoming URLs to be Rewritten
--------------------------------------------
-
-At this point, you're probably wondering just how in the world
-any of this helps you.  You're certainly not going to ask
-people to use their browser to visit a URL like
-'http://yourserver.com//VirtualHostBase/http/zope.com/vhm_test/VirtualHostRoot/'
-just so your Zope-generated URLs will be "right".  That would
-defeat the purpose of virtual hosting entirely.  The answer is:
-don't ask humans to do it, ask your computer to do it.  There
-are two common (but mutually exclusive) ways to accomplish
-this: via the VirtualHostMonster *Mappings* tab and via Apache
-"rewrite rules" (or your webserver's facility to do the same
-thing if you don't use Apache).  Be warned: use either one of
-these facilities or the other but not both or very strange
-things may start to happen.  We give examples of using both
-facilities below.
-
-Virtual Host Monster *Mappings* Tab
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Use the Virtual Host Monster's *Mappings* tab to cause your
-URLs to be rewritten if:
-
-- You run a "bare" Zope without a front-end webserver like
-  Apache.
-
-- You have one or more folders in your Zope that you'd like
-  to publish as "http://some.hostname.com/" instead of
-  "http://hostname.com/a/folder".
-
-The lines entered into the *Mappings* tab are in the form::
-
-  www.example.com /path/to/be/rewritten/to
-
-You can also match multiple subdomains by putting "\*." in front
-of the host name in the mapping rule.  For example::
-
-  *.example.com /folder 
-  
-This example  will match "my.example.com",
-"zoom.example.com", etc. If an exact match exists, it is
-used instead of a wildcard match.
-
-The best way to explain how to use the *Mappings* tab is by
-more specific example.  Assuming you've added a Virtual Host 
-Monster object in your root folder on a Zope running on 'localhost'
-on port 8080, create an alias in your local system's 'hosts'
-file (in /etc/hosts on UNIX and in
-c:\WINNT\system32\drivers\etc\hosts on Windows) that looks
-like this::
-
-  127.0.0.1 www.example.com
-
-This causes your local machine to contact itself when a
-hostname of 'wwww.example.com' is encountered.  For the sake
-of this example, we're going to want to contact Zope via the
-hostname 'www.example.com' through a browser (also on your
-local host) and this makes it possible.
-
-Then visit the VHM in the root folder and click on its
-*Mappings* tab.  On a line by itself enter the following::
-
-  www.example.com:8080/vhm_test
-
-This will cause the 'vhm_test' folder to be published when
-we visit 'http://www.example.com:8080'.  Visit
-'http://www.example.com:8080'.  You will see::
-
-  Absolute URL   http://www.example.com:8080
-  URL0           http://www.example.com:8080/index_html
-  URL1           http://www.example.com:8080
-
-In the "real world" this means that you are "publishing" the
-'vhm_test' folder as http://'www.example.com:8080'.
-
-Note that it is not possible to rewrite the port part
-(by default, '8080') of the URL this way. To change the
-port Zope is listening on, you will have to configure
-Zope's start parameter or use Apache rewriting.
-
-Apache Rewrite Rules
-~~~~~~~~~~~~~~~~~~~~
-
-If you use Apache in front of Zope, instead of using the
-*Mappings* tab, you should use Apache's rewrite rule
-functionality to rewrite URLs in to Zope.  The way this
-works is straightforward: Apache listens on its "normal"
-port, typically port 80.  At the same time, Zope's web
-server (on the same host or on another host) listens on a
-different port (typically 8080).  Apache accepts requests on
-its listening port.  A virtual host declaration in Apache's 
-configuration tells Apache to apply the contained
-directives to the specified virtual host.
-
-Using Apache's rewrite rule functionality requires that the
-'mod_rewrite' and 'mod_proxy' Apache modules be enabled.
-This can for instance be done by configuring Apache with the
-'--enable-modules="rewrite proxy"' flag during compile time or
-by loading the corresponding shared modules.
-
-If you are using the new Apache 2 series, you will also have
-to include the 'mod_proxy_http' module. See the "Apache
-mod_rewrite documentation",
-http://httpd.apache.org/docs/trunk/mod/mod_rewrite.html
-for details.
-
-You can check whether you have the required modules installed
-in Apache by examinint 'LoadModule' section of httpd.conf
-
-After you've got Apache configured with mod_rewrite
-and mod_proxy (and, depending on your Apache version,
-mod_proxy_http), you can start configuring Apache's
-config file and Zope for the following example.
-Assuming you've added a Virtual Host Monster object in
-your root folder on a Zope running on 'localhost' on
-port 8080, create an alias in your local system's
-'hosts' file (in /etc/hosts on UNIX and in
-c:\WINNT\system32\drivers\etc\hosts on Windows) that
-looks like this::
-
-  127.0.0.1 www.example.com
-
-This causes your local machine to contact itself when a
-hostname of 'wwww.example.com' is encountered.  For the sake
-of this example, we're going to want to contact Zope via the
-hostname 'www.example.com' through a browser (also on your
-local host) and this makes it possible.
-
-Note:  On MacOS X Server, the 'Server Admin.app' program
-simplifies adding virtual host definitions to your Apache.
-This application can make and maintain virtual host , access
-log, etc. 
-
-Now, assuming you've got Apache running on port 80 and Zope
-running on port 8080 on your local machine, and assuming
-that you want to serve the folder named 'vhm_test' in Zope
-as 'www.example.com' and, add the following to your Apache's
-'httpd.conf' file and restart your Apache process::
-
-  NameVirtualHost *:80
-  <VirtualHost *:80>
-  ServerName www.example.com
-  RewriteEngine On
-  RewriteRule ^/(.*) http://127.0.0.1:8080/VirtualHostBase/http/www.example.com:80/vhm_test/VirtualHostRoot/$1 [L,P]
-  </VirtualHost>
-
-If you want to proxy SSL to Zope, you need a similar directive
-for port 443::
-
-   NameVirtualHost *:443
-   <VirtualHost *:443>
-   ServerName www.example.com
-   SSLProxyEngine on
-   RewriteEngine On
-   RewriteRule ^/(.*) http://127.0.0.1:8080/VirtualHostBase/https/www.example.com:443/vhm_test/VirtualHostRoot/$1 [L,P]
-   </VirtualHost>
-
-Note: the long lines in the RewriteRule directive above
-*must* remain on a single line, in order for Apache's
-configuration parser to accept it.
-
-
-When you visit 'http://www.example.com' in your browser, you
-will see::
-
-  Absolute URL   http://www.example.com
-  URL0           http://www.example.com/index_html
-  URL1           http://www.example.com
-
-This page is being served by Apache, but the results are
-coming from Zope.  Requests come in to Apache with "normal"
-URLs (e.g. 'http://www.example.com').  The VirtualHost
-stanza in Apache's httpd.conf causes the request URL to be
-rewritten (e.g. to
-'http://127.0.0.1:8080/VirtualHostBase/http/www.example.com:80/vhm_test/VirtualHostRoot/').
-Apache then calls the rewritten URL, and returns the result.
-
-See the "Apache Documentation",
-http://httpd.apache.org/docs/2.0/misc/rewriteguide.html
-for more information on the subject of rewrite rules.
-
-Virtual Hosting Considerations for Content classes
---------------------------------------------------
-
-Be sure that content objects catalog themselves using as their
-unique ID a "site-relative" path, rather than their full physical
-path;  otherwise, the object will be findable when using the site
-without virtual hosting, but not with, or vice versa.
-
-"Inside-Out" Virtual Hosting
-----------------------------
-
-Another use for virtual hosting is to make Zope appear to be
-part of a site controlled by another server. For example, Zope
-might only serve the contents of
-'http://www.mycause.org/dynamic_stuff', while Apache or
-another webserver serves files via
-'http://www.mycause.org/'. To accomplish this, you want to add
-"dynamic_stuff" to the start of all Zope-generated URLs.
-
-If you insert VirtualHostRoot, followed by one or more path
-elements that start with '_vh_', then these elements will be
-ignored during traversal and then added (without the '_vh_')
-to the start of generated URLs. For instance, a request for
-"/a/VirtualHostRoot/_vh_z/" will traverse "a" and then
-generate URLs that start with /z.
-
-In our example, you would have the main server send requests
-for http://www.mycause.org/dynamic_stuff/anything to Zope,
-rewritten as /VirtualHostRoot/_vh_dynamic_stuff/anything.
-

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/ZEO.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/ZEO.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/ZEO.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,596 +0,0 @@
-Scalability and ZEO
-###################
-
-When a web application receives more requests than it can handle over a short
-period of time, it can become unresponsive. In the worst case, too many
-concurrent requests to a web application can cause the software which services
-the application to crash. This can be a problem for any kind of web-based app,
-not just those which are served by Zope.
-
-The obvious solution to this problem is to use more than one server. When one
-server becomes overloaded, the others can then hopefully continue to
-successfully serve requests. By adding additional servers to this kind of
-configuration, you can "scale" your web application as necessary to meet
-demand.
-
-Using multiple servers has obvious benefits, but it also poses serious
-challenges. For example, if you have five servers, then you must ensure that
-all five server installations are populated with the same information. This is
-not a very hard task if you have only a few static web pages, but for larger
-applications with large bodies of rapidly changing information, manually
-synchronizing the data which drives five separate server installations is
-almost impossible, even with the "out of the box" features that Zope provides.
-
-A "stock" Zope installation uses the Zope Object Database as its content store,
-using a "storage" which is named a "FileStorage". This storage type (there are
-others) keeps all of your Zope data in a single file on your computer's hard
-drive, typically named `Data.fs`. This configuration works well until you need
-to add an additional Zope server to your site to handle increased traffic to
-your web application. Two Zope servers cannot share this file. The file is
-"locked" by one Zope server and no other Zope server can access the file. Thus,
-in a "stock" Zope configuration, it is impossible to add Zope servers which
-read from the same database in order to "scale" your web application to meet
-demand.
-
-To solve this problem, Zope Corporation has created another kind of "storage",
-which operates using a client/server architecture, allowing many Zopes to share
-the same database information. This product is known as `Zope Enterprise
-Objects` or ZEO. ZEO is built into Zope, no additional software install is
-required.
-
-This chapter gives you a brief overview on installing ZEO, but there are many
-other options we don't cover. For more in-depth information, see the
-documentation that comes with the ZEO package, and also take a look at the
-`ZODB and ZEO discussion area <http://www.zope.org/Wikis/ZODB/FrontPage>`_.
-
-What is ZEO?
-============
-
-ZEO is a system that allows you to share a Zope Object Database between more
-than one Zope process. By using ZEO, you may run multiple instances of Zope on
-a single computer or on multiple computers. Thus, you may spread requests to
-your web application between Zope servers. You may add more computers as the
-number of requests grows, allowing your web application to scale. Furthermore,
-if one Zope server fails or crashes, other servers can still service requests
-while you fix the broken one. ZEO takes care of making sure each Zope
-installation uses consistent information from the same Zope Object Database.
-
-ZEO uses a client/server architecture. The Zope processes (shown on multiple
-computers in the diagram below) are the *ZEO Clients*. All of the clients
-connect to one, central *ZEO Storage Server*, as shown in the image below.
-
-`Simple ZEO illustration <img:20-1:Figures/11-1.png>`_
-
-The terminology may be a bit confusing. Typically, you may think of Zope as a
-server, not a client. But when using ZEO, your Zope processes act as both
-servers (for web requests) and clients (for data from the ZEO server).
-
-ZEO clients and servers communicate using standard Internet protocols, so they
-can be in the same room or in different countries. ZEO, in fact, could
-distribute a Zope site to disparate geographic locations, given good network
-connectivity between the ZEO clients and the ZEO server. In this chapter we'll
-explore some interesting ways you can distribute your ZEO clients.
-
-When you should use ZEO
-=======================
-
-Using a ZEO-based installation is advantageous for almost all users. Here are
-some of the reasons:
-
-- Zope is a high-performance system, and one Zope can handle millions of hits
-  per day, but there are upper bounds on the capacity of a single Zope server.
-  ZEO allows you to scale your site by adding more hardware on which you may
-  place extra Zope servers to handle excess demand.
-
-- Your site is critical and requires 24/7 uptime. Using ZEO can help you add
-  redundancy to your server configuration.
-
-- You want to distribute your site to disparate geographic locations in order
-  to increase response time to remote sites. ZEO allows you to place Zope
-  servers which use the same ZODB in separate geographic locations.
-
-- You want to "debug" an application which is currently served by a single Zope
-  server from another Zope process. ZEO enables the developer to attach to a
-  ZODB database while still continuing to serve requests from another ZEO
-  client.
-
-Installing, configuring, and maintaining a ZEO-enabled Zope requires some
-system administration knowledge. Most Zope users will not need ZEO, or may not
-have the expertise necessary to maintain a distributed server system like ZEO.
-ZEO is fun, and can be very useful, but before jumping head-first and
-installing ZEO in your system you should weigh the extra administrative burden
-ZEO creates against the simplicity of running just a simple, stand-alone Zope.
-
-Installing and Running ZEO
-==========================
-
-ZEO is part of Zope, all batteries are included. However, there are some
-prerequisites before you will be successfully able to use ZEO:
-
-- All of the Zope servers in a ZEO-enabled configuration must run the same
-  version of Zope and ZEO. The easiest way to meet this prerequisite is to make
-  sure all of your computers use the same Zope version.
-
-- All of your ZEO clients must have the same third party Products installed and
-  they must be the same version. This is necessary, or your third-party objects
-  may behave abnormally or not work at all.
-
-- If your Zope system requires access to external resources, like mail servers
-  or relational databases, ensure that all of your ZEO clients have access to
-  those resources.
-
-- Slow or intermittent network connections between clients and server degrade
-  the performance of your ZEO clients. Your ZEO clients should have a good
-  connection to their server.
-
-Installing ZEO is very easy. After you have gone through the steps necessary to
-build the Zope software it takes nothing more than running two scripts and
-tweaking the default configuration laid down in the ZEO client's `zope.conf`
-configuration file.
-
-First, you need to create a place where the ZEO server will live. It also
-contains the database file, so make sure you have enough space to cover your
-expected database size and at least double that so you can pack the ZODB::
-
-  $ python /path/to/Zope/bin/mkzeoinstance.py /path/to/zeostorage
-
-Make sure you use the same python interpreter that was used to build your Zope
-software. `/path/to/zeostorage` represents the location where you want the ZEO
-server to be. While the script runs you will see output telling you what it is
-doing.
-
-Once you have built the ZEO server's home this way you will notice that its
-layout is very similar to a Zope instance home. It has a configuration file
-named `zeo.conf` inside its etc-subdirectory which you should look at to get a
-notion of what can be configured, and you will need it to look up where the
-server will listen for ZEO requests when you configure your ZEO clients.
-
-The ZEO storage home also contains prefabricated start/stop scripts that work
-the same way as the Zope `zopectl` script, for ZEO it is called `zeoctl`.
-
-You should now have ZEO properly installed. Try it out by first starting the
-server. In a terminal window or DOS box type::
-
-  $ /path/to/zeostorage/bin/zeoctl start
-
-You can follow its log file by simply typing::
-
-  $ /path/to/zeostorage/bin/zeoctl logtail
-
-or by looking at the log file directly. Its location is configurable using the
-previously mentioned zeo.conf configuration file.
-
-After having set up the ZEO storage server that way you will want at least one
-ZEO client. You can use an existing Zope server (provided it meets the
-prerequisites mentioned earlier) or build a new instance home the same way you
-would if you set up a new Zope server without ZEO::
-
-  $ python /path/to/Zope/bin/mkzopeinstance
-
-Now visit the instance home you created and look for the `zope.conf`
-configuration file in its etc-directory. In order to use ZEO the client must be
-told to access the ZODB not from the file system but talk to a ZEO server
-instead. Look for the::
-
-  zodb_db main
-
-directive at the bottom. Underneath the default configuration you will notice
-an example ZEO client configuration. Comment out the complete zodb_db main
-stanza containing the
-
-  `filestorage`
-
-directive and uncomment the example zodb_db main configuration that contains
-the::
-
-  zeoclient
-
-directive. If you have not tweaked your zeo.conf file all you need to do at
-this moment is to ensure that the `server` argument in the `zeoclient`
-directive shows the same value as the `address` argument in the `zeo` directive
-inside your ZEO server's zeo.conf-file.
-
-Now you are ready to test the ZEO client. Fire it up by running::
-
-  $ /path/to/zeoclient/bin/zopectl start
-
-and check the log file manually or by running::
-
-  $ /path/to/zeoclient/bin/zopectl logtail
-
-Now visit the Zope Managment Interface (ZMI) of your ZEO client in a web
-browser and go to the *Control Panel*. Click on *Database Managment*. Here, you
-see that Zope is connected to a *ZEO Storage* and that its state is
-*connected*.
-
-Running ZEO on one computer is a great way to familiarize yourself with ZEO and
-how it works. Running a single ZEO client does not however, improve the speed
-of your site, and in fact, it may slow it down just a little. To really get the
-speed benefits that ZEO provides, you need to run multiple ZEO clients. This
-can easily be achieved by creating more ZEO client instances as described
-above. The instances can be on the same server machine or distributed over
-several machines.
-
-How to Distribute Load
-======================
-
-Imagine you have a ZEO server named *zooServer* and three ZEO clients named
-*zeoclient1*, *zeoclient2*, and *zeoclient3*. The three ZEO clients are
-connected to the ZEO server and each client is verified to work properly.
-
-Now you have three computers that serve content to your users. The next problem
-is how to actually spread the incoming web requests evenly among the three ZEO
-clients. Your users only know about *www.zopezoo.org*, not *zeoclient1*,
-*zeoclient2* or *zeoclient3*. It would be a hassle to tell only some users to
-use *zeoclient1*, and others to use *zeoclient3*, and it wouldn't be very good
-use of your computing resources. You want to automate, or at least make very
-easy, the process of evenly distributing requests to your various ZEO clients.
-
-There are a number of solutions to this problem, some easy, some advanced, and
-some expensive. The next section goes over the more common ways of spreading
-web requests around various computers using different kinds of technology, some
-of them based on freely-available or commercial software, and some of them
-based on special hardware.
-
-User Chooses a Mirror
-+++++++++++++++++++++
-
-The easiest way to distribute requests across many web servers is to pick from
-a list of *mirrored sites*, each of which is a ZEO client. Using this method
-requires no extra software or hardware, it just requires the maintenance of a
-list of mirror servers. By presenting your users with a menu of mirrors, they
-can use to choose which server to use.
-
-Note that this method of distributing requests is passive (you have no active
-control over which clients are used) and voluntary (your users need to make a
-voluntary choice to use another ZEO client). If your users do not use a mirror,
-then the requests will go to your ZEO client that serves *www.zopezoo.org*.
-
-If you do not have any administrative control over your mirrors, then this can
-be a pretty easy solution. If your mirrors go off-line, your users can always
-choose to come back to the master site which you *do* have administrative
-control over and choose a different mirror.
-
-On a global level, this method improves performance. Your users can choose to
-use a server that is geographically closer to them, which probably results in
-faster access. For example, if your main server was in Portland, Oregon on the
-west coast of the USA and you had users in London, England, they could choose
-your London mirror and their request would not have to go half-way across the
-world and back.
-
-To use this method, create a property in your root folder of type *lines* named
-"mirror". On each line of this property, put the URL to your various ZEO
-clients, as shown in the figure below.
-
-`Figure of property with URLs to mirrors <img:20-2:Figures/11-2.png>`_
-
-Now, add some simple TAL code to your site to display a list of your mirrors::
-
-  <h2>Please choose from the following mirrors:
-  <ul>
-    <li tal:repeat="mirror here/mirrors">
-      <a href=""
-         tal:attributes="href mirror"
-         tal:content="mirror">
-          my.mirror.site
-      </a>
-    </li>
-  </ul>
-
-Or, in a Script (Python):::
-
-  ## Script (Python) "generate_mirror"
-  ##bind container=container
-  ##bind context=context
-  ##bind namespace=
-  ##bind script=script
-  ##bind subpath=traverse_subpath
-  ##parameters=a, b
-  ##title=
-  ##
-  print "<h2>Please choose from the following mirrors: <ul>"
-  for mirror in container.mirrors:
-      print "<li><a href="%s">%s</a>" % (mirror, mirror)
-  return printed
-
-This TAL code (and Script (Python) equivalent) displays a list of all mirrors
-your users can choose from. When using this model, it is good to name your
-computers in ways that assist your users in their choice of mirror. For
-example, if you spread the load geographically, then choose names of countries
-for your computer names.
-
-Alternately, if you do not want users voluntarily choosing a mirror, you can
-have the *index_html* method of your www.zopezoo.org site issue HTTP redirects.
-For example, use the following code in your *www.zopezoo.org* site's
-*index_html* method::
-
-  <tal:block define="mirror python: modules.random.choice(here.mirrors);
-  dummy python: request.RESPONSE.redirect(mirror)" />
-
-This code will redirect any visitors to *www.zopezoo.org* to a random mirror
-server.
-
-Using Round-robin DNS to Distribute Load
-++++++++++++++++++++++++++++++++++++++++
-
-The *Domain Name System*, or DNS, is the Internet mechanism that translates
-computer names (like "www.zope.org") into numeric addresses. This mechanism can
-map one name to many addresses.
-
-The simplest method for load-balancing is to use round-robin DNS, as
-illustrated in the figure below.
-
-`Load balancing with round-robin DNS. <img:20-3:Figures/11-3.png>`_
-
-When *www.zopezoo.org* gets resolved, DNS answers with the address of either
-*zeoclient1*, *zeoclient2*, or *zeoclient3* - but in a rotated order every
-time. For example, one user may resolve *www.zopezoo.org* and get the address
-for *zeoclient1*, and another user may resolve *www.zopezoo.org* and get the
-address for *zeoclient2*. This way your users are spread over the various ZEO
-clients.
-
-This not a perfect load balancing scheme, because DNS information gets cached
-by the other nameservers on the Internet. Once a user has resolved
-*www.zopezoo.org* to a particular ZEO client, all subsequent requests for that
-user also go to the same ZEO client. The final result is generally acceptable,
-because the total sum of the requests are really spread over your various ZEO
-clients.
-
-One potential problem with this solution is that it can take hours or days for
-name servers to refresh their cached copy of what they think the address of
-*www.zopezoo.org* is. If you are not responsible for the maintenance of your
-ZEO clients and one fails, then 1/Nth of your users (where N is the number of
-ZEO clients) will not be able to reach your site until their name server cache
-refreshes.
-
-Configuring your DNS server to do round-robin name resolution is an advanced
-technique that is not covered in this book. A good reference on how to do this
-can be found in the `Apache Documentation
-<http://www.engelschall.com/pw/apache/rewriteguide/#ToC29>`_.
-
-Distributing the load with round-robin DNS is useful, and cheap, but not 100%
-effective. DNS servers can have strange caching policies, and you are relying
-on a particular quirk in the way DNS works to distribute the load. The next
-section describes a more complex, but much more powerful way of distributing
-load called *Layer 4 Switching*.
-
-Using Layer 4 Switching to Distribute Load
-++++++++++++++++++++++++++++++++++++++++++
-
-Layer 4 switching lets one computer transparently hand requests to a farm of
-computers. This is an advanced technique that is largely beyond the scope of
-this book, but it is worth pointing out several products that do Layer 4
-switching for you.
-
-Layer 4 switching involves a *switch* that, according to your preferences,
-chooses from a group of ZEO clients whenever a request comes in, as shown in
-the figure below.
-
-`Illustration of Layer 4 switching <img:20-4:Figures/11-4.png>`_
-
-There are hardware and software Layer 4 switches. There are a number of
-software solutions, but one in general that stands out is the *Linux Virtual
-Server* (LVS). This is an extension to the free Linux operating system that
-lets you turn a Linux computer into a Layer 4 switch. More information on the
-LVS can be found on `its website <http://www.linuxvirtualserver.org>`_.
-
-There are also a number of hardware solutions that claim higher performance
-than software based solutions like LVS. Cisco Systems has a hardware router
-called LocalDirector that works as a Layer 4 switch, and Alteon also makes a
-popular Layer 4 switch.
-
-Other software-based solutions
-++++++++++++++++++++++++++++++
-
-If you are looking for a simple load balancer and proxy software to put in
-front of your ZEO clients you can take a look at the `Pound load balancer
-<http://www.apsis.ch/pound/>`_ which can be set up quickly and offers many
-convenient features.
-
-Many administrators will want to cache content and load balance at the same
-time. The `Squid cache server <http://www.squid-cache.org/>`_ is an excellent
-choice. Toby Dickenson has written up a `HowTo
-<http://www.zope.org/Members/htrd/howto/squid>`_ describing a configuration in
-which Squid caches and balances the load among several ZEO clients.
-
-Dealing with the Storage Server as A Single Point of Failure
-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-Without ZEO, a single Zope system is a single point of failure. ZEO allows you
-to spread that point of failure around to many different computers. If one of
-your ZEO clients fails, other clients can answer requests on the failed clients
-behalf.
-
-However, in a typical ZEO setup there is still a single point of failure: the
-ZEO server itself. Without using commercial software, this single point of
-failure cannot be removed.
-
-One popular method is to accept the single point of failure risk and mitigate
-that risk as much as possible by using very high-end, reliable equipment for
-your ZEO server, frequently backing up your data, and using inexpensive,
-off-the-shelf hardware for your ZEO clients. By investing the bulk of your
-infrastructure budget on making your ZEO server rock solid (redundant power
-supplies, RAID, and other fail-safe methods) you can be pretty well assured
-that your ZEO server will remain up, even if a handful of your inexpensive ZEO
-clients fail.
-
-Some applications, however, require absolute one-hundred-percent uptime. There
-is still a chance, with the solution described above, that your ZEO server will
-fail. If this happens, you want a backup ZEO server to jump in and take over
-for the failed server right away.
-
-Like Layer 4 switching, there are a number of products, software and hardware,
-that may help you to create a backup storage server. One popular software
-solution for linux is called `fake <http://vergenet.net/linux/fake/>`_. Fake is
-a Linux-based utility that can make a backup computer take over for a failed
-primary computer by "faking out" network addresses. When used in conjunction
-with monitoring utilities like `mon <http://www.kernel.org/software/mon/>`_ or
-`heartbeat <http://www.linux-ha.org/>`_, fake can guarantee almost 100% up-time
-of your ZEO server and Layer 4 switches. Using `fake` in this way is beyond the
-scope of this book.
-
-ZEO also has a commercial "multiple-server" configuration which provides for
-redundancy at the storage level. Zope Corporation sells a commercial product
-named `Zope Replication Services <http://www.zope.com/Products/ZRS.html>`_ that
-provides redundancy in storage server services. It allows a "secondary" storage
-server to take over for a "primary" server when the primary fails.
-
-ZEO Server Details
-++++++++++++++++++
-
-The final piece of the puzzle is where the ZEO server stores its information.
-If your primary ZEO server fails, how can your backup ZEO server ensure it has
-the most recent information that was contained in the primary server?
-
-Before explaining the details of how the ZEO server works, it is worth
-understanding some details about how Zope *storages* work in general.
-
-Zope does not save any of its object or information directly to disk. Instead,
-Zope uses a *storage* component that takes care of all the details of where
-objects should be saved.
-
-This is a very flexible model, because Zope no longer needs to be concerned
-about opening files, or reading and writing from databases, or sending data
-across a network (in the case of ZEO). Each particular storage takes care of
-that task on Zope's behalf.
-
-For example, a plain, stand-alone Zope system can be illustrated in the figure
-below.
-
-`Zope connected to a filestorage <img:20-5:Figures/11-5.png>`_
-
-You can see there is one Zope application which plugs into a *FileStorage*.
-This storage, as its name implies, saves all of its information to a file on
-the computer's filesystem.
-
-When using ZEO, you simple replace the FileStorage with a *ClientStorage*, as
-illustrated in the figure below.
-
-`Zope with a Client Storage and Storage server <img:20-6:Figures/11-6.png>`_
-
-Instead of saving objects to a file, a ClientStorage sends objects over a
-network connection to a *Storage Server*. As you can see in the illustration,
-the Storage Server uses a FileStorage to save that information to a file on the
-ZEO server's filesystem. In a "stock" ZEO setup, this storage file is in the
-same place as it would be were you not running ZEO (within your Zope
-directory's `var` directory named `Data.fs`).
-
-Ongoing Maintenance
-===================
-
-A ZEO server does not need much in terms of care and feeding. You need to make
-sure the ZODB does not grow too large and pack it once in a while, and you
-should rotate the server logs.
-
-Packing
-+++++++
-
-FileStorage, the most common ZODB database format, works by appending changes
-at the file end. That means it will grow with time. To avoid running out of
-space it can be *packed*, a process that will remove old object revisions and
-shrink the ZODB. Zope comes with a handy utility script to do this task, and
-you can run it in an automated fashion like out of `cron` . Look for a script
-named `zeopack.py` underneath ZODBTools in the utilities directory of your Zope
-installation.
-
-Given a setup where the ZEO server is listening on port 8001 on localhost, you
-pack it this way::
-
-  $ python /path/to/Zope/utilities/ZODBTools/zeopack.py -h localhost -p 8001
-
-Make sure you use the same version of Python that is used to run the ZEO
-server.
-
-Log Rotation
-++++++++++++
-
-ZEO by default keeps a single event log. It is located in the *log*
-subdirectory of your ZEO server's home and can be configured using the
-`zeo.conf` configuration file. Depending on the level of logging specified and
-server traffic the file can grow quite quickly.
-
-The `zeoctl` script in your ZEO storage home has a facility to effect the
-closing and reopening of the log file. All you need to do is move the old log
-aside and tell the server to start a new one::
-
-  $ cd /path/to/zeostorage
-  $ mv logs/zeo.log logs/zeo.log.1
-  $ bin/zeoctl logreopen
-
-These steps can be automated via `cron`, at on Windows or the handy `logrotate`
-facility on Linux. Here is an example logrotate script that can be dropped into
-'/etc/logrotate.d'::
-
-  # Rotate ZEO logs weekly
-  /path/to/zeostorage/log/zeo.log {
-      weekly
-      rotate 5
-      compress
-      notifempty
-      missingok
-      postrotate
-      /path/to/zeostorage/bin/zeoctl logreopen
-      endscript
-  }
-
-
-ZEO Caveats
-===========
-
-For the most part, running ZEO is exactly like running Zope by itself, but
-there are a few issues to keep in mind.
-
-First, it takes longer for information to be written to the Zope object
-database. This does not slow down your ability to use Zope (because Zope does
-not block you during this write operation) but it does increase your chances of
-getting a *ConflictError*. Conflict errors happen when two ZEO clients try to
-write to the same object at the same time. One of the ZEO clients wins the
-conflict and continues on normally. The other ZEO client loses the conflict and
-has to try again.
-
-Conflict errors should be as infrequent as possible because they could slow
-down your system. While it's normal to have a *few* conflict errors (due to the
-concurrent nature of Zope) it is abnormal to have *many* conflict errors. The
-pathological case is when more than one ZEO client tries to write to the same
-object over and over again very quickly. In this case, there will be lots of
-conflict errors, and therefore lots of retries. If a ZEO client tries to write
-to the database three times and gets three conflict errors in a row, then the
-request is aborted and the data is not written.
-
-Because ZEO takes longer to write this information, the chances of getting a
-ConflictError are higher than if you are not running ZEO. Because of this, ZEO
-is more *write sensitive* than running Zope without ZEO. You may have to keep
-this in mind when you are designing your network or application. As a rule of
-thumb, more and more frequent writes to the database increase your chances of
-getting a ConflictError. However, faster and more reliable network connections
-and computers lower your chances of getting a ConflictError. By taking these
-two factors into account, conflict errors can be mostly avoided.
-
-ZEO servers do not have any in-memory cache for frequently or recently accessed
-items. Every request for an object from a ZEO client will cause a read from
-disk. While some of that read activity is served by operating system level disk
-caches or hardware caches built into the drive itself it can still make the
-server quite busy if multiple ZEO clients are in use. It is good practice to
-ensure that a busy ZEO server has a fast disk.
-
-To maximize serving speed for ZEO clients (which necessitates minimizing trips
-to the ZEO server for retrieving content) it is advisable to keep a large ZEO
-client cache. This cache keeps frequently accessed objects in memory on the ZEO
-client. The cache size is set inside the `zeoclient` stanza in the `zodb_db
-main` section of your ZEO client's `zope.conf` file. Using the key `cache-size`
-you can specify an integer value for the number of bytes used as the ZEO cache.
-By default this is set to a value of 20000000, which equates about 20 MB. Zope
-allows you to use a simpler format such as *256MB* for the cache-size key.
-
-Conclusion
-==========
-
-In this chapter we looked at ZEO, and how ZEO can substantially increase the
-capacity of your website. In addition to running ZEO on one computer to get
-familiarized, we looked at running ZEO on many computers, and various
-techniques for spreading the load of your visitors among those many computers.
-
-ZEO is not a "magic bullet" solution, and like other system designed to work
-with many computers, it adds another level of complexity to your website. This
-complexity pays off however when you need to serve up lots of dynamic content
-to your audience.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/ZPT.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/ZPT.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/ZPT.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,913 +0,0 @@
-Using Zope Page Templates
-=========================
-
-*Page Templates* are a web page generation tool.  They help programmers and
-designers collaborate in producing dynamic web pages for Zope web
-applications.  Designers can use them to maintain pages without having to
-abandon their tools, while preserving the work required to embed those pages
-in an application.
-
-In this chapter, you'll learn the basic features of *Page Templates*,
-including how you can use them in your website to create dynamic web pages
-easily.  The next chapter walks you through a "hands on" example showing how
-to build a Zope web application using scripts and *Page Templates*.  In the
-chapter entitled `Advanced Page Templates <AdvZPT.html>`_, you'll learn about
-advanced *Page Template* features.
-
-The goal of *Page Templates* is to allow designers and programmers to work
-together easily.  A designer can use a WYSIWYG HTML editor to create a
-template, then a programmer can edit it to make it part of an application.
-If required, the designer can load the template *back* into his editor and
-make further changes to its structure and appearance.  By taking reasonable
-steps to preserve the changes made by the programmer, the designer will not
-disrupt the application.
-
-*Page Templates* aim at this goal by adopting three principles:
-
-1. Play nicely with editing tools.
-
-2. What you see is very similar to what you get.
-
-3. Keep code out of templates, except for structural logic.
-
-A Page Template is like a model of the pages that it will generate.  In
-particular, it is parseable by most HTML tools.
-
-HTML Page Templates
--------------------
-
-*Page Templates* can operate in two modes: *HTML Mode* and *XML Mode*.
-Later in this chapter we will show you how to use the *XML Mode*, but in
-most cases we want to use the *HTML Mode* which is also the default mode.
-For the *HTML Mode* the *Content-Type* has to be set to 'text/html'.
-
-HTML isn't XML-conform and can't be extended by a template language.  So
-while rendered HTML *Page Templates* should return valid HTML, their
-source code isn't valid HTML or XML.  But the *Template Attribute
-Language* (*TAL*) does a good job in hiding itself in HTML tags, so most
-HTML tools will be able to parse the source of HTML *Page Templates* and
-just ignore the *TAL* attributes.
-
-As you might already know, XHTML is a XML-conform reformulation of HTML
-and widely used in our days.  Nevertheless, generating HTML and XHTML
-with *Page Templates* works exactly the same way.  While the *HTML Mode*
-doesn't enforce well-formed XML, it's absolutely fine to use this mode
-also for XHTML.
-
-How Page Templates Work
-~~~~~~~~~~~~~~~~~~~~~~~
-
-*Page Templates* use the *Template Attribute Language* (*TAL*).  *TAL*
-consists of special tag attributes.  For example, a dynamic page
-headline might look like this::
-
-  <h1 tal:content="context/title">Sample Page Title</h1>
-
-The 'tal:content' attribute is a *TAL* statement.  Since it has an XML
-namespace (the 'tal:' part) most editing tools will not complain that
-they don't understand it, and will not remove it.  It will not change
-the structure or appearance of the template when loaded into a WYSIWYG
-editor or a web browser.  The name *content* indicates that it will set
-the text contained by the 'h1' tag, and the value 'context/title' is an
-expression providing the text to insert into the tag.  Given the text
-specified by 'context/title' resolves to "Susan Jones Home Page", the
-generated HTML snippet looks like this::
-
-  <h1>Susan Jones Home Page</h1>
-
-All *TAL* statements consist of tag attributes whose name starts with
-'tal:' and all *TAL* statements have values associated with them.  The
-value of a *TAL* statement is shown inside quotes.  See Appendix C,
-`Zope Page Templates Reference <AppendixC.html>`_, for more information
-on *TAL*.
-
-To the HTML designer using a WYSIWYG tool, the dynamic headline example
-is perfectly parseable HTML, and shows up in their editor looking like a
-headline should look like.  In other words, *Page Templates* play nicely
-with editing tools.
-
-This example also demonstrates the principle that "What you see is very
-similar to what you get".  When you view the template in an editor, the
-headline text will act as a placeholder for the dynamic headline text.
-The template provides an example of how generated documents will look.
-
-When this template is saved in Zope and viewed by a user, Zope turns the
-dummy content into dynamic content, replacing "Sample Page Title" with
-whatever 'context/title' resolves to.  In this case, 'context/title'
-resolves to the title of the object to which the template is applied.
-This substitution is done dynamically, when the template is viewed.
-
-There are template statements for replacing entire tags, their contents,
-or just some of their attributes.  You can repeat a tag several times or
-omit it entirely.  You can join parts of several templates together, and
-specify simple error handling.  All of these capabilities are used to
-generate document structures.  Despite these capabilities, you **can't**
-create subroutines or classes, perform complex flow control, or easily
-express complex algorithms using a *Page Template*.  For these tasks,
-you should use Python-based Scripts or application components.
-
-The *Page Template* language is deliberately not as powerful and
-general-purpose as it could be.  It is meant to be used inside of a
-framework (such as Zope) in which other objects handle business logic
-and tasks unrelated to page layout.
-
-For instance, template language would be useful for rendering an invoice
-page, generating one row for each line item, and inserting the
-description, quantity, price, and so on into the text for each row.  It
-would not be used to create the invoice record in a database or to
-interact with a credit card processing facility.
-
-Creating a Page Template
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Use your web browser to log into the Zope Management Interface as a manager.
-Create a *Folder* to work in named 'template_test' in the root of your Zope.
-Visit this folder and choose *Page Template* from Zope's add list. Type
-'simple_page' in the add form's *Id* field, then push the *Add and Edit*
-button.
-
-You should now see the main editing page for the new *Page Template*.
-The title is blank and the default template text is in the editing area.
-
-Now let's create a simple dynamic page.  Type the words 'a Simple Page'
-in the *Title* field.  Then, edit the template text to look like this::
-
-  <html>
-    <body>
-      <p>
-        This is <b tal:content="template/title">the Title</b>.
-      </p>
-    </body>
-  </html>
-
-Now push the *Save Changes* button.  Zope should show a message
-confirming that your changes have been saved.
-
-If you get an error message, check to make sure you typed the example
-correctly and save it again.
-
-Click on the *Test* tab.  You should see a page with "This is **a Simple
-Page**." at the top.  Notice that the title is bold.  This is because
-the 'tal:content' statement just replaces the content of the *bold* tag.
-
-Back up, then click on the *Browse HTML source* link under the
-*Content-Type* field.  This will show you the *unrendered* source of the
-template.  You should see, "This is **the Title**." The bold text acts
-as a placeholder for the dynamic title text.  Back up again, so that you
-are ready to edit the example further.
-
-You can find two options on the *Edit* tab we will not touch for now:
-The *Content-Type* field allows you to specify the content type of
-your page.  Changing that value switches the *Page Template* into *XML
-Mode*, discussed later in this chapter.  The *Expand macros with
-editing* control is explained in the "Macros" section of this chapter.
-
-*TALES* Expressions
-~~~~~~~~~~~~~~~~~~~
-
-The expression "template/title" in your simple Page Template is a *path
-expression*.  This is the most common type of expression.  There are
-several other types of expressions defined by the *TAL Expression
-Syntax* (*TALES*) specification.  For more information on TALES see
-Appendix C, `Zope Page Templates Reference`_.
-
-Path Expressions
-%%%%%%%%%%%%%%%%
-
-The 'template/title' *path expression* fetches the *title* attribute
-of the template.  Here are some other common path expressions:
-
-- 'context/objectValues': A list of the sub-objects of the folder on
-  which the template is called.
-
-- 'request/URL': The URL of the current web request.
-
-- 'user/getUserName': The authenticated user's login name.
-
-From the last chapter you should already be familiar with the context
-variable that is also available in *Python-based Scripts* and the
-attribute 'objectValues' that specifies an API method.  The other two
-examples are just to show you the pattern.  You will learn more about
-them later in the book.
-
-To see what these examples return, just copy the following lines into
-a *Page Template* and select the *Test* tab.  You'll notice that
-'context/objectValues' returns a list that needs further treatment to
-be useful.  We'll come back to that later in this chapter::
-
-  <p tal:content="context/objectValues"></p>
-  <p tal:content="request/URL"></p>
-  <p tal:content="user/getUserName"></p>
-
-Every *path expression* starts with a variable name.  The available
-variable names refer either to objects like *context*, *request* or
-*user* that are bound to every *Page Template* by default or variables
-defined within the *Page Template* using TAL.  Note that *here* is an
-old alias of *context* and still used in many places.
-
-The small set of built-in variables such as *request* and *user* is
-described in the chapter entitled `Advanced Page Templates`_.
-You will also learn how to define your own variables in that chapter.
-
-If the variable itself returns the value you want, you are done.
-Otherwise, you add a slash ('/') and the name of a sub-object or
-attribute.  You may need to work your way through several
-sub-objects to get to the value you're looking for.
-
-Python Expressions
-%%%%%%%%%%%%%%%%%%
-
-A good rule of thumb is that if you need Python to express your logic,
-you better factor out the code into a script.  But Zope is a good tool
-for prototyping and sometimes it would be overkill to write a script
-for one line of code.  And looking at existing products you will see
-quite often 'Python expressions', so it's better to know them.
-
-Recall the first example of this chapter::
-
-  <h1 tal:content="context/title">Sample Page Title</h1>
-
-Let's try to rewrite it using a *Python expression*::
-
-  <h1 tal:content="python: context.title">Sample Page Title</h1>
-
-While *path expressions* are the default, we need a prefix to indicate other
-expression types. This expression with the prefix 'python:' does (at least
-here) the same as the *path expression* above. *Path expressions* try different
-ways to access 'title', so in general they are more flexible, but less
-explicit.
-
-There are some simple things you can't do with *path expressions*.
-The most common are comparing values like in::
-
-  "python: variable1 == variable2"
-
-... or passing arguments to methods, e.g.::
-
-  "python: context.objectValues(['Folder'])"
-
-*TAL* Attributes
-~~~~~~~~~~~~~~~~
-
-*Page Templates* are example pages or snippets.  *TAL* statements define
-how to convert them dynamically.  Depending on the used *TAL* attribute
-they substitute example content or attributes by dynamic values, or
-remove or repeat example elements depending on dynamic values.
-
-Inserting Text
-%%%%%%%%%%%%%%
-
-  In your "simple_page" template, you used the 'tal:content' statement
-  on a *bold* tag.  When you tested it, Zope replaced the content of the
-  HTML *bold* element with the title of the template.
-
-  This is easy as long as we want to replace the complete content of an
-  HTML element.  But what if we want to replace only some words within
-  an element?
-
-  In order to place dynamic text inside of other text, you typically use
-  'tal:replace' on an additional 'span' tag.  For example, add the
-  following lines to your example::
-
-    <p>The URL is
-      <span tal:replace="request/URL">
-        http://www.example.com</span>.</p>
-
-  The 'span' tag is structural, not visual, so this looks like "The URL
-  is http://www.example.com." when you view the source in an editor or
-  browser.  When you view the rendered version, however, it may look
-  something like::
-
-    The URL is http://localhost:8080/template_test/simple_page.
-
-  If you look at the source code of the rendered version, the *span*
-  tags are removed.
-
-  To see the difference between 'tal:replace' and 'tal:content', create
-  a page template and include the following in the body::
-
-    <b tal:content="template/title"></b>
-    <b tal:content="request/URL"></b>
-    <b tal:content="user/getUserName"></b>
-    <b tal:replace="template/title"></b>
-    <b tal:replace="request/URL"></b>
-    <b tal:replace="user/getUserName"></b>
-
-  There are two other ways to add elements that are only needed for
-  *TAL* attributes and that are removed again in the rendered version::
-
-    <p>The URL is
-      <span tal:content="request/URL" tal:omit-tag="">
-        http://www.example.com</span>.</p>
-
-  ... which is more useful in other situations and will be discussed
-  there and::
-
-    <p>The URL is
-      <tal:span tal:content="request/URL">
-        http://www.example.com</tal:span>.</p>
-
-  While you can get really far by using HTML elements and 'tal:replace'
-  or 'tal:omit-tag', some people prefer to use *TAL* elements if the
-  elements are only used to add *TAL* attributes.  *TAL* is an attribute
-  language and doesn't define any elements like 'tal:span', but it uses
-  a complete XML namespace and allows to use any element name you like.
-  They are silently removed while the *Page Template* is rendered.
-
-  This is useful for using speaking names like 'tal:loop', 'tal:case' or
-  'tal:span' and to insert additional elements where HTML doesn't allow
-  elements like 'span' or 'div'.  And if her browser or editor also
-  ignores these tags, the designer will have less trouble with *TAL*
-  elements than with additional HTML elements.
-
-Repeating Structures
-%%%%%%%%%%%%%%%%%%%%
-
-Let's start with a simple three-liner::
-
-  <p tal:repeat="number python: range(4)" tal:content="number">
-    999
-  </p>
-
-'number' is our *repeat variable* and 'range(4)' is a *Python
-expression* that returns the list '[0, 1, 2, 3]'.  If this code is
-rendered, the 'repeat' statement repeats the *paragraph* element for
-each value of the sequence, replacing the variable 'number' by the
-current sequence value.  So the rendered page will not show the
-example number '999', but 4 *paragraph* elements containing the
-numbers of our list.
-
-In most cases we want to iterate over more complex sequences.  Our
-next example shows how to use a sequence of (references to) objects.
-The 'simple_page' template could be improved by adding an item list,
-in the form of a list of the objects that are in the same *Folder* as
-the template.  You will make a table that has a row for each object,
-and columns for the id, meta-type and title.  Add these lines to the
-bottom of your example template::
-
-  <table border="1" width="100%">
-    <tr>
-      <th>Id</th>
-      <th>Meta-Type</th>
-      <th>Title</th>
-    </tr>
-    <tr tal:repeat="item context/objectValues">
-      <td tal:content="item/getId">Id</td>
-      <td tal:content="item/meta_type">Meta-Type</td>
-      <td tal:content="item/title">Title</td>
-    </tr>
-  </table>
-
-The 'tal:repeat' statement on the table row means "repeat this row for
-each item in my context's list of object values".  The *repeat*
-statement puts the objects from the list into the *item* variable one
-at a time (this is called the *repeat variable*), and makes a copy of
-the row using that variable.  The value of 'item/getId' in each row is
-the Id of the object for that row, and likewise with 'item/meta_type'
-and 'item/title'.
-
-You can use any name you like for the repeat variable ("item" is only
-an example), as long as it starts with a letter and contains only
-letters, numbers, and underscores ('_').  The repeat variable is only
-defined in the repeat tag.  If you try to use it above or below the
-*tr* tag you will get an error.
-
-You can also use the repeat variable name to get information about the
-current repetition.  See `Advanced Page Templates`_.
-
-Now view the page and notice how it lists all the objects in the same
-folder as the template.  Try adding or deleting objects from the
-folder and notice how the page reflects these changes.
-
-Conditional Elements
-%%%%%%%%%%%%%%%%%%%%
-
-Using Page Templates you can dynamically query your environment and
-selectively insert text depending on conditions.  For example, you
-could display special information in response to a cookie::
-
-  <p tal:condition="request/cookies/verbose | nothing">
-    Here's the extra information you requested.
-  </p>
-
-This paragraph will be included in the output only if there is a
-'verbose' cookie set.  The expression, 'request/cookies/verbose |
-nothing' is true only when there is a cookie named 'verbose' set.
-You'll learn more about this kind of expression in the chapter
-entitled `Advanced Page Templates`_.
-
-Using the 'tal:condition' statement you can check all kinds of
-conditions.  A 'tal:condition' statement leaves the tag and its
-contents in place if its expression has a true value, but removes them
-if the value is false.  Zope considers the number zero, a  blank
-string, an empty list, and the built-in variable 'nothing' to be false
-values.  Nearly every other value is true, including non-zero numbers,
-and strings with anything in them (even spaces!).
-
-Another common use of conditions is to test a sequence to see if it is
-empty before looping over it.  For example in the last section you saw
-how to draw a table by iterating over a collection of objects.  Here's
-how to add a check to the page so that if the list of objects is empty
-no table is drawn.
-
-To allow you to see the effect, we first have to modify that example
-a bit, showing only *Folder* objects in the context folder.  Because
-we can't specify parameters using *path expressions* like
-'context/objectValues', we first convert it into the *Python
-expression* 'context.objectValues()' and then add the argument that
-tells the 'objectValues' method to return only sub-folders::
-
-  <tr tal:repeat="item python: context.objectValues(['Folder'])">
-
-If you did not add any sub-folders to the *template_test* folder so
-far, you will notice that using the *Test* tab the table header is
-still shown even if we have no table body.  To avoid this we add a
-'tal:condition' statement in the table tag.  The complete table now
-looks like this::
-
-  <table tal:condition="python: context.objectValues(['Folder'])"
-         border="1" width="100%">
-    <tr>
-      <th>Id</th>
-      <th>Meta-Type</th>
-      <th>Title</th>
-    </tr>
-    <tr tal:repeat="item python: context.objectValues(['Folder'])">
-      <td tal:content="item/getId">Id</td>
-      <td tal:content="item/meta_type">Meta-Type</td>
-      <td tal:content="item/title">Title</td>
-    </tr>
-  </table>
-
-If the list of sub-folders is an empty list, the condition is false
-and the entire table is omitted.  You can verify this by using the
-*Test* tab again.
-
-Go and add three Folders named '1', '2', and '3' to the
-*template_test* folder in which your *simple_page* template lives.
-Revisit the *simple_page* template and view the rendered output via
-the *Test* tab.  You will see a table that looks much like the below::
-
-  Id          Meta-Type          Title
-  1           Folder
-  2           Folder
-  3           Folder
-
-Changing Attributes
-%%%%%%%%%%%%%%%%%%%
-
-Most, if not all, of the objects listed by your template have an
-*icon* attribute that contains the path to the icon for that kind of
-object.  In order to show this icon in the meta-type column, you will
-need to insert this path into the 'src' attribute of an 'img' tag.
-Edit the table cell in the meta-type column of the above example to
-look like this::
-
-  <td><img src="file_icon.gif"
-           tal:attributes="src item/icon" />
-    <span tal:replace="item/meta_type">Meta-Type</span></td>
-
-The 'tal:attributes' statement replaces the 'src' attribute of the
-'img' tag with the value of 'item/icon'.  The 'src` attribute in the
-template (whose value is "file_icon.gif") acts as a placeholder.
-
-Notice that we've replaced the 'tal:content' attribute on the table
-cell with a 'tal:replace' statement on a 'span' tag.  This change
-allows you to have both an image and text in the table cell.
-
-XML Page Templates
-------------------
-
-Creating XML with *Page Templates* is almost exactly like creating HTML.
-You switch to *XML Mode* by setting the *content-type* field to
-'text/xml' or whatever the content-type for your XML should be.
-
-In *XML Mode* no "loose" markup is allowed.  Zope assumes that your
-template is well-formed XML.  Zope also requires an explicit TAL and METAL
-XML namespace declarations in order to emit XML.  For example, if you wish
-to emit XHTML, you might put your namespace declarations on the 'html'
-tag::
-
-  <html xmlns:tal="http://xml.zope.org/namespaces/tal"
-    xmlns:metal="http://xml.zope.org/namespaces/metal">
-
-To browse the source of an XML template you go to 'source.xml' rather than
-'source.html'.
-
-Debugging and Testing
-
-Zope helps you find and correct problems in your *Page Templates*.  Zope
-notices problems at two different times: when you're editing a *Page
-Template*, and when you're viewing a *Page Template*.  Zope catches
-different types of problems when you're editing and than when you're
-viewing a *Page Template*.
-
-You may have already seen the trouble-shooting comments that Zope inserts
-into your Page Templates when it runs into problems.  These comments tell
-you about problems that Zope finds while you're editing your templates.
-The sorts of problems that Zope finds when you're editing are mostly
-errors in your *TAL* statements.  For example::
-
-  <!-- Page Template Diagnostics
-   Compilation failed
-   TAL.TALDefs.TALError: bad TAL attribute: 'contents', at line 10, column 1
-  -->
-
-This diagnostic message lets you know that you mistakenly used
-'tal:contents' rather than 'tal:content' on line 10 of your template.
-Other diagnostic messages will tell you about problems with your template
-expressions and macros.
-
-When you're using the Zope management interface to edit *Page Templates*
-it's easy to spot these diagnostic messages, because they are shown in the
-"Errors" header of the management interface page when you save the *Page
-Template*.
-
-If you don't notice the diagnostic message and try to render a template
-with problems you'll see a message like this::
-
-  Error Type: PTRuntimeError
-  Error Value: Page Template hello.html has errors.
-
-That's your signal to reload the template and check out the diagnostic
-message.
-
-In addition to diagnostic messages when editing, you'll occasionally get
-regular Zope errors when viewing a Page Template.  These problems are
-usually due to problems in your template expressions.  For example, you
-might get an error if an expression can't locate a variable::
-
-  Error Type: KeyError
-  Error Value: 'unicorn'
-
-This error message tells you that it cannot find the *unicorn* variable.
-To help you figure out what went wrong, Zope includes information about
-the environment in the traceback.  This information will be available in
-your *error_log* (in your Zope root folder).  The traceback will include
-information about the place where the error occurred and the environment::
-
-  URL: /sandbox/demo
-  Line 1, Column 14
-  Expression: standard:'context/unicorn'
-  Names:
-    {'container': <Folder instance at 019AC4D0>,
-     'context': <Application instance at 01736F78>,
-     'default': <Products.PageTemplates.TALES.Default instance at 0x012F9D00>,
-     ...
-     'root': <Application instance at 01736F78>,
-     'template': <ZopePageTemplate at /sandbox/demo>,
-     'traverse_subpath': [],
-     'user': admin}
-
-This information is a bit cryptic, but with a little detective work it can
-help you figure out what went wrong.  In this case, it tells us that the
-'context' variable is an "Application instance".  This means that it is
-the top-level Zope folder (notice how 'root' variable is the same
-"Application instance").  Perhaps the problem is that you wanted to apply
-the template to a folder that had a *unicorn* property, but the root on
-which you called the template hasn't such a property.
-
-Macros
-------
-
-So far, you've seen how *Page Templates* can be used to add dynamic
-behavior to individual web pages.  Another feature of page templates is
-the ability to reuse look and feel elements across many pages.
-
-For example, with *Page Templates*, you can have a site that has a
-standard look and feel.  No matter what the "content" of a page, it will
-have a standard header, side-bar, footer, and/or other page elements.
-This is a very common requirement for websites.
-
-You can reuse presentation elements across pages with *macros*.  Macros
-define a section of a page that can be reused in other pages.  A macro can
-be an entire page, or just a chunk of a page such as a header or footer.
-After you define one or more macros in one *Page Template*, you can use
-them in other *Page Templates*.
-
-Using Macros
-~~~~~~~~~~~~
-
-You can define macros with tag attributes similar to *TAL* statements.
-Macro tag attributes are called *Macro Expansion Tag Attribute Language*
-(*METAL*) statements.  Here's an example macro definition::
-
-  <p metal:define-macro="copyright">
-    Copyright 2009, <em>Foo, Bar, and Associates</em> Inc.
-  </p>
-
-This 'metal:define-macro' statement defines a macro named "copyright".
-The macro consists of the 'p' element (including all contained elements,
-ending with the closing 'p' tag).
-
-Macros defined in a Page Template are stored in the template's *macros*
-attribute.  You can use macros from other *Page Templates* by referring
-to them through the *macros* attribute of the *Page Template* in which
-they are defined.  For example, suppose the *copyright* macro is in a
-*Page Template* called "master_page".  Here's how to use the *copyright*
-macro from another *Page Template*::
-
-  <hr />
-  <b metal:use-macro="container/master_page/macros/copyright">
-    Macro goes here
-  </b>
-
-In this *Page Template*, the 'b' element will be completely replaced by
-the macro when Zope renders the page::
-
-  <hr />
-  <p>
-    Copyright 2009, <em>Foo, Bar, and Associates</em> Inc.
-  </p>
-
-If you change the macro (for example, if the copyright holder changes)
-then all *Page Templates* that use the macro will automatically reflect
-the change.
-
-Notice how the macro is identified by a *path expression* using the
-'metal:use-macro' statement.  The 'metal:use-macro' statement replaces
-the statement element with the named macro.
-
-Macro Details
-~~~~~~~~~~~~~
-
-The 'metal:define-macro' and 'metal:use-macro' statements are pretty
-simple.  However there are a few subtleties to using them which are
-worth mentioning.
-
-A macro's name must be unique within the Page Template in which it is
-defined.  You can define more than one macro in a template, but they all
-need to have different names.
-
-Normally you'll refer to a macro in a 'metal:use-macro' statement with a
-path expression.  However, you can use any expression type you wish so
-long as it returns a macro.  For example::
-
-  <p metal:use-macro="python:context.getMacro()">
-    Replaced with a dynamically determined macro,
-    which is located by the getMacro script.
-  </p>
-
-In this case the path expression returns a macro defined dynamically by
-the 'getMacro' script.  Using *Python expressions* to locate macros lets
-you dynamically vary which macro your template uses.  An example
-of the body of a "getMacro" Script (Python) is as follows::
-
-  return container.ptMacros.macros['amacroname']
-
-You can use the 'default' variable with the 'metal:use-macro'
-statement::
-
-  <p metal:use-macro="default">
-    This content remains - no macro is used
-  </p>
-
-The result is the same as using *default* with 'tal:content' and
-'tal:replace'.  The "default" content in the tag doesn't change when it
-is rendered.  This can be handy if you need to conditionally use a macro
-or fall back on the default content if it doesn't exist.
-
-If you try to use the 'nothing' variable with 'metal:use-macro' you will
-get an error, since 'nothing' is not a macro.  If you want to use
-'nothing' to conditionally include a macro, you should instead enclose
-the 'metal:use-macro' statement with a 'tal:condition' statement.
-
-Zope handles macros first when rendering your templates.  Then Zope
-evaluates TAL expressions.  For example, consider this macro::
-
-  <p metal:define-macro="title"
-     tal:content="template/title">
-    template's title
-  </p>
-
-When you use this macro it will insert the title of the template in
-which the macro is used, *not* the title of the template in which the
-macro is defined.  In other words, when you use a macro, it's like
-copying the text of a macro into your template and then rendering your
-template.
-
-If you check the *Expand macros when editing* option on the *Page
-Template* *Edit* view, then any macros that you use will be expanded in
-your template's source.
-
-Using Slots
-~~~~~~~~~~~
-
-Macros are much more useful if you can override parts of them when you
-use them.  You can do this by defining *slots* in the macro that you can
-fill in when you use the template.  For example, consider a side bar
-macro::
-
-  <div metal:define-macro="sidebar">
-    Links
-    <ul>
-      <li><a href="/">Home</a></li>
-      <li><a href="/products">Products</a></li>
-      <li><a href="/support">Support</a></li>
-      <li><a href="/contact">Contact Us</a></li>
-    </ul>
-  </div>
-
-This macro is fine, but suppose you'd like to include some additional
-information in the sidebar on some pages.  One way to accomplish this is
-with slots::
-
-  <div metal:define-macro="sidebar">
-    Links
-    <ul>
-      <li><a href="/">Home</a></li>
-      <li><a href="/products">Products</a></li>
-      <li><a href="/support">Support</a></li>
-      <li><a href="/contact">Contact Us</a></li>
-    </ul>
-    <span metal:define-slot="additional_info"></span>
-  </div>
-
-When you use this macro you can choose to fill the slot like so::
-
-  <p metal:use-macro="container/master.html/macros/sidebar">
-    <b metal:fill-slot="additional_info">
-      Make sure to check out our <a href="/specials">specials</a>.
-    </b>
-  </p>
-
-When you render this template the side bar will include the extra
-information that you provided in the slot::
-
-  <div>
-    Links
-    <ul>
-      <li><a href="/">Home</a></li>
-      <li><a href="/products">Products</a></li>
-      <li><a href="/support">Support</a></li>
-      <li><a href="/contact">Contact Us</a></li>
-    </ul>
-    <b>
-      Make sure to check out our <a href="/specials">specials</a>.
-    </b>
-  </div>
-
-Notice how the 'span' element that defines the slot is replaced with the
-'b' element that fills the slot.
-
-Customizing Default Presentation
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A common use of slot is to provide default presentation which you can
-customize.  In the slot example in the last section, the slot definition
-was just an empty 'span' element.  However, you can provide default
-presentation in a slot definition.  For example, consider this revised
-sidebar macro::
-
-  <div metal:define-macro="sidebar">
-    <div metal:define-slot="links">
-    Links
-    <ul>
-      <li><a href="/">Home</a></li>
-      <li><a href="/products">Products</a></li>
-      <li><a href="/support">Support</a></li>
-      <li><a href="/contact">Contact Us</a></li>
-    </ul>
-    </div>
-    <span metal:define-slot="additional_info"></span>
-  </div>
-
-Now the sidebar is fully customizable.  You can fill the 'links' slot to
-redefine the sidebar links.  However, if you choose not to fill the
-'links' slot then you'll get the default links, which appear inside the
-slot.
-
-You can even take this technique further by defining slots inside of
-slots.  This allows you to override default presentation with a fine
-degree of precision.  Here's a sidebar macro that defines slots within
-slots::
-
-  <div metal:define-macro="sidebar">
-    <div metal:define-slot="links">
-    Links
-    <ul>
-      <li><a href="/">Home</a></li>
-      <li><a href="/products">Products</a></li>
-      <li><a href="/support">Support</a></li>
-      <li><a href="/contact">Contact Us</a></li>
-      <span metal:define-slot="additional_links"></span>
-    </ul>
-    </div>
-    <span metal:define-slot="additional_info"></span>
-  </div>
-
-If you wish to customize the sidebar links you can either fill the
-'links' slot to completely override the links, or you can fill the
-'additional_links' slot to insert some extra links after the default
-links.  You can nest slots as deeply as you wish.
-
-Combining METAL and TAL
-~~~~~~~~~~~~~~~~~~~~~~~
-
-You can use both *METAL* and *TAL* statements on the same elements.  For
-example::
-
-  <ul metal:define-macro="links"
-      tal:repeat="link context/getLinks">
-    <li>
-      <a href="link url"
-         tal:attributes="href link/url"
-         tal:content="link/name">link name</a>
-    </li>
-  </ul>
-
-In this case, 'getLinks' is an (imaginary) Script that assembles a list
-of link objects, possibly using a Catalog query.
-
-Since METAL statements are evaluated before *TAL* statements, there are
-no conflicts.  This example is also interesting since it customizes a
-macro without using slots.  The macro calls the 'getLinks' Script to
-determine the links.  You can thus customize your site's links by
-redefining the 'getLinks' Script at different locations within your
-site.
-
-It's not always easy to figure out the best way to customize look and
-feel in different parts of your site.  In general you should use slots
-to override presentation elements, and you should use Scripts to provide
-content dynamically.  In the case of the links example, it's arguable
-whether links are content or presentation.  Scripts probably provide a
-more flexible solution, especially if your site includes link content
-objects.
-
-Whole Page Macros
-~~~~~~~~~~~~~~~~~
-
-Rather than using macros for chunks of presentation shared between
-pages, you can use macros to define entire pages.  Slots make this
-possible.  Here's an example macro that defines an entire page::
-
-  <html metal:define-macro="page">
-    <head>
-      <title tal:content="context/title">The title</title>
-    </head>
-
-    <body>
-      <h1 metal:define-slot="headline"
-          tal:content="context/title">title</h1>
-
-      <p metal:define-slot="body">
-        This is the body.
-      </p>
-
-      <span metal:define-slot="footer">
-        <p>Copyright 2009 Fluffy Enterprises</p>
-      </span>
-
-    </body>
-  </html>
-
-This macro defines a page with three slots, 'headline', 'body', and
-'footer'.  Notice how the 'headline' slot includes a *TAL* statement to
-dynamically determine the headline content.
-
-You can then use this macro in templates for different types of content,
-or different parts of your site.  For example here's how a template for
-news items might use this macro::
-
-  <html metal:use-macro="container/master.html/macros/page">
-
-    <h1 metal:fill-slot="headline">
-      Press Release:
-      <span tal:replace="context/getHeadline">Headline</span>
-    </h1>
-
-    <p metal:fill-slot="body"
-       tal:content="context/getBody">
-      News item body goes here
-    </p>
-
-  </html>
-
-This template redefines the 'headline' slot to include the words "Press
-Release" and call the 'getHeadline' method on the current object.  It
-also redefines the 'body' slot to call the 'getBody' method on the
-current object.
-
-The powerful thing about this approach is that you can now change the
-'page' macro and the press release template will be automatically
-updated.  For example you could put the body of the page in a table and
-add a sidebar on the left and the press release template would
-automatically use these new presentation elements.
-
-Using Templates with Content
-----------------------------
-
-In general Zope supports content, presentation and logic components.
-*Page Templates* are presentation components and they can be used to
-display content components.
-
-Zope ships with several content components: ZSQL Methods, Files, and Images.
-You can use Files for textual content since you can edit the contents of Files
-if the file is less than 64K and contains text. However, the File object is
-fairly basic and may not provide all of the features or metadata that you need.
-
-Zope's `Content Management Framework <http://cmf.zope.org>`_ (CMF) solves
-this problem by providing an assortment of rich content components.  The
-CMF is Zope's content management add on.  It introduces all kinds of
-enhancements including workflow, skins and content objects.  The CMF makes
-a lot of use of *Page Templates*.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/ZopeArchitecture.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/ZopeArchitecture.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/ZopeArchitecture.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,301 +0,0 @@
-##############################
-Zope Concepts and Architecture
-##############################
-
-Fundamental Zope Concepts
-=========================
-
-The Zope framework has several fundamental underlying concepts,
-each of which should be understood in order to make the most of your Zope
-experience.
-
-Zope Is a Framework
--------------------
-
-Zope relieves the developer of most of the onerous details of
-Web application development, such as data persistence, data
-integrity, and access control, allowing one to focus instead on the
-problem at hand.  It allows you to utilize the services it
-provides to build web applications more quickly than other
-languages or frameworks, and to write web
-application logic in the `Python <http://www.python.org/>`_
-language.  Zope also comes with one solution that allow you 
-to "template" text, XML, and HTML: *Zope Page Templates* (ZPT).
-
-Object Orientation
-------------------
-
-Unlike common, file-based web template systems, such as ASP or
-PHP, Zope is a highly "object-oriented" web development
-platform.  Object orientation is a concept that is shared
-between many different programming languages, including 
-Python.  The concept of
-object orientation may take a little "getting-used-to" if you're
-an old hand at procedural languages used for
-web scripting, such as Perl or PHP.  However, you will easily grasp its 
-main concepts by reading the `Object Orientation <ObjectOrientation.html>`_
-chapter, and by trying the hands-on examples in this book.
-
-Object Publishing
-------------------
-
-The technology that would become Zope was founded on the
-realization that the Web is fundamentally object-oriented. A URL
-to a Web resource is really just a path to an object in a set of
-containers, and the HTTP protocol provides a way to send
-messages to that object and to request a response.
-
-Zope's object structure is hierarchical, which means that a
-typical Zope site is composed of objects that contain other
-objects (which may contain other objects, ad infinitum).  URLs
-map naturally to objects in the hierarchical Zope environment
-based on their names. For example, the URL
-"/Marketing/index.html" could be used to access the Document
-object named "index.html" located in the Folder object named
-"Marketing".
-
-Zope's seminal duty is to *publish* the objects you create.  The
-way it does this is conceptually straightforward:
-
-1. Your web browser sends a request to the Zope server.  The
-   request specifies a URL in the form
-   'protocol://host:port/path?querystring"',
-   e.g., 'http://www.zope.org:8080/Resources?batch_start=100'.
-
-2. Zope separates the URL into its component "host", "port" "path"
-   and "query string" portions ('http://www.zope.org', '8080',
-   '/Resources' and '?batch_start=100', respectively).
-
-3. Zope locates the object in its object database corresponding
-   to the "path" ('/Resources').
-
-4. Zope "executes" the object using the "query string" as a source
-   of parameters that can modify the behavior of the object.  This
-   means that the object may behave differently depending on the
-   values passed in the query string.
-
-5. If the act of executing the object returns a value, the value
-   is sent back to your browser.  Typically a given Zope object
-   returns HTML, file data, or image data.
-
-6. The data is interpreted by the browser and shown to you.
-
-Mapping URLs to objects isn't a new idea.  Web servers like Apache
-and Microsoft's IIS do the same thing: they translate URLs into
-files and directories on a file system.  Zope similarly maps URLs
-to objects in its object database.
-
-A Zope object's URL is based on its *path*, which is composed of the
-'ids' of its containing Folders and the object's 'id', separated
-by slash characters.  For example, if you have a Zope "Folder"
-object in the root folder called *Bob*, then its path would be
-'/Bob'.  If *Bob* is in a sub-folder called *Uncles*, then its URL
-would be '/Uncles/Bob'.
-
-There could also be other Folders in the Uncles folder called
-*Rick*, *Danny*, and *Louis*.  You would access them through the web
-similarly::
-
-  /Uncles/Rick
-  /Uncles/Danny 
-  /Uncles/Louis
-
-The URL of an object is most simply composed of its 'host',
-'port', and 'path'.  For the Zope object with the path '/Bob'
-on the Zope server at ``http://localhost:8080/``, the URL would be
-``http://localhost:8080/Bob``.  Visting a URL of a Zope object
-directly is termed *calling the object through the web*.  This
-causes the object to be evaluated and the result of the
-evaluation to be returned to your web browser.
-
-For a more detailed explanation of how Zope performs object
-publishing, see the `Object Publishing chapter
-<http://www.zope.org/Documentation/Books/ZDG/current/ObjectPublishing.stx>`_
-of the *Zope Developer's Guide*.
-
-Through-The-Web Management
---------------------------
-
-To create and work with Zope objects, you can use your Web browser to access
-the *Zope management interface* (ZMI). Basic management and application
-configuration tasks can be done completely through the Web using only a
-browser. The ZMI provides a familiar, Windows Explorer-like view of the Zope
-object system.
-
-Any object in the object hierarchy can be configured. Site managers can work
-with their objects by clicking on tabs that represent different "views" of an
-object. These views vary depending on the type of object. For example a
-"Database Connection" Zope object provides views that let you modify its
-connection string or caching parameters. All objects also have a "Security"
-view that allows you to manage their individual access control settings.
-
-Zope had a much larger focus on Through-The-Web activities in its beginning.
-In recent years the Through-The-Web model has been discouraged for any kind of
-development and reduced to configuration tasks.
-
-Security and Safe Delegation
-----------------------------
-
-One of the things that sets Zope apart from other application
-servers, is that it was designed from the start to be tightly
-coupled with not only the Web object model, but also the Web
-development model. Today's successful web applications require
-the participation of many people across an organization with
-different areas of expertise. Zope is specifically designed to
-accommodate this model, allowing site managers to safely
-delegate control to design experts, database experts, and content
-managers.
-
-A successful Web site requires the collaboration of many people
-people in an organization: application developers, SQL experts,
-content managers, and often even the end users of the
-application. On a conventional Web site, maintenance and
-security can quickly become problematic: how much control do you
-give to the content manager? How does giving the content manager
-a user account affect your security? What about that SQL code embedded
-in the ASP files he'll be working on -- code that probably
-exposes your database login?
-
-Objects in Zope provide a robust set of possible
-permissions, richer than that of a conventional file-based system. Permissions
-vary by object type, based on the capabilities of that
-object, which enables the implementation of fine-grained access
-control. For example, you can set access control so that content
-managers can use "SQL Method" objects without being able to change them or
-even view their source. You can also set restrictions so that a
-user can only create certain kinds of objects, for instance,
-"Folders" and "Page Templates," but not "SQL Methods" or other
-objects.
-
-Zope provides the capability to manage users through the web via
-*User Folders*, which are special folders that contain user
-information. Several Zope add-ons are available that provide
-extended types of User Folders that get their user data from
-external sources, such as relational databases or LDAP
-directories.  The ability to add new User Folders can be
-delegated to users within a sub-folder, essentially allowing you
-to delegate the creation and user management of subsections of
-your website to semi-trusted users, without having to worry about those
-users changing the objects "above" their own folder.
-
-Native Object Persistence and Transactions
-------------------------------------------
-
-By default, Zope objects are stored in a high-performance, transactional
-object database known as the *Zope Object Database* (ZODB). Each
-web request is treated as a separate transaction by the ZODB. 
-If an error occurs in your application during a
-request, any changes made during the request will be
-automatically rolled back. The ZODB also provides
-multi-level undo, allowing a site manager to "undo" changes to
-the site with the click of a button.  The Zope framework makes
-all of the details of persistence and transactions totally
-transparent to the application developer.  Relational databases,
-when used with Zope, can also play in Zope's transactional
-framework.
-
-Acquisition
------------
-
-One more prominent aspect of Zope is *acquisition*, whose core concepts are
-simply that:
-
-* Zope objects are contained inside other objects (such as Folders).
-
-* Objects can "acquire" attributes and behavior from their containers.
-
-The concept of acquisition works with all Zope objects and
-provides an extremely powerful way to centralize common
-resources. A commonly-used SQL query or snippet of HTML, for
-example, can be defined in one Folder, and objects in sub-folders
-can use it through acquisition. If the query needs
-to be changed, you can change it in one place without worrying
-about all of the sub-objects that use the same query.
-
-If you are familiar with *Cascading Style Sheets* (CSS), you already
-know how an element in an HTML document can inherit cascading properties
-from its parent or ancestor elements. Containment acquisition
-works in the same fashion: if a document X is contained in folder Y,
-document X can access the attributes of folder Y through acquisition.
-Note that some advanced aspects of acquisition may break
-this analogy; these are discussed in the 
-`Advanced Zope Scripting <ScriptingZope.html>`_ chapter.
-
-Acquisition is explained in further detail in the chapter on
-`Acquisition <Acquisition.html>`_ .
-
-Zope Is Extensible
-------------------
-
-Zope is highly extensible, and component developers can create new
-types of Zope objects by writing new Zope add-on in Python. The Zope
-software provides a number of useful, built-in components to aid
-extension authors in development, including a robust set of framework classes
-that take care of most of the details of implementing new Zope
-objects.
-
-A number of Zope add-ons are available that provide
-features like drop-in web discussion topics, desktop data
-publishing, XML tools, and e-commerce integration. Many of these
-add-ons have been written by highly active members of the
-Zope community, and most are also open source.
-
-Fundamental Zope Components
-===========================
-
-Zope consists of several different components that work together
-to help you build web applications.  Zope's fundamental components
-are shown in the following figure and explained below:
-
-.. image:: ../Figures/zopearchitecture.png
-
-ZServer
--------
-
-Zope comes with a built-in web server that serves content to you and your
-users.  This web server also serves Zope content via FTP, WebDAV, and
-XML-RPC (a remote procedure call facility).
-
-Web Server
-----------
-
-Of course, you may already have an existing web server, such as Apache or
-Microsoft IIS, and you may not want to use Zope's web server.  Zope works
-with these servers also, and any other web server that supports the
-Common Gateway Interface (CGI).  In production environments, it can be
-advantageous to run a server like Apache or Squid "in front of" Zope in
-order to help sanitize incoming requests, augment its capabilities (e.g.,
-terminate HTTPS connections), and cache Zope-provided content.
-
-Zope Core
----------
-
-This is the engine that coordinates Zope activity, driving its management
-interface and object database.
-
-Object Database
----------------
-
-When you work with Zope, you are usually working with objects that are
-stored in the ZODB.
-
-Relational database
--------------------
-
-You don't have to store your information in Zope's object database if you
-don't want to.  Zope also works with other relational databases,
-including *Oracle*, *PostgreSQL*, *Sybase*, and *MySQL*.
-
-File System
------------
-
-Zope can, of course, work with documents and other files stored on your
-server's file system.
-
-Products
---------
-
-Zope also allows site managers to add new, pre-built object types to Zope
-by installing add-ons on the Zope server file system. These are referred to
-as Products or Add-ons. Technically they are normal Python packages.
-

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/ZopeServices.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/ZopeServices.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/ZopeServices.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,380 +0,0 @@
-Zope Services
-=============
-
-Some Zope objects are *service* objects.  *Service* objects provide
-various kinds of support to your "domain-specific" content, logic,
-and presentation objects.  They help solve fundamental problems that
-many others have experienced when writing applications in Zope.
-
-Access Rule Services
---------------------
-
-*Access Rules* make it possible to cause an action to happen any
-time a user "traverses" a Folder in your Zope site.  When a user's
-browser submits a request for a URL to Zope which has a Folder's
-name in it, the Folder is "looked up" by Zope during object
-publishing.  That action (the lookup) is called *traversal*.
-Access Rules are arbitrary bits of code which effect the
-environment in some way during Folder traversal.  They are easiest
-to explain by way of an example.
-
-.. note:::
-
-   The Access Service section needs an explanation of how to suppress
-   an access rule. For the baffled among us, you can set an environmental
-   variable 'SUPPRESS_ACCESSRULE' ( I add a line in my 'start' script to
-   do this ) or include '_SUPPRESS_ACCESSRULE' to the URL at a point AFTER
-   the folder/container in question.
-   SITEROOT works the same way, just replace ACCESSRULE with SITEROOT in
-   the above explanation.
-
-In your Zope site, create a Folder named "accessrule_test".
-Inside the accessrule_test folder, create a Script (Python) object
-named 'access_rule' with two parameters: 'container' and
-'request'.  Give the 'access_rule' Script (Python) the following
-body::
-
-  useragent = request.get('HTTP_USER_AGENT', '')
-  if useragent.find('Windows') != -1:
-      request.set('OS', 'Windows')
-  elif useragent.find('Linux') != -1:
-      request.set('OS', 'Linux')
-  else:
-      request.set('OS', 'Non-Windows, Non-Linux')
-
-This Script causes the traversal of the accessrule_test folder to
-cause a new variable named 'OS' to be entered into the REQUEST,
-which has a value of 'Windows', 'Linux', or 'Non-Windows,
-Non-Linux' depending on the user's browser.
-
-Save the 'access_rule' script and revisit the accessrule_test
-folder's *Contents* view.  Choose *Set Access Rule* from the add
-list.  In the 'Rule Id' form field, type 'access_rule'.  Then
-click *Set Rule*.  A confirmation screen appears claiming that
-"'access_rule' is now the Access Rule for this object".  Click
-"OK".  Notice that the icon for the 'access_rule' Script (Python)
-has changed, denoting that it is now the access rule for this
-Folder.
-
-Create a page template named 'test' in the accessrule_test folder
-with the following text::
-
-  <html>
-  <body>
-    <pre tal:content="context/REQUEST">request details</pre>
-  </body>
-  </html>
-
-Save the 'test' page template and click its "View" tab.  You will
-see a representation of all the variables that exist in the
-REQUEST.  Note that in the **other** category, there is now a
-variable named "OS" with (depending on your browser platform)
-either 'Windows', 'Linux' or 'Non-Linux, Non-Windows').
-
-Revisit the accessrule_test folder and again select *Set Access
-Rule* from the add list.  Click the *No Access Rule* button.  A
-confirmation screen will be displayed stating that the object now
-has no Access Rule.
-
-Visit the 'test' script you created previously and click its
-*View* tab.  You will notice that there is now no "OS" variable
-listed in the request because we've turned off the Access Rule
-capability for 'access_rule'.
-
-Temporary Storage Services
---------------------------
-
-Temporary Folders are Zope folders that are used for storing
-objects temporarily.  Temporary Folders acts almost exactly like a
-regular Folder with two significant differences:
-
-1. Everything contained in a Temporary Folder disappears when you
-   restart Zope.  (A Temporary Folder's contents are stored in
-   RAM).
-
-2. You cannot undo actions taken to objects stored a Temporary
-   Folder.
-
-By default there is a Temporary Folder in your root folder named
-*temp_folder*.  You may notice that there is an object entitled,
-"Session Data Container" within *temp_folder*. This is an object
-used by Zope's default sessioning system configuration.  See the
-"Using Sessions" section later in this chapter for more
-information about sessions.
-
-Temporary folders store their contents in RAM rather than in the
-Zope database. This makes them appropriate for storing small
-objects that receive lots of writes, such as session data.
-However, it's a bad idea use temporary folders to store large
-objects because your computer can potentially run out of RAM as
-a result.
-
-Caching Services
-----------------
-
-A *cache* is a temporary place to store information that you
-access frequently.  The reason for using a cache is speed.  Any
-kind of dynamic content, like a a Script (Python),
-must be evaluated each time it is called.  For simple pages or
-quick scripts, this is usually not a problem.  For very complex
-scripts that do a lot of computation or call remote
-servers, accessing that page or script could take more than a
-trivial amount of time.  Scripts can get this
-complex, especially if you use lots of looping (such as the
-Python 'for' loop) or if you call lots of scripts, that
-in turn call lots of scripts, and so on.  Computations that take a
-lot of time are said to be *expensive*.
-
-A cache can add a lot of speed to your site by calling an
-expensive page or script once and storing the result of that call
-so that it can be reused.  The very first person to call that page
-will get the usual "slow" response time, but then once the value
-of the computation is stored in the cache, all subsequent users to
-call that page will see a very quick response time because they
-are getting the *cached copy* of the result and not actually going
-through the same expensive computation the first user went
-through.
-
-To give you an idea of how caches can improve your site speed,
-imagine that you are creating *www.zopezoo.org*, and that the very
-first page of your site is very complex.  Let's suppose this page
-has complex headers, footers, queries several different database
-tables, and calls several special scripts that parse the results
-of the database queries in complex ways.  Every time a user comes
-to *www.zopezoo.org*, Zope must render this very complex page.
-For the purposes of demonstration, let's suppose this complex page
-takes one-half of a second, or 500 milliseconds, to compute.
-
-Given that it takes a half of a second to render this fictional
-complex main page, your machine can only really serve 120 hits per
-minute.  In reality, this number would probably be even lower than
-that, because Zope has to do other things in addition to just
-serving up this main page.  Now, imagine that you set this page up
-to be cached.  Since none of the expensive computation needs to be
-done to show the cached copy of the page, many more users could
-see the main page.  If it takes, for example, 10 milliseconds to
-show a cached page, then this page is being served *50 times
-faster* to your website visitors.  The actual performance of the
-cache and Zope depends a lot on your computer and your
-application, but this example gives you an idea of how caching can
-speed up your website quite a bit.  There are some disadvantages
-to caching however:
-
-Cache lifetime
-  If pages are cached for a long time, they may
-  not reflect the most current information on your site.  If you
-  have information that changes very quickly, caching may hide the
-  new information from your users because the cached copy contains
-  the old information.  How long a result remains cached is called
-  the *cache lifetime* of the information.
-
-Personal information
-  Many web pages may be personalized for
-  one particular user.  Obviously, caching this information and
-  showing it to another user would be bad due to privacy concerns,
-  and because the other user would not be getting information
-  about *them*, they'd be getting it about someone else.  For this
-  reason, caching is often never used for personalized
-  information.
-
-Zope allows you to get around these problems by setting up a *cache
-policy*.  The cache policy allows you to control how content gets
-cached.  Cache policies are controlled by *Cache Manager* objects.
-
-Adding a Cache Manager
-~~~~~~~~~~~~~~~~~~~~~~
-
-Cache managers can be added just like any other Zope object.
-Currently Zope comes with two kinds of cache managers:
-
-HTTP Accelerated Cache Manager
-  An HTTP Accelerated Cache Manager allows you to control an HTTP cache
-  server that is external to Zope, for example,
-  `Squid <http://www.squid-cache.org/>`_.  HTTP Accelerated Cache Managers
-  do not do the caching themselves, but rather set special HTTP headers
-  that tell an external cache server what to cache.  Setting up an external
-  caching server like Squid is beyond the scope of this book, see the Squid
-  site for more details.
-
-(RAM) Cache Manager
-  A RAM Cache Manager is a Zope cache manager that caches the content of
-  objects in your computer memory.  This makes it very fast, but also
-  causes Zope to consume more of your computer's memory.  A RAM Cache
-  Manager does not require any external resources like a Squid server, to
-  work.
-
-For the purposes of this example, create a RAM Cache Manager in
-the root folder called *CacheManager*.  This is going to be the
-cache manager object for your whole site.
-
-Now, you can click on *CacheManager* and see its configuration
-screen.  There are a number of elements on this screen:
-
-Title
-  The title of the cache manager.  This is optional.
-
-REQUEST variables
-  This information is used to store the
-  cached copy of a page.  This is an advanced feature, for now,
-  you can leave this set to just "AUTHENTICATED_USER".
-
-Threshold Entries
-  The number of objects the cache manager
-  will cache at one time.
-
-Cleanup Interval
-  The lifetime of cached results.
-
-For now, leave all of these entries as is, they are good,
-reasonable defaults.  That's all there is to setting up a cache
-manager!
-
-There are a couple more views on a cache manager that you may find
-useful.  The first is the *Statistics* view.  This view shows you
-the number of cache "hits" and "misses" to tell you how effective
-your caching is.
-
-There is also an *Associate* view that allows you to associate a
-specific type or types of Zope objects with a particular cache
-manager.  For example, you may only want your cache manager to
-cache Scripts.  You can change these settings on the
-*Associate* view.
-
-At this point, nothing is cached yet, you have just created a
-cache manager.  The next section explains how you can cache the
-contents of actual documents.
-
-Caching an Object
-~~~~~~~~~~~~~~~~~
-
-Caching any sort of cacheable object is fairly straightforward.
-First, before you can cache an object you must have a cache
-manager like the one you created in the previous section.
-
-To cache a page, create a new page template object in the
-root folder called *Weather*.  This object will contain some
-weather information.  For example, let's say it contains::
-
-  <html>
-  <body>
-
-    <p>Yesterday it rained.</p>
-
-  </body>
-  </html>
-
-Now, click on the *Weather* page template and click on its *Cache*
-view.  This view lets you associate this page with a cache
-manager.  If you pull down the select box at the top of the view,
-you'll see the cache manager you created in the previous section,
-*CacheManager*.  Select this as the cache manager for *Weather*.
-
-Now, whenever anyone visits the *Weather* page, they will get
-the cached copy instead.  For a page as trivial as our
-*Weather* example, this is not much of a benefit.  But imagine for
-a moment that *Weather* contained some database queries.  For
-example::
-
-  <html>
-  <body>
-
-    <p>
-      Yesterday's weather was
-      <tal:yesterday tal:replace="context/yesterdayQuery" />
-    </p>
-
-    <p>
-      The current temperature is
-      <tal:current tal:replace="context/currentTempQuery" />
-    </p>
-
-  </body>
-  </html>
-
-
-Let's suppose that *yesterdayQuery* and *currentTempQuery* are
-SQL Methods that query a database for yesterdays forecast and
-the current temperature, respectively (for more information on
-SQL Methods, see the chapter entitled `Relational Database
-Connectivity <RelationalDatabases.html>`_.)  Let's also suppose that
-the information in the database only changes once every hour.
-
-Now, without caching, the *Weather* document would query the
-database every time it was viewed.  If the *Weather* document was
-viewed hundreds of times in an hour, then all of those hundreds of
-queries would always contain the same information.
-
-If you specify that the page should be cached, however, then
-the page will only make the query when the cache expires.  The
-default cache time is 300 seconds (5 minutes), so setting this
-page up to be cached will save you 91% of your database
-queries by doing them only one twelfth as often.  There is a
-trade-off with this method, there is a chance that the data may be
-five minutes out of date, but this is usually an acceptable
-compromise.
-
-Outbound Mail Services
-----------------------
-
-Zope comes with an object that is used to send outbound e-mail,
-usually in conjunction with a Script (Python).
-
-Mailhosts can be used Python to send an email
-message over the Internet.  They are useful as 'gateways' out to
-the world.  Each mailhost object is associated with one mail
-server, for example, you can associate a mailhost object with
-'yourmail.yourdomain.com', which would be your outbound SMTP mail
-server.  Once you associate a server with a mailhost object, the
-mailhost object will always use that server to send mail.
-
-To create a mailhost object select *MailHost* from the add list.
-You can see that the default id is "MailHost" and the default SMTP
-server and port are "localhost" and "25".  make sure that either
-your localhost machine is running a mail server, or change
-"localhost" to be the name of your outgoing SMTP server.
-
-Now you can use the new MailHost object from a Script.
-
-Error Logging Services
-----------------------
-
-The *Site Error Log* object, typically accessible in the Zope root
-under the name 'error_log', provides debugging and error logging
-information in real-time.  When your site encounters an error, it
-will be logged in the Site Error Log, allowing you to review (and
-hopefully fix!) the error.
-
-Options settable on a Site Error Log instance
-include:
-
-Number of exceptions to keep
-  keep 20 exceptions by default, rotating "old" exceptions out when more
-  than 20 are stored.  Set this to a higher or lower number as you like.
-
-Copy exceptions to the event log
-  If this option is selected, the site error log object will copy the text
-  of exceptions that it receives to the "event log" facility, which is
-  typically controlled by the 'EVENT_LOG_FILE' environment variable.  For
-  more information about this environment variable, see the chapter
-  entitled `Installing and Starting Zope <InstallingZope.html>`_.
-
-Virtual Hosting Services
-------------------------
-
-For detailed information about using virtual hosting services in
-Zope, see the chapter entitled `Virtual Hosting Services
-<VirtualHosting.html>`_.
-
-Searching and Indexing Services
--------------------------------
-
-For detailed information about using searching and indexing services in Zope to
-index and search a collection of documents, see the chapter entitled
-`Searching and Categorizing Content <SearchingZCatalog.html>`_.
-
-Sessioning Services
--------------------
-
-For detailed information about using Zope's "sessioning" services
-to "keep state" between HTTP requests for anonymous users, see the
-chapter entitled `Sessions <Sessions.html>`_.

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/conf.py
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/conf.py	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/conf.py	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,190 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Zope2 Book documentation build configuration file, created by
-# sphinx-quickstart on Tue Feb 10 00:26:02 2009.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# The contents of this file are pickled, so don't put values in the namespace
-# that aren't pickleable (module imports are okay, they're removed automatically).
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import sys, os
-
-# If your extensions are in another directory, add it here. If the directory
-# is relative to the documentation root, use os.path.abspath to make it
-# absolute, like shown here.
-#sys.path.append(os.path.abspath('.'))
-
-# General configuration
-# ---------------------
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = []
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-#source_encoding = 'utf-8'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'Zope2 Book'
-copyright = u'2009, Zope Community'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = '2.12'
-# The full version, including alpha/beta/rc tags.
-release = '2.12dev'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
-# List of documents that shouldn't be included in the build.
-#unused_docs = []
-
-# List of directories, relative to source directory, that shouldn't be searched
-# for source files.
-exclude_trees = []
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-
-# Options for HTML output
-# -----------------------
-
-# The style sheet to use for HTML and HTML Help pages. A file of that name
-# must exist either in Sphinx' static/ path, or in one of the custom paths
-# given in html_static_path.
-html_style = 'default.css'
-
-# The name for this set of Sphinx documents.  If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar.  Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_use_modindex = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, the reST sources are included in the HTML build as _sources/<name>.
-#html_copy_source = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it.  The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = ''
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'Zope2Bookdoc'
-
-
-# Options for LaTeX output
-# ------------------------
-
-# The paper size ('letter' or 'a4').
-#latex_paper_size = 'letter'
-
-# The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, document class [howto/manual]).
-latex_documents = [
-  ('index', 'Zope2Book.tex', ur'Zope2 Book Documentation',
-   ur'Zope Community', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# Additional stuff for the LaTeX preamble.
-#latex_preamble = ''
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_use_modindex = True

Deleted: zope2docs/branches/baijum-reorganize/zope2book/source/index.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zope2book/source/index.rst	2009-10-10 05:25:27 UTC (rev 104981)
+++ zope2docs/branches/baijum-reorganize/zope2book/source/index.rst	2009-10-10 05:47:18 UTC (rev 104982)
@@ -1,44 +0,0 @@
-The Zope2 Book
-==============
-
-Welcome to *The Zope Book*.  This book is designed to introduce you
-to `Zope2`, an open-source web application server.
-
-
-Contents
---------
-
-.. toctree::
-   :maxdepth: 2
-
-   Preface.rst
-   IntroducingZope.rst
-   ZopeArchitecture.rst
-   InstallingZope.rst
-   ObjectOrientation.rst
-   UsingZope.rst
-   BasicObject.rst
-   Acquisition.rst
-   BasicScripting.rst
-   ZPT.rst
-   SimpleExamples.rst
-   Security.rst
-   AdvZPT.rst
-   ScriptingZope.rst
-   ZopeServices.rst
-   DTML.rst
-   AdvDTML.rst
-   SearchingZCatalog.rst
-   RelationalDatabases.rst
-   VirtualHosting.rst
-   Sessions.rst
-   ZEO.rst
-   ExternalTools.rst
-   MaintainingZope.rst
-   AppendixA.rst
-   AppendixB.rst
-   AppendixC.rst
-   AppendixD.rst
-   AppendixE.rst
-   Contributions.rst
-



More information about the checkins mailing list