[Checkins] SVN: zope2docs/trunk/ merge re-organize branch

Baiju M baiju.m.mail at gmail.com
Sat Oct 10 02:20:10 EDT 2009


Log message for revision 104988:
  merge re-organize branch
  

Changed:
  _U  zope2docs/trunk/
  U   zope2docs/trunk/Makefile
  U   zope2docs/trunk/buildout.cfg
  U   zope2docs/trunk/index.rst
  A   zope2docs/trunk/zdgbook/Acquisition.rst
  A   zope2docs/trunk/zdgbook/AppendixA.rst
  A   zope2docs/trunk/zdgbook/ComponentsAndInterfaces.rst
  A   zope2docs/trunk/zdgbook/Credits.txt
  A   zope2docs/trunk/zdgbook/GettingStarted.rst
  D   zope2docs/trunk/zdgbook/Gotchas.stx
  A   zope2docs/trunk/zdgbook/Gotchas.txt
  A   zope2docs/trunk/zdgbook/Introduction.rst
  D   zope2docs/trunk/zdgbook/Makefile
  A   zope2docs/trunk/zdgbook/ObjectPublishing.rst
  A   zope2docs/trunk/zdgbook/Outline.txt
  A   zope2docs/trunk/zdgbook/Products.rst
  A   zope2docs/trunk/zdgbook/Security.rst
  A   zope2docs/trunk/zdgbook/TestingAndDebugging.rst
  A   zope2docs/trunk/zdgbook/ZODBPersistentComponents.rst
  D   zope2docs/trunk/zdgbook/bootstrap.py
  D   zope2docs/trunk/zdgbook/build/
  D   zope2docs/trunk/zdgbook/buildout.cfg
  A   zope2docs/trunk/zdgbook/index.rst
  D   zope2docs/trunk/zdgbook/source/Acquisition.rst
  D   zope2docs/trunk/zdgbook/source/AppendixA.rst
  D   zope2docs/trunk/zdgbook/source/ComponentsAndInterfaces.rst
  D   zope2docs/trunk/zdgbook/source/Credits.rst
  D   zope2docs/trunk/zdgbook/source/GettingStarted.rst
  D   zope2docs/trunk/zdgbook/source/Introduction.rst
  D   zope2docs/trunk/zdgbook/source/ObjectPublishing.rst
  D   zope2docs/trunk/zdgbook/source/Outline.rst
  D   zope2docs/trunk/zdgbook/source/Products.rst
  D   zope2docs/trunk/zdgbook/source/Security.rst
  D   zope2docs/trunk/zdgbook/source/TestingAndDebugging.rst
  D   zope2docs/trunk/zdgbook/source/ZODBPersistentComponents.rst
  D   zope2docs/trunk/zdgbook/source/conf.py
  D   zope2docs/trunk/zdgbook/source/index.rst
  A   zope2docs/trunk/zope2book/Acquisition.rst
  A   zope2docs/trunk/zope2book/AdvDTML.rst
  A   zope2docs/trunk/zope2book/AdvZPT.rst
  A   zope2docs/trunk/zope2book/AppendixA.rst
  A   zope2docs/trunk/zope2book/AppendixB.rst
  A   zope2docs/trunk/zope2book/AppendixC.rst
  A   zope2docs/trunk/zope2book/AppendixD.rst
  A   zope2docs/trunk/zope2book/AppendixE.rst
  A   zope2docs/trunk/zope2book/BasicObject.rst
  A   zope2docs/trunk/zope2book/BasicScripting.rst
  A   zope2docs/trunk/zope2book/Contributions.rst
  A   zope2docs/trunk/zope2book/DTML.rst
  A   zope2docs/trunk/zope2book/ExternalTools.rst
  A   zope2docs/trunk/zope2book/InstallingZope.rst
  A   zope2docs/trunk/zope2book/IntroducingZope.rst
  A   zope2docs/trunk/zope2book/MaintainingZope.rst
  D   zope2docs/trunk/zope2book/Makefile
  A   zope2docs/trunk/zope2book/ObjectOrientation.rst
  A   zope2docs/trunk/zope2book/Preface.rst
  A   zope2docs/trunk/zope2book/RelationalDatabases.rst
  A   zope2docs/trunk/zope2book/ScriptingZope.rst
  A   zope2docs/trunk/zope2book/SearchingZCatalog.rst
  A   zope2docs/trunk/zope2book/Security.rst
  A   zope2docs/trunk/zope2book/Sessions.rst
  A   zope2docs/trunk/zope2book/SimpleExamples.rst
  A   zope2docs/trunk/zope2book/UsingZope.rst
  A   zope2docs/trunk/zope2book/VirtualHosting.rst
  A   zope2docs/trunk/zope2book/ZEO.rst
  A   zope2docs/trunk/zope2book/ZPT.rst
  A   zope2docs/trunk/zope2book/ZopeArchitecture.rst
  A   zope2docs/trunk/zope2book/ZopeServices.rst
  D   zope2docs/trunk/zope2book/bootstrap.py
  D   zope2docs/trunk/zope2book/buildout.cfg
  A   zope2docs/trunk/zope2book/index.rst
  D   zope2docs/trunk/zope2book/source/

-=-

Property changes on: zope2docs/trunk
___________________________________________________________________
Deleted: svn:externals
   - 

Added: svn:ignore
   + develop-eggs
eggs
parts
.installed.cfg
build
bin


Modified: zope2docs/trunk/Makefile
===================================================================
--- zope2docs/trunk/Makefile	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/Makefile	2009-10-10 06:20:10 UTC (rev 104988)
@@ -3,7 +3,7 @@
 
 # You can set these variables from the command line.
 SPHINXOPTS    =
-SPHINXBUILD   = sphinx-build
+SPHINXBUILD   = ./bin/sphinx-build
 PAPER         =
 
 # Internal variables.

Modified: zope2docs/trunk/buildout.cfg
===================================================================
--- zope2docs/trunk/buildout.cfg	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/buildout.cfg	2009-10-10 06:20:10 UTC (rev 104988)
@@ -15,7 +15,8 @@
 [stxpy]
 recipe = zc.recipe.egg
 eggs =
-    Sphinx
+    Sphinx==0.6.3
+    docutils==0.5
 interpreter = stxpy
 scripts =
     sphinx-build

Modified: zope2docs/trunk/index.rst
===================================================================
--- zope2docs/trunk/index.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/index.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -5,8 +5,8 @@
 .. toctree::
    :maxdepth: 1
 
-   zope2book/source/index
-   zdgbook/source/index
+   zope2book/index
+   zdgbook/index
 
 Release information
 ===================

Copied: zope2docs/trunk/zdgbook/Acquisition.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/Acquisition.rst)
===================================================================
--- zope2docs/trunk/zdgbook/Acquisition.rst	                        (rev 0)
+++ zope2docs/trunk/zdgbook/Acquisition.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,457 @@
+###########
+Acquisition
+###########
+
+Acquisition is a mechanism that allows objects to obtain attributes
+from their environment.  It is similar to inheritance, except that,
+rather than searching an inheritance hierarchy to obtain attributes,
+a containment hierarchy is traversed.
+
+
+Introductory Example
+====================
+
+Zope implements acquisition with "Extension Class" mix-in classes. To
+use acquisition your classes must inherit from an acquisition base
+class. For example::
+
+  import ExtensionClass, Acquisition
+
+  class C(ExtensionClass.Base):
+    color = 'red'
+
+  class A(Acquisition.Implicit):
+
+    def report(self):
+      print self.color
+
+  a = A()
+  c = C()
+  c.a = A()
+
+  c.a.report() # prints 'red'
+
+  d = C()
+  d.color = 'green'
+  d.a = a
+
+  d.a.report() # prints 'green'
+
+  a.report() # raises an attribute error
+
+The class 'A' inherits acquisition behavior from
+'Acquisition.Implicit'.  The object, 'a', "has" the color of objects
+'c' and 'd' when it is accessed through them, but it has no color by
+itself.  The object 'a' obtains attributes from its environment,
+where its environment is defined by the access path used to reach
+'a'.
+
+Acquisition Wrappers
+====================
+
+When an object that supports acquisition is accessed through an
+extension class instance, a special object, called an acquisition
+wrapper, is returned.  In the example above, the expression 'c.a'
+returns an acquisition wrapper that contains references to both 'c'
+and 'a'.  It is this wrapper that performs attribute lookup in 'c'
+when an attribute cannot be found in 'a'.
+
+Acquisition wrappers provide access to the wrapped objects through
+the attributes 'aq_parent', 'aq_self', 'aq_base'.  In the example
+above, the expressions::
+
+  'c.a.aq_parent is c'
+
+and::
+
+  'c.a.aq_self is a'
+
+
+both evaluate to true, but the expression::
+
+  'c.a is a'
+
+evaluates to false, because the expression 'c.a' evaluates to an
+acquisition wrapper around 'c' and 'a', not 'a' itself.
+
+The attribute 'aq_base' is similar to 'aq_self'.  Wrappers may be
+nested and 'aq_self' may be a wrapped object.  The 'aq_base'
+attribute is the underlying object with all wrappers removed.
+
+You can manually wrap an instance of an object that inherits from an
+acquisition base class by using its '__of__' method. For example::
+
+  class A(Acquisition.Implicit):
+      pass
+
+  a = A()
+  a.color = 'red'
+  b = A()
+  a.b = b
+
+  print b.__of__(a).color # prints red
+
+
+The expression 'b.__of__(a)' wraps 'b' in an acquisition wrapper
+explicitly, and returns the acquisition wrapper.  The 'color'
+attrribute of 'a' is found via acquisition when this expression is
+executed.
+
+
+Explicit and Implicit Acquisition
+=================================
+
+Two styles of acquisition are supported: implicit and explicit
+acquisition.
+
+Implicit acquisition
+--------------------
+
+Implicit acquisition is so named because it searches for
+attributes from the environment automatically whenever an
+attribute cannot be obtained directly from an object or through
+inheritance.
+
+An attribute can be implicitly acquired if its name does not
+begin with an underscore.
+
+To support implicit acquisition, your class should inherit from
+the mix-in class 'Acquisition.Implicit'.
+
+Explicit Acquisition
+--------------------
+
+When explicit acquisition is used, attributes are not automatically
+obtained from the environment.  Instead, the method 'aq_acquire' must
+be used. For example::
+
+  print c.a.aq_acquire('color')
+
+To support explicit acquisition, your class should inherit from the
+mix-in class 'Acquisition.Explicit'.
+
+Controlling Acquisition
+=======================
+
+A class (or instance) can provide attribute by attribute control over
+acquisition.  Your should subclass from 'Acquisition.Explicit', and
+set all attributes that should be acquired to the special value
+'Acquisition.Acquired'.  Setting an attribute to this value also
+allows inherited attributes to be overridden with acquired ones.  For
+example::
+
+  class C(Acquisition.Explicit):
+     id=1
+     secret=2
+     color=Acquisition.Acquired
+     __roles__=Acquisition.Acquired
+
+The *only* attributes that are automatically acquired from containing
+objects are 'color', and '__roles__'.  Note that the '__roles__'
+attribute is acquired even though its name begins with an underscore.
+In fact, the special 'Acquisition.Acquired' value can be used in
+'Acquisition.Implicit' objects to implicitly acquire selected objects
+that smell like private objects.
+
+Sometimes, you want to dynamically make an implicitly acquiring
+object acquire explicitly. You can do this by getting the object's
+'aq_explicit' attribute. This attribute provides the object with an
+explicit wrapper that places the original implicit wrapper.
+
+Filtered Acquisition
+====================
+
+The acquisition method, 'aq_acquire', accepts two optional
+arguments. The first of the additional arguments is a "filtering"
+function that is used when considering whether to acquire an object.
+The second of the additional arguments is an object that is passed as
+extra data when calling the filtering function and which defaults to
+'None'.  The filter function is called with five arguments:
+
+- The object that the 'aq_acquire' method was called on,
+
+- The object where an object was found,
+
+- The name of the object, as passed to 'aq_acquire',
+
+- The object found, and
+
+- The extra data passed to 'aq_acquire'.
+
+If the filter returns a true object that the object found is
+returned, otherwise, the acquisition search continues.
+
+For example, in::
+
+  from Acquisition import Explicit
+
+  class HandyForTesting:
+      def __init__(self, name):
+          self.name = name
+      def __str__(self):
+          return "%s(%s)" % (self.name, self.__class__.__name__)
+      __repr__ = __str__
+
+  class E(Explicit, HandyForTesting): pass
+
+  class Nice(HandyForTesting):
+      isNice = 1
+      def __str__(self):
+          return HandyForTesting.__str__(self) + ' and I am nice!'
+      __repr__ = __str__
+
+  a = E('a')
+  a.b = E('b')
+  a.b.c = E('c')
+  a.p = Nice('spam')
+  a.b.p = E('p')
+
+  def find_nice(self, ancestor, name, object, extra):
+      return hasattr(object,'isNice') and object.isNice
+
+  print a.b.c.aq_acquire('p', find_nice)
+
+The filtered acquisition in the last line skips over the first
+attribute it finds with the name 'p', because the attribute doesn't
+satisfy the condition given in the filter. The output of the last
+line is::
+
+  spam(Nice) and I am nice!
+
+Filtered acquisition is rarely used in Zope.
+
+Acquiring from Context
+======================
+
+Normally acquisition allows objects to acquire data from their
+containers. However an object can acquire from objects that aren't
+its containers.
+
+Most of the example's we've seen so far show establishing of an
+acquisition *context* using 'getattr' symanitics. For example, 'a.b'
+is a reference to 'b' in the context of 'a'.
+
+
+You can also manuallyset acquisition context using the '__of__'
+method.  For example::
+
+  from Acquisition import Implicit
+  class C(Implicit): pass
+  a = C()
+  b = C()
+  a.color = "red"
+  print b.__of__(a).color # prints red
+
+In this case, 'a' does not contain 'b', but it is put in 'b''s
+context using the '__of__' method.
+
+Here's another subtler example that shows how you can construct an
+acquisition context that includes non-container objects::
+
+  from Acquisition import Implicit
+
+  class C(Implicit):
+      def __init__(self, name):
+          self.name = name
+
+  a = C("a")
+  a.b = C("b")
+  a.b.color = "red"
+  a.x = C("x")
+
+  print a.b.x.color # prints red
+
+Even though 'b' does not contain 'x', 'x' can acquire the 'color'
+attribute from 'b'. This works because in this case, 'x' is accessed
+in the context of 'b' even though it is not contained by 'b'.
+
+Here acquisition context is defined by the objects used to access
+another object.
+
+Containment Before Context
+==========================
+
+If in the example above suppose both 'a' and 'b' have an 'color'
+attribute::
+
+  a = C("a")
+  a.color = "green"
+  a.b = C("b")
+  a.b.color = "red"
+  a.x = C("x")
+
+  print a.b.x.color # prints green
+
+
+Why does 'a.b.x.color' acquire 'color' from 'a' and not from 'b'?
+The answer is that an object acquires from its containers before
+non-containers in its context.
+
+To see why consider this example in terms of expressions using the
+'__of__' method::
+
+   a.x -> x.__of__(a)
+
+   a.b -> b.__of__(a)
+
+   a.b.x -> x.__of__(a).__of__(b.__of__(a))
+
+Keep in mind that attribute lookup in a wrapper is done by trying to
+look up the attribute in the wrapped object first and then in the
+parent object.  So in the expressions above proceeds from left to
+right.
+
+
+The upshot of these rules is that attributes are looked up by
+containment before context.
+
+This rule holds true also for more complex examples. For example,
+'a.b.c.d.e.f.g.attribute' would search for 'attribute' in 'g' and all
+its containers first. (Containers are searched in order from the
+innermost parent to the outermost container.) If the attribute is not
+found in g or any of its containers, then the search moves to 'f' and
+all its containers, and so on.
+
+Additional Attributes and Methods
+=================================
+
+You can use the special method 'aq_inner' to access an object wrapped
+only by containment. So in the example above::
+
+  a.b.x.aq_inner
+
+is equivalent to::
+
+  a.x
+
+You can find out the acquisition context of an object using the
+'aq_chain' method like so::
+
+  a.b.x.aq_chain # returns [x, b, a]
+
+You can find out if an object is in the acquisition context of
+another object using the 'aq_inContextOf' method. For example::
+
+  a.b.x.aq_inContextOf(a.b) # returns 1
+
+
+You can also pass an additional argument to 'aq_inContextOf' to
+indicate whether to only check containment rather than the full
+acquisition context. For example::
+
+  a.b.x.aq_inContextOf(a.b, 1) # returns 0
+
+Note: as of this writing the 'aq_inContextOf' examples don't
+work. According to Jim, this is because 'aq_inContextOf' works by
+comparing object pointer addresses, which (because they are actually
+different wrapper objects) doesn't give you the expected results. He
+acknowledges that this behavior is controversial, and says that there
+is a collector entry to change it so that you would get the answer
+you expect in the above. (We just need to get to it).
+
+
+Acquisition Module Functions
+----------------------------
+
+In addition to using acquisition attributes and methods directly on
+objects you can use similar functions defined in the 'Acquisition'
+module. These functions have the advantage that you don't need to
+check to make sure that the object has the method or attribute before
+calling it.
+
+'aq_acquire(object, name [, filter, extra, explicit, default, containment])' -- Acquires an object with the given name.
+
+This function can be used to explictly acquire when using explicit
+acquisition and to acquire names that wouldn't normally be acquired.
+
+The function accepts a number of optional arguments:
+
+- 'filter' -- A callable filter object that is used to decide if an
+  object should be acquired.
+
+  The filter is called with five arguments:
+
+  - The object that the aq_acquire method was called on,
+
+  - The object where an object was found,
+
+  - The name of the object, as passed to aq_acquire,
+
+  - The object found, and
+
+  - The extra argument passed to aq_acquire.
+
+  If the filter returns a true object that the object found is
+  returned, otherwise, the acquisition search continues.
+
+- 'extra' -- extra data to be passed as the last argument to the
+  filter.
+
+- 'explicit' -- A flag (boolean value) indicating whether explicit
+  acquisition should be used. The default value is true.  If the flag
+  is true, then acquisition will proceed regardless of whether
+  wrappers encountered in the search of the acquisition hierarchy are
+  explicit or implicit wrappers. If the flag is false, then parents
+  of explicit wrappers are not searched.
+
+  This argument is useful if you want to apply a filter without
+  overriding explicit wrappers.
+
+- 'default' -- A default value to return if no value can be acquired.
+
+- 'containment' -- A flag indicating whether the search should be
+  limited to the containment hierarchy.
+
+In addition, arguments can be provided as keywords.
+
+- 'aq_base(object)' -- Return the object with all wrapping removed.
+
+- 'aq_chain(object [, containment])' -- Return a list containing the
+  object and it's acquisition parents. The optional argument,
+  'containment', controls whether the containment or access hierarchy
+  is used.
+
+- 'aq_get(object, name [, default, containment])' -- Acquire an
+  attribute, name. A default value can be provided, as can a flag
+  that limits search to the containment hierarchy.
+
+- 'aq_inner(object)' -- Return the object with all but the innermost
+  layer of wrapping removed.
+
+- 'aq_parent(object)' -- Return the acquisition parent of the object
+  or 'None' if the object is unwrapped.
+
+- 'aq_self(object)' -- Return the object with one layer of wrapping
+  removed, unless the object is unwrapped, in which case the object
+  is returned.
+
+In most cases it is more convenient to use these module functions
+instead of the acquisition attributes and methods directly.
+
+Acquisition and Methods
+=======================
+
+Python methods of objects that support acquisition can use acquired
+attributes.  When a Python method is called on an object that is
+wrapped by an acquisition wrapper, the wrapper is passed to the
+method as the first argument.  This rule also applies to user-defined
+method types and to C methods defined in pure mix-in classes.
+
+Unfortunately, C methods defined in extension base classes that
+define their own data structures, cannot use aquired attributes at
+this time.  This is because wrapper objects do not conform to the
+data structures expected by these methods. In practice, you will
+seldom find this a problem.
+
+Conclusion
+==========
+
+Acquisition provides a powerful way to dynamically share information
+between objects. Zope using acquisition for a number of its key
+features including security, object publishing, and DTML variable
+lookup. Acquisition also provides an elegant solution to the problem
+of circular references for many classes of problems. While
+acquisition is powerful, you should take care when using acquisition
+in your applications. The details can get complex, especially with
+the differences between acquiring from context and acquiring from
+containment.

Copied: zope2docs/trunk/zdgbook/AppendixA.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/AppendixA.rst)
===================================================================
--- zope2docs/trunk/zdgbook/AppendixA.rst	                        (rev 0)
+++ zope2docs/trunk/zdgbook/AppendixA.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,123 @@
+#################################
+Appendix A: Zope Core Permissions
+#################################
+
+This is a list of standard permissions included with Zope.  It is a
+good idea to use these permissions when applicable with your Zope
+products, rather than creating new ones.  A list of built-in Zope
+permissions are available in Zope source code:
+``src/AccessControl/Permissions.py``.
+
+Core Permissions
+================
+
+- Access contents information -- get "directory listing" info
+
+- Add Accelerated HTTP Cache Managers -- add HTTP Cache Manager objects
+
+- Add Database Methods -- add ZSQL Method objects
+
+- Add Documents, Images, and Files -- add DTML Method/Document objects,
+  Image objects, and File objects
+
+- Add External Methods  -- add External Method objects
+
+- Add Folders -- add Folder objects
+
+- Add MailHost objects  -- add MailHost objects
+
+- Add Python Scripts  -- Add Python Script objects
+
+- Add RAM Cache Managers  -- Add RAM Cache manager objects
+
+- Add Site Roots -- add Site Root objects
+
+- Add User Folders  -- add User Folder objects
+
+- Add Versions  -- add Version objects
+
+- Add Virtual Host Monsters  -- add Virtual Host Monster objects
+
+- Add Vocabularies  -- add Vocabulary objects (ZCatalog-related)
+
+- Add ZCatalogs  -- add ZCatalog objects
+
+- Add Zope Tutorials  -- add Zope Tutorial objects
+
+- Change DTML Documents -- modify DTML Documents
+
+- Change DTML Methods  -- modify DTML Methods
+
+- Change Database Connections  -- change database connection objects
+
+- Change Database Methods  -- change ZSQL method objects
+
+- Change External Methods -- change External Method objects
+
+- Change Images and Files  -- change Image and File objects
+
+- Change Python Scripts  -- change Python Script objects
+
+- Change Versions  -- change Version objects
+
+- Change bindings  -- change bindings (for Python Scripts)
+
+- Change cache managers  -- change cache manager objects
+
+- Change cache settings  -- change cache settings (cache mgr parameters)
+
+- Change configuration  -- generic
+
+- Change permissions  -- change permissions
+
+- Change proxy roles  -- change proxy roles
+
+- Create class instances  -- used for ZClass permission mappings
+
+- Delete objects  -- delete objects
+
+- Edit Factories  -- edit Factory objects (ZClass)
+
+- FTP access  -- allow FTP access to this object
+
+- Import/Export objects  -- export and import objects
+
+- Join/leave Versions  -- join and leave Zope versions
+
+- Manage Access Rules -- manage access rule objects
+
+- Manage Vocabulary  -- manage Vocabulary objects
+
+- Manage Z Classes  -- Manage ZClass objects (in the control panel)
+
+- Manage ZCatalog Entries  -- catalog and uncatalog objects
+
+- Manage properties -- manage properties of an object
+
+- Manage users  -- manage Zope users
+
+- Open/Close Database Connections  -- open and close database connections    
+
+- Query Vocabulary -- query Vocabulary objects (ZCatalog-related)
+
+- Save/discard Version changes -- save or discard Zope version changes
+
+- Search ZCatalog -- search a ZCatalog instance
+
+- Take ownership  -- take ownership of an object
+
+- Test Database Connections  -- test database connection objects
+
+- Undo changes  -- undo changes to the ZODB (e.g. use the Undo tab)
+
+- Use Database Methods  -- use ZSQL methods
+
+- Use Factories  -- use Factory objects (ZClass-related)
+
+- Use mailhost services -- use MailHost object services
+
+- View -- view or execute an object
+
+- View History -- view ZODB history of an object
+
+- View management screens -- view management screens related to an object

Copied: zope2docs/trunk/zdgbook/ComponentsAndInterfaces.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/ComponentsAndInterfaces.rst)
===================================================================
--- zope2docs/trunk/zdgbook/ComponentsAndInterfaces.rst	                        (rev 0)
+++ zope2docs/trunk/zdgbook/ComponentsAndInterfaces.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,333 @@
+#########################
+Components and Interfaces
+#########################
+
+Zope uses a component architecture internally in many places.  Zope
+components is nothing but Python objects with interfaces that
+describe them.  As a Zope developer you can use interfaces right now
+to build your Zope components.
+
+Zope Components
+===============
+
+Components are objects that are associated with interfaces.  An
+interface is a Python object that describes how you work with other
+Python objects.  In this chapter, you'll see some simple examples of
+creating components, and a description of interfaces and how they
+work.
+
+Here is a very simple component that says hello.  Like all
+components, this one generally consists of two pieces, an interface,
+and an implementation::
+
+  from zope.interface import Interface
+  from zope.interface import implements
+
+  class IHello(Interface):
+      """The Hello interface provides greetings."""
+
+      def hello(name):
+          """Say hello to the name"""
+
+  class HelloComponent(object):
+
+      implements(IHello)
+
+      def hello(self, name):
+          return "hello %s!" % name
+
+Let's take a look at this step by step.  Here, you see two Python
+class statements.  The first class statement creates the *interface*,
+and the second class statement creates the *implementation*.
+
+The first class statement creates the ``IHello`` interface.  This
+interface describes one method, called ``hello``.  Notice that there
+is no implementation for this method, interfaces do not define
+behavior, they just describe a specification.
+
+The second ``class`` statement creates the ``HelloComponent`` class.
+This class is the actual component that *does* what ``IHello``
+*describes*.  This is usually referred to as the *implementation* of
+``IHello``.  In order for you to know what interfaces
+``HelloComponent`` implements, it must somehow associate itself with
+an interface.  The ``implements`` function call inside the class does
+just that.  It says, "I implement these interfaces".  In this case,
+``HelloComponent`` asserts that it implements one interface,
+``IHello``.
+
+The interface describes how you would work with the object, but it
+doesn't dictate how that description is implemented.  For example,
+here's a more complex implementation of the ``Hello`` interface::
+
+  import xmlrpclib
+  class XMLRPCHello:
+
+      implementats(IHello)
+
+      def hello(self, name):
+          """Delegates the hello call to a remote object
+          using XML-RPC.
+
+          """
+          s = xmlrpclib.Server('http://www.zope.org/')
+          return s.hello(name)
+
+This component contacts a remote server and gets its hello greeting
+from a remote component.
+
+And that's all there is to components, really.  The rest of this
+chapter describes interfaces and how you can work with them from the
+perspective of components.  In Chapter 3, we'll put all this together
+into a Zope product.
+
+Python Interfaces
+=================
+
+Interface describe the behavior of an object by containing useful
+information about the object.  This information includes:
+
+- Prose documentation about the object.  In Python terms, this is
+  called the "doc string" of the interface.  In this element, you
+  describe how the object works in prose language and any other
+  useful information about the object.
+
+- Descriptions of attributes.  Attribute descriptions include the
+  name of the attribute and prose documentation describing the
+  attributes usage.
+
+- Descriptions of methods.  Method descriptions can include:
+
+  - Prose "doc string" documentation about the method and its usage.
+
+  - A sequence of parameter objects that describes the parameters
+    expected by the method.
+
+- Optional tagged data.  Interface objects (and their attributes,
+  methods, and method parameters) can have optional, application
+  specific tagged data associated with them.  Examples uses for this
+  are security assertions, pre/post conditions, unit tests, and other
+  possible information you may want to associate with an Interface or
+  its attributes.
+
+Not all of this information is mandatory.  For example, you may only
+want the methods of your interface to have prose documentation and
+not describe the arguments of the method in exact detail.  Interface
+objects are flexible and let you give or take any of these
+components.
+
+Why Use Interfaces?
+===================
+
+Interfaces solve a number of problems that arise while developing
+large systems with lots of developers.
+
+- Developers waste a lot of time looking at the source code of your
+  system to figure out how objects work.  This is even worse if
+  someone else has already wasted their time doing the same thing.
+
+- Developers who are new to your system may misunderstand how your
+  object works, causing, and possibly propagating, usage errors.
+
+- Because an object's interface is inferred from the source,
+  developers may end up using methods and attributes that are meant
+  for "internal use only".
+
+- Code inspection can be hard, and very discouraging to novice
+  programmers trying to understand code written by gurus.
+
+Interfaces try to solve these problems by providing a way for you to
+describe how to use an object, and a mechanism for discovering that
+description.
+
+Creating Interfaces                                       
+===================
+
+The first step to creating a component, as you've been shown, is to
+create an interface.
+
+Interface objects can be conveniently constructed using the Python
+``class`` statement.  Keep in mind that this syntax can be a little
+misleading, because interfaces are *not* classes.  It is important to
+understand that using Python's class syntax is just a convenience,
+and that the resulting object is an *interface*, not a class.
+
+To create an interface object using Python's class syntax, create a
+Python class that subclasses from ``zope.interface.Interface``::
+
+  from zope.interface import Interface
+
+  class IHello(Interface):
+
+      def hello(name):
+          """Say hello to the world"""
+
+This interface does not implement behavior for its methods, it just
+describes an interface that a typical "Hello" object would realize.
+By subclassing the ``zope.interface.Interface`` interface, the
+resulting object ``Hello`` is an interface object. The Python
+interpreter confirms this::
+
+  >>> IHello
+  <InterfaceClass __main__.IHello>
+
+Now, you can associate the ``Hello`` Interface with your new concrete
+class in which you define your user behavior.  For example::
+
+  class HelloComponent:
+
+      implements(IHello)
+
+      def hello(self, name):
+          return "Hello %s!" % name
+
+This new class, ``HelloComponent`` is a concrete class that
+implements the ``Hello`` interface.  A class can realize more than
+one interface.  For example, say you had an interface called 'Item'
+that described how an object worked as an item in a "Container"
+object.  If you wanted to assert that ``HelloComponent`` instances
+realized the ``Item`` interface as well as ``Hello``, you can provide
+a sequence of Interface objects to the 'HelloComponent' class::
+
+  class HelloComponent:
+
+      implements(IHello, IItem)
+
+
+The Interface Model
+===================
+
+Interfaces can extend other interfaces.  For example, let's extend
+the ``IHello`` interface by adding an additional method::
+
+  class ISmartHello(IHello):
+      """A Hello object that remembers who it's greeted"""
+
+      def lastGreeted(self):
+          """Returns the name of the last person greeted."""
+
+
+``ISmartHello`` extends the ``IHello`` interface.  It does this by
+using the same syntax a class would use to subclass another class.
+
+Now, you can ask the ``ISmartHello`` for a list of the interfaces it
+extends with ``getBases``::
+
+  >>> ISmartHello.getBases()
+  (<InterfaceClass __main__.IHello>,)
+
+An interface can extend any number of other interfaces, and
+``getBases`` will return that list of interfaces for you.  If you
+want to know if ``ISmartHello`` extends any other interface, you
+could call ``getBases`` and search through the list, but a
+convenience method called ``extends`` is provided that returns true
+or false for this purpose::
+
+  >>> ISmartHello.extends(IHello)
+  True
+  >>> ISandwich(Interface):
+  ...     pass
+  >>> ISmartHello.extends(ISandwich)
+  False
+
+Here you can see ``extends`` can be used to determine if one
+interface extends another.
+
+You may notice a similarity between interfaces extending from other
+interfaces and classes sub-classing from other classes.  This *is* a
+similar concept, but the two should not be considered equal.  There
+is no assumption that classes and interfaces exist in a one to one
+relationship; one class may implement several interfaces, and a class
+may not implement its base classes's interfaces.
+
+The distinction between a class and an interface should always be
+kept clear.  The purpose of a class is to share the implementation of
+how an object works.  The purpose of an interface is to document how
+to work *with* an object, not how the object is implemented.  It is
+possible to have several different classes with very different
+implementations realize the same interface.  Because of this,
+interfaces and classes should never be confused.
+
+
+Querying an Interface
+=====================
+
+Interfaces can be queried for information.  The simplest case is to
+ask an interface the names of all the various interface items it
+describes.  From the Python interpreter, for example, you can walk
+right up to an interface and ask it for its *names*::
+
+  >>> User.names()
+  ['getUserName', 'getFavoriteColor', 'getPassword']
+
+Interfaces can also give you more interesting information about their
+items.  Interface objects can return a list of '(name, description)'
+tuples about their items by calling the *namesAndDescriptions*
+method.
+
+For example::
+
+  >>> User.namesAndDescriptions()
+  [('getUserName', <Interface.Method.Method object at 80f38f0>),
+  ('getFavoriteColor', <Interface.Method.Method object at 80b24f0>),
+  ('getPassword', <Interface.Method.Method object at 80fded8>)]
+
+As you can see, the "description" of the Interface's three items in
+these cases are all `Method` objects.  Description objects can be
+either 'Attribute' or `Method` objects.  Attributes, methods, and
+interface objects implement the following interface::
+
+- `getName()` -- Returns the name of the object.
+
+- `getDoc()` -- Returns the documentation for the object.
+
+Method objects provide a way to describe rich meta-data about Python
+methods. Method objects have the following methods:
+
+- `getSignatureInfo()` -- Returns a dictionary describing the method
+  parameters.
+
+- `getSignatureString()` -- Returns a human-readable string
+  representation of the method's signature.
+
+For example::
+
+  >>> m = User.namesAndDescriptions()[0][1]
+  >>> m
+  <Interface.Method.Method object at 80f38f0>
+  >>> m.getSignatureString()
+  '(fullName=1)'
+  >>> m.getSignatureInfo()   
+  {'varargs': None, 'kwargs': None, 'optional': {'fullName': 1}, 
+  'required': (), 'positional': ('fullName',)}  
+
+You can use `getSignatureInfo` to find out the names and types of the
+method parameters.
+
+
+Checking Implementation
+=======================
+
+You can ask an interface if a certain class or instance that you hand
+it implements that interface.  For example, say you want to know if
+instances of the `HelloComponent` class implement 'Hello'::
+
+  IHello.implementedBy(HelloComponent)
+
+This is a true expression.  If you had an instance of
+`HelloComponent`, you can also ask the interface if that instance
+implements the interface::
+
+  IHello.implementedBy(my_hello_instance)
+
+This would also return true if *my_hello_instance* was an instance of
+*HelloComponent*, or any other class that implemented the *Hello*
+Interface.
+
+Conclusion
+==========
+
+Interfaces provide a simple way to describe your Python objects.  By
+using interfaces you document capabilities of objects.  As Zope
+becomes more component oriented, your objects will fit right in.
+While components and interfaces are forward looking technologies,
+they are useful today for documentation and verification.

Copied: zope2docs/trunk/zdgbook/Credits.txt (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/Credits.txt)
===================================================================
--- zope2docs/trunk/zdgbook/Credits.txt	                        (rev 0)
+++ zope2docs/trunk/zdgbook/Credits.txt	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,13 @@
+#######
+Credits
+#######
+
+- Amos Latteier
+
+- Michel Pelletier
+
+- Shane Hathaway
+
+- Chris McDonough
+
+- Beehive

Copied: zope2docs/trunk/zdgbook/GettingStarted.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/GettingStarted.rst)
===================================================================
--- zope2docs/trunk/zdgbook/GettingStarted.rst	                        (rev 0)
+++ zope2docs/trunk/zdgbook/GettingStarted.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,372 @@
+###############
+Getting Started
+###############
+
+Introduction
+============
+
+This chapter cover installation and getting started with development
+of a simple application.  This guide use a build system called
+`Buildout <http://www.buildout.org>`_ to build the application.  And
+the Python packages developed as part of the application can be
+distributed as `Python eggs
+<http://peak.telecommunity.com/DevCenter/setuptools>`_.
+
+
+Directory Structure
+===================
+
+To begin the application development, create a directory structure to
+place Python packages and build related files.
+
+::
+
+  $ mkdir poll
+  $ mkdir poll/poll_build
+  $ mkdir poll/poll.main
+
+All build related files can be added inside `poll_build` directory.
+The main Python package can be added inside `poll.main` directory.
+We can make the ``poll``, a namespace package using the functionality
+provided by `pkg_resources` module included in setuptools.
+
+Bootstraping the Build
+======================
+
+You should have Python 2.5 or 2.6 installed in your system.  To start
+the build process, download and run `bootstrap.py`.  The
+`bootstrap.py` will download and install `setuptools` and
+`zc.buildout` packages.  Also it will create the directory structure
+and `buildout` script inside `bin` directory.
+
+::
+
+  $ cd poll/poll.build
+  $ touch buildout.cfg
+  $ wget -c http://svn.zope.org/repos/main/zc.buildout/trunk/bootstrap/bootstrap.py
+  $ python2.6 bootstrap.py
+
+Installing Zope 2
+=================
+
+From Zope 2.12 onwards Zope 2 is distributed in egg format.  To
+install Zope 2 egg and create an instance, update buildout
+configuration file (``buildout.cfg``) with appropriate parts and
+recipes.
+
+::
+
+  [buildout]
+  parts = zope2
+          instance
+  extends = http://download.zope.org/Zope2/index/2.12.0/versions.cfg
+
+  [zope2]
+  recipe = zc.recipe.egg
+  eggs = Zope2
+  interpreter = zopepy
+
+  [instance]
+  recipe = plone.recipe.zope2instance
+  user = admin:admin
+  http-address = 8080
+  eggs = ${zope2:eggs}
+
+The ``[zope2]`` part use `zc.recipe.egg` which will download `Zope2`
+egg and all its dependencies.  It will create few console scripts
+inside `bin` directory.  Also it will create a custom Python
+interpreter named ``zopepy``.
+
+The ``[instance]`` part creates a Zope 2 application instance to
+develop application.  It will create a script named ``instance``
+inside `bin` directory.  We can use that script to run the
+application instance.
+
+After updating the buildout configuration, you can run the `buildout`
+command to build the system.
+
+::
+
+  $ ./bin/buildout
+
+The initial build will take some time to complete.
+
+Running Instance
+================
+
+Once build is completed, you can run Zope 2 instance like this.
+
+::
+
+  $ ./bin/instance fg
+
+
+You can see that Zope is running in 8080 port.  You can go to the
+Zope Management Interface (ZMI).
+
+::
+
+  http://localhost:8080/manage
+
+You can provide the user name & password provided in `[instance]`
+part to access this page.
+
+You can see a list of installable applications in the drop-down box.
+Also you can see it in "Control_Panel" -> "Products".
+
+::
+
+  http://localhost:8080/Control_Panel/Products/manage_main
+
+In the next section we will make the `poll.main` listed here.  And
+later we will make it installable.
+
+
+Developing the main package
+===========================
+
+Now we can move to `poll.main` packae to create the main package to
+develop the application.  We can develop the entire application
+inside `poll.main` package.  But it is reccomended to split packages
+logically and maintain the dependencies between packages properly.
+
+::
+
+  $ cd ../poll.build
+
+Again we need to create the basic directory structure and `setup.py`
+to create egg distribution.  We are going to place python package
+inside `src` directory.
+
+::
+
+  $ touch setup.py
+  $ mkdir src
+  $ mkdir src/poll
+  $ mkdir src/poll/main
+  $ touch src/poll/__init__.py
+  $ touch src/poll/main/__init__.py
+  $ touch src/poll/main/configure.zcml
+
+The last file we created is a configuration file called Zope
+Configuration Markup Language (ZCML). Soon we will add some boiler
+plate code inside ZCML file.
+
+To declare `poll` as a namespace package, we need to add this boiler
+plate code to `src/poll/__init__.py`.
+
+::
+
+  __import__('pkg_resources').declare_namespace(__name__)
+
+Next we need to add the minimum meta data required for the package in
+`setup.py`.
+
+::
+
+  from setuptools import setup, find_packages
+
+  setup(
+      name="poll.main",
+      version="0.1",
+      packages=find_packages("src"),
+      package_dir={"": "src"},
+      namespace_packages=["poll"],
+      install_requires=["setuptools",
+                        "Zope2"],
+      )
+
+We need to add two more files to be recognized by Zope.  First,
+define this call-back function in `src/poll/main/__init__.py`.
+
+::
+
+  def initialize(registrar):
+      pass
+
+And in the ZCML file add these few lines.
+
+::
+
+  <configure
+      xmlns="http://namespaces.zope.org/five">
+
+      <registerPackage package="." initialize=".initialize" />
+
+  </configure>
+
+Creating Installable Application
+================================
+
+We need three things to make an installable application.
+
+- Form object created using ZPT (manage_addPollMain)
+- A function to define form action (addPollMain)
+- A class to define toplevel application object (PollMain).
+
+And we need to register the class along with form and add function
+using the `registrar` object passed to the `initialize` function.
+
+We can define all these things in `app.py` and the form template as
+`manage_addPollMain_form.zpt`.
+
+::
+
+  $ touch src/poll/main/app.py
+  $ touch src/poll/main/manage_addPollMain_form.zpt
+
+Here is the code for `app.py`.
+
+::
+
+  from OFS.Folder import Folder
+  from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+
+  class PollMain(Folder):
+      meta_type = "POLL"
+
+  manage_addPollMain = PageTemplateFile("manage_addPollMain_form", globals())
+
+  def addPollMain(context, id):
+      """ """
+      context._setObject(id, PollMain(id))
+      return "POLL Installed: %s" % id
+
+And `manage_addPollMain_form.zpt`.
+
+::
+
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:tal="http://xml.zope.org/namespaces/tal">
+    <body>
+
+      <h2>Add POLL</h2>
+      <form action="addPollMain" method="post">
+        Id: <input type="text" name="id" /><br />
+        Title: <input type="text" name="title" /><br />
+        <input type="submit" value="Add" />
+      </form>
+    </body>
+  </html>
+
+Finally we can register it like this (update `__init__.py`)::
+
+  from poll.main.app import PollMain, manage_addPollMain, addPollMain
+
+  def initialize(registrar):
+      registrar.registerClass(PollMain,
+                              constructors=(manage_addPollMain, addPollMain))
+
+The application is now ready to install.  But we need to make some
+changes in `poll_build` to recognize this package by Zope 2.
+
+Adding poll.main to build
+=========================
+
+First in `[buildout]` part we need to mention that `poll.main` is
+locally developed.  Otherwise buildout will try to get the package
+from package index server, by default http://pypi.python.org/pypi .
+
+::
+
+  [buildout]
+  develop = ../poll.main
+  ...
+
+Also we need to add `poll.main` egg to `eggs` option in `[zope2]`
+part.
+
+::
+
+  ...
+  eggs = Zope2
+         poll.main
+  ...
+
+And finally we need to add a new option to include the ZCML file.  So
+that the package will be recognized by Zope.
+
+::
+
+  ...
+  zcml = poll.main
+
+The final `buildout.cfg` will look like this.
+
+::
+
+  [buildout]
+  develop = ../poll.main
+  parts = zope2
+          instance
+
+  [zope2]
+  recipe = zc.recipe.egg
+  eggs = Zope2
+         poll.main
+  interpreter = zopepy
+
+  [instance]
+  recipe = plone.recipe.zope2instance
+  user = admin:admin
+  http-address = 8080
+  eggs = ${zope2:eggs}
+  zcml = poll.main
+
+Now to make these change effective, run the buildout again.
+
+::
+
+  $ ./bin/buildout
+
+Now we can run application instance again.
+
+::
+
+  $ ./bin/instance fg
+
+Adding application instance
+===========================
+
+Visit ZMI and select `POLL` from the drop-down box.  It will display
+the add-form created earlier.  You can provide the ID as `poll` and
+submit the form.  After submitting, it should display a message:
+"POLL Installed: poll".
+
+Adding the main page to POLL
+============================
+
+In this section we will try to add a main page to POLL application.
+So that we can acces POLL application like this:
+http://localhost:8080/poll .
+
+First create a file named `index_html.zpt` inside `src/poll/main` with
+content like this::
+
+  <html>
+  <head>
+    <title>Welcome to POLL!</title>
+  </head>
+  <body>
+
+  <h2>Welcome to POLL!</h2>
+
+  </body>
+  </html>
+
+Now add an attribute named `index_html` inside PollMain class like
+this::
+
+  class PollMain(Folder):
+      meta_type = "POLL"
+
+      index_html = PageTemplateFile("index_html", globals())
+
+Restart the Zope. Now you can see that it display the main page when
+you access: http://localhost:8080/poll .
+
+Summary
+=======
+
+This chapter covered installation and beginning a simple project in
+Zope 2.

Deleted: zope2docs/trunk/zdgbook/Gotchas.stx
===================================================================
--- zope2docs/trunk/zdgbook/Gotchas.stx	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/Gotchas.stx	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,169 +0,0 @@
-Here is the place to add comments about "gotchas" related to Zope development.  We will try to work
-these in to the ZDG narrative from time to time.
-
-  % mcdonc - Jan. 17, 2002 6:23 pm - Methods declared in Product classes must
-    have docstrings to callable by visiting them "through the web" (by calling
-    them up by URL via a browser).
-
-  % Anonymous User - Feb. 27, 2002 10:52 pm - Volatile attributes are not shared
-    between threads, so using them for  page counters or holding state between
-    requests will not work (although it will sometimes appear to until your server
-    is under load)
-
-  % Anonymous User - May 22, 2002 7:18 am:
-   DTMLMethod with a name ending '_alpha' was not rendered at all
-
-  % Anonymous User - July 17, 2002 1:40 pm:
-   From Zope Maillist:
-   On Tue, 16 Jul 2002, Ross Boylan wrote:
-   > The Zope Developer's Guide and the API docs (Zope 2.5) present
-   > different stories about how to add things to object managers.  I don't
-   > really follow what the API stuff is doing.  This is a request for
-   > clarification.
-   >
-   > Devguide says do
-   > def addFunction(dispatcher, id):
-   >    "Create object and add to self"
-   >    p = SomeProduct(id)
-   >    dispatcher.Destination()._setObject(id, p)
-   >
-   > This makes sense, though, as commented at
-   > http://www.zope.org//Members/michel/Projects/Interfaces/ObjectManager,
-   > it relies on a private, undocumented method.  addFunction is in outer
-   > scope of a module, and is hooked up wtih various calls in ___init__.py.
-   Call this the "add function".  Defined by the product, it is passed
-   the dispatcher for the ObjectManager to which the object is being added.
-   As you say, it apparently uses a private function, however despite
-   it's (historical artifact of a) name, it is the proper way to do
-   this operation.  And it is documented, in the Dev Guide <wry grin>.
-   > On the other hand, the ObjectManager API says to do
-   > self.manage_addProduct['OFSP'].manage_addFolder(id, title).
-   This is the action that non-Product code uses to add an object from
-   the Product to an arbitrary object manager.  'self' being the object
-   manager in question (eg: when called from an External Method, self
-   will be the folder the External Method was called on).  This sequence
-   *calls* the "add function" defined above.  In this case, it is
-   calling the add function defined by the Folder object in the OFSP
-   Product.
-   > First, what scope should that be done in?  Second, this seems to
-   > create one product (OFSP) and then add a folder to it, so that it
-   > creates two, nested products.
-   Actually, it doesn't.  This syntax has bothered me since I first
-   encoutered it, and I'm sure I'm not alone.  But we are stuck with
-   it (for now).  "manage_addProduct[<someproductname>]" is, essentially,
-   a lookup in a registry keyed by product name.  So that part looks
-   up the Product from the registry, and then you have access to the
-   module level functions in that Product, such as the "add function"
-   defined above.
-   > The API for Folder mentions manage_addFolder as a constructor, but
-   > again the scope is unclear to me.  Presumably it needs to know what to
-   > add it to, but that is not passed in.
-   You are calling the method on 'self' in the API example, or on some
-   other reference to an ObjectManager in some other context.
-   (Literally 'context' if you were doing this from a pythonscript.)
-   'manage_addProduct' gets "acquired" (from where I'm not quite sure
-   <wry grin>), and some magic that I haven't had a need to look in
-   to arranges things so that your add function gets passed a dispatcher
-   that has that ObjectManager as its Destination() as its first
-   argument, followed by whatever arguments (id, title) in the API
-   example) you pass it explicitly.  This is an example of Zope2
-   "magic" that we are trying hard to eliminate from Zope3 <grin>.
-   > Finally, the use of id in two places in the first code snippet (one
-   > apparently associated with the container, the other with the object)
-   > seems like an invitation to trouble.  Why is it done that way?
-   Tell us about it.  This is an old Zope2 (or was it bobo?) design
-   decision that has been revisited in Zope3.  In Zope3, only containers
-   know about ids in the general case, not the objects referenced by
-   them.
-   > One reason I want to know this is that I'm considering having a
-   > container that would automatically label (or set id) of its contents
-   > (e.g., 'a' is first, 'b' is second....).
-   >
-   > Thanks for any light you can shed.
-   Hopefully I haven't told you anything untrue up above, but if I have
-   someone will doubtless correct me <grin>.
-   --RDM
-
-  % eckamm - Nov. 11, 2002 10:05 pm:
-   This one has bit me on more than one occassion:
-       manage_add_XYZ_form = DTMLFile('dtml/manage_add_XYZ_form')
-   instead of:
-       manage_add_XYZ_form = DTMLFile('dtml/manage_add_XYZ_form', globals())
-   The error message is tough to interpret; it looks like an attempt
-   is made to find manage_add_XYZ_form.dtml in {base}/lib/python/dtml/.
-   This may send you on a wild goose chase if you're like me.
-
-  % slinkp - Mar. 21, 2003 12:53 pm:
-   i just posted this to the zope list...
-   I find "Monkey patches" a useful way to expand or modify functionality provided by
-   zope or 3rd-party products, but I just discovered something very important:
-   it's apparently NOT safe to "refresh" a MonkeyPatch-style product.
-   I have a monkeypatch that works fine until I refresh it, then I get mysterious
-   errors like "Object of type 'None' is not callable" with no indication in the
-   traceback of what object is None or even what's trying to call it!
-   I've spent hours in a debugging session trying to find out what's None and
-   came up with nothing.
-   Then i discovered that if i restart zope, everything's fine. :-P
-
-  % Anonymous User - Mar. 29, 2003 12:43 am:
-   slinkp: Yes, that's right, you should never try to refresh monkey patch
-   products. However, I haven't found the right way to spread this warning
-   so that the people who need to know it will hear it. How do you suggest
-   this be documented?
-   Shane Hathaway
-
-  % Anonymous User - Aug. 5, 2003 4:51 pm:
-   Seems obvious to some, but wansn't obvious to me:
-   ZCatalog method searchResults' sort_limit argument only works when sort_on
-   argument is present as well. A "nice to have" would be to limit unsorted
-   results coming back from the catalog as opposed to doing it after the fact.
-
-  % slinkp - Dec. 8, 2003 3:32 pm:
-   Don't confuse paths and URLs. Specifically, avoid using absolute_url(1) or path variables from REQUEST when
-   constructing paths that will be fed to restrictedTraverse() or similar. Everything works fine until virtual
-   hosting comes into play, at which point some part of your path may be meaningful to the client but not
-   correspond to any object in Zope. This can lead to much hair-tearing when your working app suddenly breaks at
-   deployment time. Solution: if you need to fiddle with paths, use '/'.join(foo.getPhysicalPath()) instead.
-   This is unaffected by virtual hosting.
-   The behavior of absolute_url(1) *may* change in zope 2.7 or later, we're still arguing about it :-)
-
-  % slinkp - Jan. 24, 2004 6:26 pm:
-   Set self._p_changed=1  *before* mutating something, not after.
-   From Steve Alexander on the zodb-dev mailing list:
-   > The reason to set _p_changed before mutating the object is because if
-   > there is an exception raised after a mutation but before setting
-   > _p_changed, your persistnent object might stay around in the cache. That
-   > is, it would not be reloaded with fresh state.
-   >
-   > Consider this example:
-   >
-   >      def storeMany(self, keys, values):
-   >          for key, value in zip(keys, values):
-   >              self.bar[key] = value
-   >          self._p_changed = 1  # This is too late!
-   >
-   > What happens if I call the method as below?
-   >
-   >   obj.storeMany(['fish', {}, 'fluid'], [6, 28, 496])
-   >
-   > The method will raise a TypeError because dicts are unhashable. However,
-   > the entry 'fish': 6 will have been added to the dict. The ZODB will not
-   > realize that the object has effectively changed, so the object can stick
-   > around in the cache.
-   Personally, I now prefer to avoid directly touching self._p_changed when possible:
-   1) as the zdg says, it isn't necessary for immutables.
-   2) for mutables, many cases can be covered by BTrees, PersistentLists, and
-   PersistentMappings which are very kindly provided by ZODB, so we should
-   use them :-)
-
-  % slinkp - Apr. 18, 2005 9:59 am:
-   ComputedAttributes are not documented by the ZDG, and they should be.
-
-  % slinkp - Apr. 18, 2005 10:32 am:
-   I just added some ComputedAttribute doc at http://zopewiki.org/ComputedAttribute,
-   feel free to copy this for next version of ZDG.
-
-  % Anonymous User - Aug. 19, 2005 6:24 pm:
-   Make sure that your classes inherit from Acquisition.Implicit or Acquisition.Explicit. In mid-development I
-   thought that was probably unnecessary and deleted that base class, which later caused objects I added to not
-   acquire the security information needed, leaving me unable to manage those objects.

Copied: zope2docs/trunk/zdgbook/Gotchas.txt (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/Gotchas.txt)
===================================================================
--- zope2docs/trunk/zdgbook/Gotchas.txt	                        (rev 0)
+++ zope2docs/trunk/zdgbook/Gotchas.txt	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,169 @@
+Here is the place to add comments about "gotchas" related to Zope development.  We will try to work
+these in to the ZDG narrative from time to time.
+
+  % mcdonc - Jan. 17, 2002 6:23 pm - Methods declared in Product classes must
+    have docstrings to callable by visiting them "through the web" (by calling
+    them up by URL via a browser).
+
+  % Anonymous User - Feb. 27, 2002 10:52 pm - Volatile attributes are not shared
+    between threads, so using them for  page counters or holding state between
+    requests will not work (although it will sometimes appear to until your server
+    is under load)
+
+  % Anonymous User - May 22, 2002 7:18 am:
+   DTMLMethod with a name ending '_alpha' was not rendered at all
+
+  % Anonymous User - July 17, 2002 1:40 pm:
+   From Zope Maillist:
+   On Tue, 16 Jul 2002, Ross Boylan wrote:
+   > The Zope Developer's Guide and the API docs (Zope 2.5) present
+   > different stories about how to add things to object managers.  I don't
+   > really follow what the API stuff is doing.  This is a request for
+   > clarification.
+   >
+   > Devguide says do
+   > def addFunction(dispatcher, id):
+   >    "Create object and add to self"
+   >    p = SomeProduct(id)
+   >    dispatcher.Destination()._setObject(id, p)
+   >
+   > This makes sense, though, as commented at
+   > http://www.zope.org//Members/michel/Projects/Interfaces/ObjectManager,
+   > it relies on a private, undocumented method.  addFunction is in outer
+   > scope of a module, and is hooked up wtih various calls in ___init__.py.
+   Call this the "add function".  Defined by the product, it is passed
+   the dispatcher for the ObjectManager to which the object is being added.
+   As you say, it apparently uses a private function, however despite
+   it's (historical artifact of a) name, it is the proper way to do
+   this operation.  And it is documented, in the Dev Guide <wry grin>.
+   > On the other hand, the ObjectManager API says to do
+   > self.manage_addProduct['OFSP'].manage_addFolder(id, title).
+   This is the action that non-Product code uses to add an object from
+   the Product to an arbitrary object manager.  'self' being the object
+   manager in question (eg: when called from an External Method, self
+   will be the folder the External Method was called on).  This sequence
+   *calls* the "add function" defined above.  In this case, it is
+   calling the add function defined by the Folder object in the OFSP
+   Product.
+   > First, what scope should that be done in?  Second, this seems to
+   > create one product (OFSP) and then add a folder to it, so that it
+   > creates two, nested products.
+   Actually, it doesn't.  This syntax has bothered me since I first
+   encoutered it, and I'm sure I'm not alone.  But we are stuck with
+   it (for now).  "manage_addProduct[<someproductname>]" is, essentially,
+   a lookup in a registry keyed by product name.  So that part looks
+   up the Product from the registry, and then you have access to the
+   module level functions in that Product, such as the "add function"
+   defined above.
+   > The API for Folder mentions manage_addFolder as a constructor, but
+   > again the scope is unclear to me.  Presumably it needs to know what to
+   > add it to, but that is not passed in.
+   You are calling the method on 'self' in the API example, or on some
+   other reference to an ObjectManager in some other context.
+   (Literally 'context' if you were doing this from a pythonscript.)
+   'manage_addProduct' gets "acquired" (from where I'm not quite sure
+   <wry grin>), and some magic that I haven't had a need to look in
+   to arranges things so that your add function gets passed a dispatcher
+   that has that ObjectManager as its Destination() as its first
+   argument, followed by whatever arguments (id, title) in the API
+   example) you pass it explicitly.  This is an example of Zope2
+   "magic" that we are trying hard to eliminate from Zope3 <grin>.
+   > Finally, the use of id in two places in the first code snippet (one
+   > apparently associated with the container, the other with the object)
+   > seems like an invitation to trouble.  Why is it done that way?
+   Tell us about it.  This is an old Zope2 (or was it bobo?) design
+   decision that has been revisited in Zope3.  In Zope3, only containers
+   know about ids in the general case, not the objects referenced by
+   them.
+   > One reason I want to know this is that I'm considering having a
+   > container that would automatically label (or set id) of its contents
+   > (e.g., 'a' is first, 'b' is second....).
+   >
+   > Thanks for any light you can shed.
+   Hopefully I haven't told you anything untrue up above, but if I have
+   someone will doubtless correct me <grin>.
+   --RDM
+
+  % eckamm - Nov. 11, 2002 10:05 pm:
+   This one has bit me on more than one occassion:
+       manage_add_XYZ_form = DTMLFile('dtml/manage_add_XYZ_form')
+   instead of:
+       manage_add_XYZ_form = DTMLFile('dtml/manage_add_XYZ_form', globals())
+   The error message is tough to interpret; it looks like an attempt
+   is made to find manage_add_XYZ_form.dtml in {base}/lib/python/dtml/.
+   This may send you on a wild goose chase if you're like me.
+
+  % slinkp - Mar. 21, 2003 12:53 pm:
+   i just posted this to the zope list...
+   I find "Monkey patches" a useful way to expand or modify functionality provided by
+   zope or 3rd-party products, but I just discovered something very important:
+   it's apparently NOT safe to "refresh" a MonkeyPatch-style product.
+   I have a monkeypatch that works fine until I refresh it, then I get mysterious
+   errors like "Object of type 'None' is not callable" with no indication in the
+   traceback of what object is None or even what's trying to call it!
+   I've spent hours in a debugging session trying to find out what's None and
+   came up with nothing.
+   Then i discovered that if i restart zope, everything's fine. :-P
+
+  % Anonymous User - Mar. 29, 2003 12:43 am:
+   slinkp: Yes, that's right, you should never try to refresh monkey patch
+   products. However, I haven't found the right way to spread this warning
+   so that the people who need to know it will hear it. How do you suggest
+   this be documented?
+   Shane Hathaway
+
+  % Anonymous User - Aug. 5, 2003 4:51 pm:
+   Seems obvious to some, but wansn't obvious to me:
+   ZCatalog method searchResults' sort_limit argument only works when sort_on
+   argument is present as well. A "nice to have" would be to limit unsorted
+   results coming back from the catalog as opposed to doing it after the fact.
+
+  % slinkp - Dec. 8, 2003 3:32 pm:
+   Don't confuse paths and URLs. Specifically, avoid using absolute_url(1) or path variables from REQUEST when
+   constructing paths that will be fed to restrictedTraverse() or similar. Everything works fine until virtual
+   hosting comes into play, at which point some part of your path may be meaningful to the client but not
+   correspond to any object in Zope. This can lead to much hair-tearing when your working app suddenly breaks at
+   deployment time. Solution: if you need to fiddle with paths, use '/'.join(foo.getPhysicalPath()) instead.
+   This is unaffected by virtual hosting.
+   The behavior of absolute_url(1) *may* change in zope 2.7 or later, we're still arguing about it :-)
+
+  % slinkp - Jan. 24, 2004 6:26 pm:
+   Set self._p_changed=1  *before* mutating something, not after.
+   From Steve Alexander on the zodb-dev mailing list:
+   > The reason to set _p_changed before mutating the object is because if
+   > there is an exception raised after a mutation but before setting
+   > _p_changed, your persistnent object might stay around in the cache. That
+   > is, it would not be reloaded with fresh state.
+   >
+   > Consider this example:
+   >
+   >      def storeMany(self, keys, values):
+   >          for key, value in zip(keys, values):
+   >              self.bar[key] = value
+   >          self._p_changed = 1  # This is too late!
+   >
+   > What happens if I call the method as below?
+   >
+   >   obj.storeMany(['fish', {}, 'fluid'], [6, 28, 496])
+   >
+   > The method will raise a TypeError because dicts are unhashable. However,
+   > the entry 'fish': 6 will have been added to the dict. The ZODB will not
+   > realize that the object has effectively changed, so the object can stick
+   > around in the cache.
+   Personally, I now prefer to avoid directly touching self._p_changed when possible:
+   1) as the zdg says, it isn't necessary for immutables.
+   2) for mutables, many cases can be covered by BTrees, PersistentLists, and
+   PersistentMappings which are very kindly provided by ZODB, so we should
+   use them :-)
+
+  % slinkp - Apr. 18, 2005 9:59 am:
+   ComputedAttributes are not documented by the ZDG, and they should be.
+
+  % slinkp - Apr. 18, 2005 10:32 am:
+   I just added some ComputedAttribute doc at http://zopewiki.org/ComputedAttribute,
+   feel free to copy this for next version of ZDG.
+
+  % Anonymous User - Aug. 19, 2005 6:24 pm:
+   Make sure that your classes inherit from Acquisition.Implicit or Acquisition.Explicit. In mid-development I
+   thought that was probably unnecessary and deleted that base class, which later caused objects I added to not
+   acquire the security information needed, leaving me unable to manage those objects.

Copied: zope2docs/trunk/zdgbook/Introduction.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/Introduction.rst)
===================================================================
--- zope2docs/trunk/zdgbook/Introduction.rst	                        (rev 0)
+++ zope2docs/trunk/zdgbook/Introduction.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,97 @@
+############
+Introduction
+############
+
+Overview
+========
+
+Zope 2 is a free and open-source, object-oriented web application
+server written in the Python programming language.  The term ZOPE is
+an acronym for "Z Object Publishing Environment" (the Z doesn't
+really mean anything in particular).  However, nowadays ZOPE is
+simply written as Zope.  It has three distinct audiences.
+
+*Site Managers*
+  Individuals who use of Zope's "out of the box" features to build
+  websites.  This audience is interested in making use of Zope's
+  existing array of features to create content management solutions.
+  They will likely make heavy use of "through the web" scripting
+  using DTML, Page Templates, and Python Scripts as well as (of
+  course) HTML and XML.  They are generally less concerned about code
+  reuse than the speed with which they can create a custom
+  application or website.
+
+*Developers*
+  Individuals who wish to extend Zope to create highly customized
+  solutions.  This audience is likely interested in creating highly
+  reusable custom code that makes Zope do something new and
+  interesting.  They will likely make heavy use of "through the
+  file-system" style development.
+
+*Administrators*
+  Individuals responsible for keeping a Zope site running and
+  performing installations and upgrades.
+
+This guide is intended to document Zope for the second audience,
+Developers, as defined above.  If you fit more into the "user"
+audience defined above, you'll probably want to start by reading `The
+Zope Book <http://docs.zope.org/zope2book>`_ .  If you fit more into
+the "administrator" audience defined above, you'll likely be
+interested in `The Zope Administrator's Guide
+<http://www.zope.org/DocProjects/AdminGuide>`_, although it is
+currently unfinished.
+
+Throughout this guide, it is assumed that you know how to program in
+the Python programming language.  Most of the examples in this guide
+will be in Python.  There are a number of great resources and books
+for learning Python; the best online resource is the `python.org web
+site <http://www.python.org/>`_ and many books can be found on the
+shelves of your local bookstore.
+
+Organization of the book
+========================
+
+This book describes Zope's services to the developer from a hands on,
+example-oriented standpoint.  This book is not a complete reference
+to the Zope API, but rather a practical guide to applying Zope's
+services to develop and deploy your own web applications.  This book
+covers the following topics:
+
+*Getting Started*
+  This chapter provides a brief overview of installation and getting
+  started with application development.
+
+*Components and Interfaces*
+  Zope use a component-centric development model.  This chapter
+  describes the component model in Zope and how Zope components are
+  described through interfaces.
+
+*Object Publishing*
+  Developing applications for Zope involves more than just creating a
+  component, that component must be *publishable* on the web.  This
+  chapter describes publication, and how your components need to be
+  designed to be published.
+
+*Zope Products*
+  New Zope components are distributed and installed in packages
+  called "Products".  This chapter explains Products in detail.
+
+*Persistent Components*
+  Zope provides a built-in, transparent Python object database called
+  ZODB.  This chapter describes how to create persistent components,
+  and how they work in conjunction with the ZODB.
+
+*Acquisition*
+  Zope relies heavily on a dynamic technique called acquisition. This
+  chapter explores acquisition thoroughly.
+
+*Security*
+  When your component is used by many different people through the
+  web, security becomes a big concern.  This chapter describes Zope's
+  security API and how you can use it to make security assertions
+  about your object.
+
+*Debugging and Testing*
+  Zope has built in debugging and testing support.  This chapter
+  describes these facilities and how you can debug and test your
+  components.

Deleted: zope2docs/trunk/zdgbook/Makefile
===================================================================
--- zope2docs/trunk/zdgbook/Makefile	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/Makefile	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zdgbook/ObjectPublishing.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/ObjectPublishing.rst)
===================================================================
--- zope2docs/trunk/zdgbook/ObjectPublishing.rst	                        (rev 0)
+++ zope2docs/trunk/zdgbook/ObjectPublishing.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,1297 @@
+#################
+Object Publishing
+#################
+
+Introduction
+============
+
+Zope puts your objects on the web. This is called *object
+publishing*. One of Zope's unique characteristics is the way it
+allows you to walk up to your objects and call methods on them with
+simple URLs.  In addition to HTTP, Zope makes your objects available
+to other network protocols including FTP, WebDAV and XML-RPC.
+
+
+In this chapter you'll find out exactly how Zope publishes
+objects. You'll learn all you need to know in order to design your
+objects for web publishing.
+
+ 
+HTTP Publishing
+===============
+
+When you contact Zope with a web browser, your browser sends an HTTP
+request to Zope's web server. After the request is completely
+received, it is processed by 'ZPublisher', which is Zope's object
+publisher. 'ZPublisher' is a kind of light-weight ORB (Object Request
+Broker). It takes the request and locates an object to handle the
+request. The publisher uses the request URL as a map to locate the
+published object. Finding an object to handle the request is called
+*traversal*, since the publisher moves from object to object as it
+looks for the right one. Once the published object is found, the
+publisher calls a method on the published object, passing it
+parameters as necessary.  The publisher uses information in the
+request to determine which method to call, and what parameters to
+pass. The process of extracting parameters from the request is called
+*argument marshalling*. The published object then returns a response,
+which is passed back to Zope's web server. The web server, then
+passes the response back to your web browser.
+
+
+The publishing process is summarized in [2-1]
+
+.. figure:: Figures/2-1.png
+
+   2.1 Object publishing
+
+
+Typically the published object is a persistent object that the
+published module loads from the ZODB.  See Chapter 4 for more
+information on the ZODB.
+
+
+This chapter will cover all the steps of object publishing in
+detail. To summarize, object publishing consists of the main steps:
+
+1. The client sends a request to the publisher
+
+2. The publisher locates the published object using the request
+   URL as a map.
+
+3. The publisher calls the published object with arguments from
+   the request.
+
+4. The publisher interprets and returns the results to the
+   client.
+
+The chapter will also cover all the technical details, special cases
+and extra-steps that this list glosses over.
+
+
+URL Traversal
+=============
+
+Traversal is the process the publisher uses to locate the published
+object. Typically the publisher locates the published object by
+walking along the URL. Take for example a collection of objects::
+
+      class Classification:
+          ...
+
+      class Animal:
+          ...
+
+          def screech(self, ...):
+              ...
+
+      vertebrates=Classification(...)
+      vertebrates.mammals=Classification(...)
+      vertebrates.reptiles=Classification(...)
+      vertebrates.mammals.monkey=Animal(...)
+      vertebrates.mammals.dog=Animal(...)
+      vertebrates.reptiles.lizard=Animal(...)
+
+
+This collection of objects forms an object hierarchy. Using Zope you
+can publish objects with URLs. For example, the URL
+'http://zope/vertebrates/mammals/monkey/screech', will traverse the
+object hierarchy, find the 'monkey' object and call its 'screech'
+method.
+
+.. figure:: Figures/2-2.png
+
+   2.2 Traversal path through an object hierarchy
+
+The publisher starts from the root object and takes each step in the
+URL as a key to locate the next object. It moves to the next object
+and continues to move from object to object using the URL as a guide.
+
+Typically the next object is a sub-object of the current object that
+is named by the path segment. So in the example above, when the
+publisher gets to the 'vertebrates' object, the next path segment is
+"mammals", and this tells the publisher to look for a sub-object of
+the current object with that name. Traversal stops when Zope comes to
+the end of the URL. If the final object is found, then it is
+published, otherwise an error is returned.
+
+
+Now let's take a more rigorous look at traversal.
+
+Traversal Interfaces
+====================
+
+Zope defines interfaces for publishable objects, and publishable
+modules.
+
+
+When you are developing for Zope you almost always use the 'Zope'
+package as your published module. However, if you are using
+'ZPublisher' outside of Zope you'll be interested in the published
+module interface.
+
+
+Publishable Object Requirements
+===============================
+
+Zope has few restrictions on publishable objects. The basic rule is
+that the object must have a doc string. This requirement goes for
+method objects too.
+
+Another requirement is that a publishable object must not have a name
+that begin with an underscore. These two restrictions are designed to
+keep private objects from being published.
+
+
+Finally, published objects cannot be Python module objects.
+
+Traversal Methods
+=================
+
+During traversal, 'ZPublisher' cuts the URL into path elements
+delimited by slashes, and uses each path element to traverse from the
+current object to the next object. 'ZPublisher' locates the next
+object in one of three ways:
+
+1. Using '__bobo_traverse__'
+
+2. Using 'getattr'
+
+3. Using dictionary access.
+
+First the publisher attempts to call the traversal hook method,
+'__bobo_traverse__'. If the current object has this method it is
+called with the request and the current path element. The method
+should return the next object or 'None' to indicate that a next
+object can't be found. You can also return a tuple of objects from
+'__bobo_traverse__' indicating a sequence of sub-objects. This allows
+you to add additional parent objects into the request. This is almost
+never necessary.
+
+
+Here's an example of how to use '__bobo_traverse__'::
+
+          def __bobo_traverse__(self, request, key):
+              # if there is a special cookie set, return special
+              # subobjects, otherwise return normal subobjects
+
+              if request.cookies.has_key('special'):
+                  # return a subobject from the special dict
+                  return self.special_subobjects.get(key, None)
+
+              # otherwise return a subobject from the normal dict
+              return self.normal_subobjects.get(key, None)
+
+
+This example shows how you can examine the request during the
+traversal process.
+
+If the current object does not define a '__bobo_traverse__'
+method, then the next object is searched for using 'getattr'.
+This locates sub-objects in the normal Python sense.
+
+If the next object can't be found with 'getattr', 'ZPublisher'
+calls on the current object as though it were a
+dictionary. Note: the path element will be a string, not an
+integer, so you cannot traverse sequences using index numbers
+in the URL.
+
+For example, suppose 'a' is the current object, and 'next' is
+the name of the path element. Here are the three things that
+'ZPublisher' will try in order to find the next object:
+
+  1. 'a.__bobo_traverse__("next")'
+
+  2. 'a.next'
+
+  3. 'a["next"]'
+
+
+Publishing Methods        
+==================
+
+Once the published object is located with traversal, Zope *publishes*
+it in one of three possible ways.
+
+- Calling the published object -- If the published object is a
+  function or method or other callable object, the publisher calls
+  it. Later in the chapter you'll find out how the publisher figures
+  out what arguments to pass when calling.
+
+- Calling the default method -- If the published object is not
+  callable, the publisher uses the default method. For HTTP 'GET' and
+  'POST' requests the default method is 'index_html'. For other HTTP
+  requests such as 'PUT' the publisher looks for a method named by
+  the HTTP method. So for an HTTP 'HEAD' request, the publisher would
+  call the 'HEAD' method on the published object.
+
+- Stringifying the published object -- If the published object isn't
+  callable, and doesn't have a default method, the publisher
+  publishes it using the Python 'str' function to turn it into a
+  string.
+
+
+After the response method has been determined and called, the
+publisher must interpret the results.
+
+Character Encodings for Responses
+=================================
+
+If the published method returns an object of type 'string', a plain
+8-bit character string, the publisher will use it directly as the
+body of the response.
+
+Things are different if the published method returns a unicode
+string, because the publisher has to apply some character
+encoding. The published method can choose which character encoding it
+uses by setting a 'Content-Type' response header which includes a
+'charset' property (setting response headers is explained later in
+this chapter). A common choice of character encoding is UTF-8. To
+cause the publisher to send unicode results as UTF-8 you need to set
+a 'Content-Type' header with the value 'text/html; charset=UTF-8'
+
+If the 'Content-Type' header does not include a charser property (or
+if this header has not been set by the published method) then the
+publisher will choose a default character encoding. Today this
+default is ISO-8859-1 (also known as Latin-1) for compatability with
+old versions of Zope which did not include Unicode support. At some
+time in the future this default is likely to change to UTF-8.
+
+HTTP Responses
+==============
+
+Normally the published method returns a string which is considered
+the body of the HTTP response. The response headers can be controlled
+by calling methods on the response object, which is described later
+in the chapter. Optionally, the published method can return a tuple
+with the title, and body of the response. In this case, the publisher
+returns an generated HTML page, with the first item of the tuple used
+for the HTML 'title' of the page, and the second item as the contents
+of the HTML 'body' tag. For example a response of::
+
+  ('response', 'the response')
+
+
+is turned into this HTML page::
+
+  <html>
+  <head><title>response</title></head>
+  <body>the response</body>
+  </html>
+
+Controlling Base HREF
+=====================
+
+When you publish an object that returns HTML relative links should
+allow you to navigate between methods. Consider this example::
+
+  class Example:
+      "example"
+
+      def one(self):
+          "method one"
+          return """<html>
+                    <head>
+                    <title>one</title>
+                    </head>
+                    <body>
+                    <a href="two">two</a> 
+                    </body>
+                    </html>"""
+
+      def two(self):
+          "method two"
+          return """<html>
+                    <head>
+                    <title>two</title>
+                    </head>
+                    <body>
+                    <a href="one">one</a> 
+                    </body>
+                    </html>"""
+
+
+However, the default method, 'index_html' presents a problem. Since
+you can access the 'index_html' method without specifying the method
+name in the URL, relative links returned by the 'index_html' method
+won't work right. For example::
+
+            class Example:
+                "example"
+
+                 def index_html(self):
+                    return """<html>
+                              <head>
+                              <title>one</title>
+                              </head>
+                              <body>
+                              <a href="one">one</a><br>
+                              <a href="two">two</a> 
+                              </body>
+                              </html>"""
+                 ...
+
+If you publish an instance of the 'Example' class with the URL
+'http://zope/example', then the relative link to method 'one' will be
+'http://zope/one', instead of the correct link,
+'http://zope/example/one'.
+
+
+Zope solves this problem for you by inserting a 'base' tag inside the
+'head' tag in the HTML output of 'index_html' method when it is
+accessed as the default method. You will probably never notice this,
+but if you see a mysterious 'base' tag in your HTML output, know you
+know where it came from. You can avoid this behavior by manually
+setting your own base with a 'base' tag in your 'index_html' method
+output.
+
+
+Response Headers
+----------------
+
+The publisher and the web server take care of setting response
+headers such as 'Content-Length' and 'Content-Type'. Later in
+the chapter you'll find out how to control these headers.
+Later you'll also find out how exceptions are used to set the
+HTTP response code.
+
+Pre-Traversal Hook
+------------------
+
+The pre-traversal hook allows your objects to take special action
+before they are traversed. This is useful for doing things like
+changing the request. Applications of this include special
+authentication controls, and virtual hosting support.
+
+If your object has a method named '__before_publishing_traverse__',
+the publisher will call it with the current object and the request,
+before traversing your object. Most often your method will change the
+request. The publisher ignores anything you return from the
+pre-traversal hook method.
+
+The 'ZPublisher.BeforeTraverse' module contains some functions that
+help you register pre-traversal callbacks. This allows you to perform
+fairly complex callbacks to multiple objects when a given object is
+about to be traversed.
+
+
+Traversal and Acquisition
+-------------------------
+
+Acquisition affects traversal in several ways. See Chapter 5,
+"Acquisition" for more information on acquisition. The most obvious
+way in which acquisition affects traversal is in locating the next
+object in a path. As we discussed earlier, the next object during
+traversal is often found using 'getattr'. Since acquisition affects
+'getattr', it will affect traversal. The upshot is that when you are
+traversing objects that support implicit acquisition, you can use
+traversal to walk over acquired objects. Consider the object
+hierarchy rooted in 'fruit'::
+
+        from Acquisition import Implicit
+
+        class Node(Implicit):
+            ...
+
+        fruit=Node()
+        fruit.apple=Node()
+        fruit.orange=Node()
+        fruit.apple.strawberry=Node()
+        fruit.orange.banana=Node()
+
+When publishing these objects, acquisition can come into play. For
+example, consider the URL */fruit/apple/orange*. The publisher would
+traverse from 'fruit', to 'apple', and then using acquisition, it
+would traverse to 'orange'.
+
+Mixing acquisition and traversal can get complex. Consider the URL
+*/fruit/apple/orange/strawberry/banana*. This URL is functional but
+confusing. Here's an even more perverse but legal URL
+*/fruit/apple/orange/orange/apple/apple/banana*.
+
+
+In general you should limit yourself to constructing URLs which use
+acquisition to acquire along containment, rather than context
+lines. It's reasonable to publish an object or method that you
+acquire from your container, but it's probably a bad idea to publish
+an object or method that your acquire from outside your
+container. For example::
+
+        from Acquisition import Implicit
+
+        class Basket(Implicit):
+            ...
+            def numberOfItems(self):
+                "Returns the number of contained items"
+                ...
+
+        class Vegetable(Implicit):
+            ...
+            def texture(self):
+                "Returns the texture of the vegetable."
+
+        class Fruit(Implicit):
+            ...
+            def color(self):
+                "Returns the color of the fruit."
+
+         basket=Basket()
+         basket.apple=Fruit()
+         basket.carrot=Vegetable()
+
+The URL */basket/apple/numberOfItems* uses acquisition along
+containment lines to publish the 'numberOfItems' method (assuming
+that 'apple' doesn't have a 'numberOfItems' attribute). However, the
+URL */basket/carrot/apple/texture* uses acquisition to locate the
+'texture' method from the 'apple' object's context, rather than from
+its container. While this distinction may be obscure, the guiding
+idea is to keep URLs as simple as possible. By keeping acquisition
+simple and along containment lines your application increases in
+clarity, and decreases in fragility.
+
+
+A second usage of acquisition in traversal concerns the request. The
+publisher tries to make the request available to the published object
+via acquisition. It does this by wrapping the first object in an
+acquisition wrapper that allows it to acquire the request with the
+name 'REQUEST'. This means that you can normally acquire the request
+in the published object like so::
+
+        request=self.REQUEST # for implicit acquirers
+
+or like so::
+
+        request=self.aq_acquire('REQUEST') # for explicit acquirers
+
+Of course, this will not work if your objects do not support
+acquisition, or if any traversed objects have an attribute named
+'REQUEST'.
+
+Finally, acquisition has a totally different role in object
+publishing related to security which we'll examine next.
+
+Traversal and Security
+----------------------
+
+As the publisher moves from object to object during traversal it
+makes security checks. The current user must be authorized to access
+each object along the traversal path. The publisher controls access
+in a number of ways. For more information about Zope security, see
+Chapter 6, "Security".
+
+Basic Publisher Security
+------------------------
+
+The publisher imposes a few basic restrictions on traversable
+objects. These restrictions are the same of those for publishable
+objects. As previously stated, publishable objects must have doc
+strings and must not have names beginning with underscore.
+
+The following details are not important if you are using the Zope
+framework. However, if your are publishing your own modules, the rest
+of this section will be helpful.
+
+The publisher checks authorization by examining the '__roles__'
+attribute of each object as it performs traversal. If present, the
+'__roles__' attribute should be 'None' or a list of role names. If it
+is None, the object is considered public. Otherwise the access to the
+object requires validation.
+
+Some objects such as functions and methods do not support creating
+attributes (at least they didn't before Python 2). Consequently, if
+the object has no '__roles__' attribute, the publisher will look for
+an attribute on the object's parent with the name of the object
+followed by '__roles__'. For example, a function named 'getInfo'
+would store its roles in its parent's 'getInfo__roles__' attribute.
+
+If an object has a '__roles__' attribute that is not empty and not
+'None', the publisher tries to find a user database to authenticate
+the user. It searches for user databases by looking for an
+'__allow_groups__' attribute, first in the published object, then in
+the previously traversed object, and so on until a user database is
+found.
+
+When a user database is found, the publisher attempts to validate the
+user against the user database. If validation fails, then the
+publisher will continue searching for user databases until the user
+can be validated or until no more user databases can be found.
+
+The user database may be an object that provides a validate
+method::
+
+  validate(request, http_authorization, roles)
+
+where 'request' is a mapping object that contains request
+information, 'http_authorization' is the value of the HTTP
+'Authorization' header or 'None' if no authorization header was
+provided, and 'roles' is a list of user role names.
+
+The validate method returns a user object if succeeds, and 'None' if
+it cannot validate the user. See Chapter 6 for more information on
+user objects. Normally, if the validate method returns 'None', the
+publisher will try to use other user databases, however, a user
+database can prevent this by raising an exception.
+
+
+If validation fails, Zope will return an HTTP header that causes your
+browser to display a user name and password dialog. You can control
+the realm name used for basic authentication by providing a module
+variable named '__bobo_realm__'. Most web browsers display the realm
+name in the user name and password dialog box.
+
+If validation succeeds the publisher assigns the user object to the
+request variable, 'AUTHENTICATED_USER'. The publisher places no
+restriction on user objects.
+
+
+Zope Security
+
+When using Zope rather than publishing your own modules, the
+publisher uses acquisition to locate user folders and perform
+security checks. The upshot of this is that your published objects
+must inherit from 'Acquisition.Implicit' or
+'Acquisition.Explicit'. See Chapter 5, "Acquisition", for more
+information about these classes. Also when traversing each object
+must be returned in an acquisition context. This is done
+automatically when traversing via 'getattr', but you must wrap
+traversed objects manually when using '__getitem__' and
+'__bobo_traverse__'. For example::
+
+          class Example(Acquisition.Explicit):
+              ...
+
+              def __bobo_traverse__(self, name, request):
+                  ...
+                  next_object=self._get_next_object(name)
+                  return  next_object.__of__(self)      
+
+
+Finally, traversal security can be circumvented with the
+'__allow_access_to_unprotected_subobjects__' attribute as described
+in Chapter 6, "Security".
+
+
+Environment Variables
+=====================
+
+You can control some facets of the publisher's operation by setting
+environment variables.
+
+- 'Z_DEBUG_MODE' -- Sets debug mode. In debug mode tracebacks are not
+  hidden in error pages. Also debug mode causes 'DTMLFile' objects,
+  External Methods and help topics to reload their contents from disk
+  when changed. You can also set debug mode with the '-D' switch when
+  starting Zope.
+
+- 'Z_REALM' -- Sets the basic authorization realm. This controls the
+  realm name as it appears in the web browser's username and password
+  dialog. You can also set the realm with the '__bobo_realm__' module
+  variable, as mentioned previously.
+
+- 'PROFILE_PUBLISHER' -- Turns on profiling and sets the name of the
+  profile file. See the Python documentation for more information
+  about the Python profiler.
+
+
+Many more options can be set using switches on the startup
+script. See the *Zope Administrator's Guide* for more information.
+
+Testing
+-------
+
+ZPublisher comes with built-in support for testing and working with
+the Python debugger.  This topic is covered in more detail in Chapter
+7, "Testing and Debugging".
+
+Publishable Module
+------------------
+
+If you are using the Zope framework, this section will be irrelevant
+to you. However, if you are publishing your own modules with
+'ZPublisher' read on.
+
+The publisher begins the traversal process by locating an object in
+the module's global namespace that corresponds to the first element
+of the path. Alternately the first object can be located by one of
+two hooks.
+
+If the module defines a 'web_objects' or 'bobo_application' object,
+the first object is searched for in those objects. The search happens
+according to the normal rules of traversal, using
+'__bobo_traverse__', 'getattr', and '__getitem__'.
+
+The module can receive callbacks before and after traversal. If the
+module defines a '__bobo_before__' object, it will be called with no
+arguments before traversal. Its return value is ignored. Likewise, if
+the module defines a '__bobo_after__' object, it will be called after
+traversal with no arguments. These callbacks can be used for things
+like acquiring and releasing locks.
+
+Calling the Published Object
+----------------------------
+
+Now that we've covered how the publisher located the published object
+and what it does with the results of calling it, let's take a closer
+look at how the published object is called.
+
+The publisher marshals arguments from the request and automatically
+makes them available to the published object. This allows you to
+accept parameters from web forms without having to parse the
+forms. Your objects usually don't have to do anything special to be
+called from the web. Consider this function::
+
+      def greet(name):
+          "greet someone"
+          return "Hello, %s" % name
+
+You can provide the 'name' argument to this function by calling it
+with a URL like *greet?name=World*. You can also call it with a HTTP
+'POST' request which includes 'name' as a form variable.
+
+In the next sections we'll take a closer look at how the publisher
+marshals arguments.
+
+Marshalling Arguments from the Request
+--------------------------------------
+
+The publisher marshals form data from GET and POST requests. Simple
+form fields are made available as Python strings. Multiple fields
+such as form check boxes and multiple selection lists become
+sequences of strings. File upload fields are represented with
+'FileUpload' objects. File upload objects behave like normal Python
+file objects and additionally have a 'filename' attribute which is
+the name of the file and a 'headers' attribute which is a dictionary
+of file upload headers.
+
+The publisher also marshals arguments from CGI environment variables
+and cookies. When locating arguments, the publisher first looks in
+CGI environment variables, then other request variables, then form
+data, and finally cookies. Once a variable is found, no further
+searching is done. So for example, if your published object expects
+to be called with a form variable named 'SERVER_URL', it will fail,
+since this argument will be marshaled from the CGI environment first,
+before the form data.
+
+The publisher provides a number of additional special variables such
+as 'URL0' which are derived from the request. These are covered in
+the 'HTTPRequest' API documentation.
+
+Argument Conversion
+-------------------
+
+The publisher supports argument conversion. For example consider this
+function::
+
+        def onethird(number):
+            "returns the number divided by three"
+            return number / 3.0
+
+This function cannot be called from the web because by default the
+publisher marshals arguments into strings, not numbers. This is why
+the publisher provides a number of converters. To signal an argument
+conversion you name your form variables with a colon followed by a
+type conversion code. For example, to call the above function with 66
+as the argument you can use this URL *onethird?number:int=66* The
+publisher supports many 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 a Python integer.
+
+- long -- Converts a variable to a Python long integer.
+
+- float -- Converts a variable to a Python floating point number.
+
+- string -- Converts a variable to a Python string.
+
+- ustring -- Converts a variable to a Python unicode string.
+
+- required -- Raises an exception if the variable is not present or
+  is an empty string.
+
+- ignore_empty -- Excludes a variable from the request if the
+  variable is an empty string.
+
+- date -- Converts a string to a *DateTime* object. The formats
+  accepted are fairly flexible, for example '10/16/2000', '12:01:13
+  pm'.
+
+- list -- Converts a variable to a Python list of values, even if
+  there is only one value.
+
+- tuple -- Converts a variable to a Python tuple of values, even if
+  there is only one value.
+
+- lines -- Converts a string to a Python list of values by splitting
+  the string on line breaks.
+
+- tokens -- Converts a string to a Python list of values by splitting
+  the string on spaces.
+
+- text -- Converts a variable to a string with normalized line
+  breaks.  Different browsers on various platforms encode line
+  endings differently, so this converter makes sure the line endings
+  are consistent, regardless of how they were encoded by the browser.
+
+- ulines, utokens, utext -- like lines, tokens, text, but using
+  unicode strings instead of plain strings.
+
+If the publisher cannot coerce a request variable into the type
+required by the type converter it will raise an error. This is useful
+for simple applications, but restricts your ability to tailor error
+messages. If you wish to provide your own error messages, you should
+convert arguments manually in your published objects rather than
+relying on the publisher for coercion. Another possibility is to use
+JavaScript to validate input on the client-side before it is
+submitted to the server.
+
+You can combine type converters to a limited extent. For example you
+could create a list of integers like so::
+
+        <input type="checkbox" name="numbers:list:int" value="1">
+        <input type="checkbox" name="numbers:list:int" value="2">
+        <input type="checkbox" name="numbers:list:int" value="3">
+
+In addition to these type converters, the publisher also supports
+method and record arguments.
+
+Character Encodings for Arguments
+---------------------------------
+
+The publisher needs to know what character encoding was used by the
+browser to encode form fields into the request. That depends on
+whether the form was submitted using GET or POST (which the publisher
+can work out for itself) and on the character encoding used by the
+page which contained the form (for which the publisher needs your
+help).
+
+In some cases you need to add a specification of the character
+encoding to each fields type converter. The full details of how this
+works are explained below, however most users do not need to deal
+with the full details:
+
+1. If your pages all use the UTF-8 character encoding (or at least
+   all the pages that contain forms) the browsers will always use
+   UTF-8 for arguments. You need to add ':utf8' into all argument
+   type converts. For example:
+
+   <input type="text" name="name:utf8:ustring">
+   <input type="checkbox" name="numbers:list:int:utf8" value="1">
+   <input type="checkbox" name="numbers:list:int:utf8" value="1">
+
+     % Anonymous User - Apr. 6, 2004 5:56 pm:
+      121
+
+2. If your pages all use a character encoding which has ASCII as a
+   subset (such as Latin-1, UTF-8, etc) then you do not need to
+   specify any chatacter encoding for boolean, int, long, float, and
+   date types.  You can also omit the character encoding type
+   converter from string, tokens, lines, and text types if you only
+   need to handle ASCII characters in that form field.
+
+Character Encodings for Arguments; The Full Story
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you are not in one of those two easy categories, you first need to
+determine which character encoding will be used by the browser to
+encode the arguments in submitted forms.
+
+1. Forms submitted using GET, or using POST with 
+   "application/x-www-form-urlencoded" (the default) 
+
+   1. Page uses an encoding of unicode: Forms are submitted using
+      UTF8, as required by RFC 2718 2.2.5
+
+   2. Page uses another regional 8 bit encoding: Forms are often
+      submitted using the same encoding as the page. If you choose to
+      use such an encoding then you should also verify how browsers
+      behave.
+
+2. Forms submitted using "multipart/form-data":
+
+   According to HTML 4.01 (section 17.13.4) browsers should state
+   which character encoding they are using for each field in a
+   Content-Type header, however this is poorly supported. The current
+   crop of browsers appear to use the same encoding as the page
+   containing the form.
+
+   Every field needs that character encoding name appended to is
+   converter.  The tag parser insists that tags must only use
+   alphanumberic characters or an underscore, so you might need to
+   use a short form of the encoding name from the Python 'encodings'
+   library package (such as utf8 rather than UTF-8).
+
+
+Method Arguments
+----------------
+
+Sometimes you may wish to control which object is published based on
+form data. For example, you might want to have a form with a select
+list that calls different methods depending on the item
+chosen. Similarly, you might want to have multiple submit buttons
+which invoke a different method for each button.
+
+The publisher provides a way to select methods using form variables
+through use of the *method* argument type. The method type allows the
+request 'PATH_INFO' to be augmented using information from a form
+item name or value.
+
+If the name of a form field is ':method', then the value of the field
+is added to 'PATH_INFO'. For example, if the original 'PATH_INFO' is
+'foo/bar' and the value of a ':method' field is 'x/y', then
+'PATH_INFO' is transformed to 'foo/bar/x/y'. This is useful when
+presenting a select list. Method names can be placed in the select
+option values.
+
+If the name of a form field ends in ':method' then the part of the
+name before ':method' is added to 'PATH_INFO'. For example, if the
+original 'PATH_INFO' is 'foo/bar' and there is a 'x/y:method' field,
+then 'PATH_INFO' is transformed to 'foo/bar/x/y'. In this case, the
+form value is ignored. This is useful for mapping submit buttons to
+methods, since submit button values are displayed and should,
+therefore, not contain method names.
+
+Only one method field should be provided. If more than one method
+field is included in the request, the behavior is undefined.
+
+Record Arguments 
+----------------
+
+Sometimes you may wish to consolidate form data into a structure
+rather than pass arguments individually. Record arguments allow you
+to do this.
+
+The 'record' type converter allows you to combine multiple
+form variables into a single input variable. For example::
+
+  <input name="date.year:record:int">
+  <input name="date.month:record:int">
+  <input name="date.day:record:int">
+
+This form will result in a single variable, 'date', with
+attributes 'year', 'month', and 'day'.
+
+You can skip empty record elements with the 'ignore_empty'
+converter. For example::
+
+  <input type="text" name="person.email:record:ignore_empty">
+
+When the email form field is left blank the publisher skips over the
+variable rather than returning a null string as its value. When the
+record 'person' is returned it will not have an 'email' attribute if
+the user did not enter one.
+
+You can also provide default values for record elements with the
+'default' converter. For example::
+
+  <input type="hidden"
+         name="pizza.toppings:record:list:default" 
+         value="All">
+  <select multiple name="pizza.toppings:record:list:ignore_empty">
+  <option>Cheese</option>
+  <option>Onions</option>
+  <option>Anchovies</option>
+  <option>Olives</option>
+  <option>Garlic<option>
+  </select>
+
+The 'default' type allows a specified value to be inserted when the
+form field is left blank. In the above example, if the user does not
+select values from the list of toppings, the default value will be
+used. The record 'pizza' will have the attribute 'toppings' and its
+value will be the list containing the word "All" (if the field is
+empty) or a list containing the selected toppings.
+
+You can even marshal large amounts of form data into multiple records
+with the 'records' type converter. Here's an example::
+
+  <h2>Member One</h2>
+  Name:
+  <input type="text" name="members.name:records"><BR>
+  Email:
+  <input type="text" name="members.email:records"><BR>
+  Age:
+  <input type="text" name="members.age:int:records"><BR>
+
+  <H2>Member Two</H2>
+  Name:
+  <input type="text" name="members.name:records"><BR>
+  Email:
+  <input type="text" name="members.email:records"><BR>
+  Age:
+  <input type="text" name="members.age:int:records"><BR>
+
+This form data will be marshaled into a list of records named
+'members'. Each record will have a 'name', 'email', and 'age'
+attribute.
+
+Record marshalling provides you with the ability to create complex
+forms. However, it is a good idea to keep your web interfaces as
+simple as possible.
+
+Exceptions
+----------
+
+Unhandled exceptions are caught by the object publisher and are
+translated automatically to nicely formatted HTTP output.
+
+When an exception is raised, the exception type is mapped to an HTTP
+code by matching the value of the exception type with a list of
+standard HTTP status names. Any exception types that do not match
+standard HTTP status names are mapped to "Internal Error" (500). The
+standard HTTP status names are: "OK", "Created", "Accepted", "No
+Content", "Multiple Choices", "Redirect", "Moved Permanently", "Moved
+Temporarily", "Not Modified", "Bad Request", "Unauthorized",
+"Forbidden", "Not Found", "Internal Error", "Not Implemented", "Bad
+Gateway", and "Service Unavailable". Variations on these names with
+different cases and without spaces are also valid.
+
+An attempt is made to use the exception value as the body of the
+returned response. The object publisher will examine the exception
+value. If the value is a string that contains some white space, then
+it will be used as the body of the return error message. If it
+appears to be HTML, the error content type will be set to
+'text/html', otherwise, it will be set to 'text/plain'. If the
+exception value is not a string containing white space, then the
+object publisher will generate its own error message.
+
+There are two exceptions to the above rule:
+
+1. If the exception type is: "Redirect", "Multiple Choices" "Moved
+   Permanently", "Moved Temporarily", or "Not Modified", and the
+   exception value is an absolute URI, then no body will be provided
+   and a 'Location' header will be included in the output with the
+   given URI.
+
+2. If the exception type is "No Content", then no body will be
+   returned.
+
+When a body is returned, traceback information will be included in a
+comment in the output. As mentioned earlier, the environment variable
+'Z_DEBUG_MODE' can be used to control how tracebacks are included. If
+this variable is set then tracebacks are included in 'PRE' tags,
+rather than in comments. This is very handy during debugging.
+
+Exceptions and Transactions
+---------------------------
+
+When Zope receives a request it begins a transaction. Then it begins
+the process of traversal. Zope automatically commits the transaction
+after the published object is found and called. So normally each web
+request constitutes one transaction which Zope takes care of for
+you. See Chapter 4. for more information on transactions.
+
+If an unhandled exception is raised during the publishing process,
+Zope aborts the transaction. As detailed in Chapter
+4. Zope handles 'ConflictErrors' by re-trying the request up to
+three times.  This is done with the 'zpublisher_exception_hook'.
+
+In addition, the error hook is used to return an error message to the
+user. In Zope the error hook creates error messages by calling the
+'raise_standardErrorMessage' method. This method is implemented by
+'SimpleItem.Item'. It acquires the 'standard_error_message' DTML
+object, and calls it with information about the exception.
+
+You will almost never need to override the
+'raise_standardErrorMessage' method in your own classes, since it is
+only needed to handle errors that are raised by other components. For
+most errors, you can simply catch the exceptions normally in your
+code and log error messages as needed. If you need to, you should be
+able to customize application error reporting by overriding the
+'standard_error_message' DTML object in your application.
+
+Manual Access to Request and Response
+-------------------------------------
+
+You do not need to access the request and response directly most of
+the time. In fact, it is a major design goal of the publisher that
+most of the time your objects need not even be aware that they are
+being published on the web. However, you have the ability to exert
+more precise control over reading the request and returning the
+response.
+
+Normally published objects access the request and response by listing
+them in the signature of the published method. If this is not
+possible you can usually use acquisition to get a reference to the
+request. Once you have the request, you can always get the response
+from the request like so::
+
+  response=REQUEST.RESPONSE
+
+The APIs of the request and response are covered in the API
+documentation. Here we'll look at a few common uses of the request
+and response.
+
+One reason to access the request is to get more precise information
+about form data. As we mentioned earlier, argument marshalling comes
+from a number of places including cookies, form data, and the CGI
+environment. For example, you can use the request to differentiate
+between form and cookie data::
+
+  cookies = REQUEST.cookies # a dictionary of cookie data
+  form = REQUEST.form # a dictionary of form data
+
+One common use of the response object is to set response headers.
+Normally the publisher in concert with the web server will take care
+of response headers for you. However, sometimes you may wish manually
+control headers::
+
+  RESPONSE.setHeader('Pragma', 'No-Cache')
+
+Another reason to access the response is to stream response data. You
+can do this with the 'write' method::
+
+  while 1:
+      data=getMoreData() #this call may block for a while
+      if not data:
+          break
+      RESPONSE.write(data)
+
+Here's a final example that shows how to detect if your method is
+being called from the web. Consider this function::
+
+  def feedParrot(parrot_id, REQUEST=None):
+      ...
+
+      if REQUEST is not None:
+          return "<html><p>Parrot %s fed</p></html>" % parrot_id
+
+The 'feedParrot' function can be called from Python, and also from
+the web. By including 'REQUEST=None' in the signature you can
+differentiate between being called from Python and being called form
+the web. When the function is called from Python nothing is returned,
+but when it is called from the web the function returns an HTML
+confirmation message.
+
+Other Network Protocols
+=======================
+
+FTP
+---
+
+Zope comes with an FTP server which allows users to treat the Zope
+object hierarchy like a file server. As covered in Chapter 3, Zope
+comes with base classes ('SimpleItem' and 'ObjectManager') which
+provide simple FTP support for all Zope objects. The FTP API is
+covered in the API reference.
+
+To support FTP in your objects you'll need to find a way to represent
+your object's state as a file. This is not possible or reasonable for
+all types of objects. You should also consider what users will do
+with your objects once they access them via FTP.  You should find out
+which tools users are likely to edit your object files.  For example,
+XML may provide a good way to represent your object's state, but it
+may not be easily editable by your users.  Here's an example class
+that represents itself as a file using RFC 822 format::
+
+  from rfc822 import Message
+  from cStringIO import StringIO
+
+  class Person(...):
+
+      def __init__(self, name, email, age):
+          self.name=name
+          self.email=email
+          self.age=age
+
+      def writeState(self):
+          "Returns object state as a string"
+          return "Name: %s\nEmail: %s\nAge: %s" % (self.name,
+                                                   self.email, 
+                                                   self.age)
+      def readState(self, data):
+          "Sets object state given a string"
+          m=Message(StringIO(data))
+          self.name=m['name']
+          self.email=m['email']
+          self.age=int(m['age'])
+
+The 'writeState' and 'readState' methods serialize and unserialize
+the 'name', 'age', and 'email' attributes to and from a string. There
+are more efficient ways besides RFC 822 to store instance attributes
+in a file, however RFC 822 is a simple format for users to edit with
+text editors.
+
+To support FTP all you need to do at this point is implement the
+'manage_FTPget' and 'PUT' methods. For example::
+
+  def manage_FTPget(self):
+      "Returns state for FTP"
+      return self.writeState()
+
+  def PUT(self, REQUEST):
+      "Sets state from FTP"
+       self.readState(REQUEST['BODY'])
+
+You may also choose to implement a 'get_size' method which returns
+the size of the string returned by 'manage_FTPget'. This is only
+necessary if calling 'manage_FTPget' is expensive, and there is a
+more efficient way to get the size of the file. In the case of this
+example, there is no reason to implement a 'get_size' method.
+
+One side effect of implementing 'PUT' is that your object now
+supports HTTP PUT publishing. See the next section on WebDAV for more
+information on HTTP PUT.
+
+That's all there is to making your object work with FTP. As you'll
+see next WebDAV support is similar.
+
+WebDAV
+------
+
+WebDAV is a protocol for collaboratively edit and manage files on
+remote servers. It provides much the same functionality as FTP, but
+it works over HTTP.
+
+It is not difficult to implement WebDAV support for your
+objects. Like FTP, the most difficult part is to figure out how to
+represent your objects as files.
+
+Your class must inherit from 'webdav.Resource' to get basic DAV
+support. However, since 'SimpleItem' inherits from 'Resource', your
+class probably already inherits from 'Resource'. For container
+classes you must inherit from 'webdav.Collection'. However, since
+'ObjectManager' inherits from 'Collection' you are already set so
+long as you inherit from 'ObjectManager'.
+
+In addition to inheriting from basic DAV classes, your classes must
+implement 'PUT' and 'manage_FTPget'. These two methods are also
+required for FTP support. So by implementing WebDAV support, you also
+implement FTP support.
+
+The permissions that you assign to these two methods will control the
+ability to read and write to your class through WebDAV, but the
+ability to see your objects is controlled through the "WebDAV access"
+permission.
+
+Supporting Write Locking
+------------------------
+
+Write locking is a feature of WebDAV that allows users to put lock on
+objects they are working on. Support write locking s easy. To
+implement write locking you must assert that your lass implements the
+'WriteLockInterface'. For example::
+
+  from webdav.WriteLockInterface import WriteLockInterface
+
+  class MyContentClass(OFS.SimpleItem.Item, Persistent):
+      __implements__ = (WriteLockInterface,)
+
+It's sufficient to inherit from 'SimpleItem.Item', since it inherits
+from 'webdav.Resource', which provides write locking long with other
+DAV support.
+
+In addition, your 'PUT' method should begin with calls to dav__init'
+and 'dav_simpleifhandler'. For example::
+
+ def PUT(self, REQUEST, RESPONSE):
+     """
+     Implement WebDAV/HTTP PUT/FTP put method for this object.
+     """
+     self.dav__init(REQUEST, RESPONSE)
+     self.dav__simpleifhandler(REQUEST, RESPONSE)
+     ...
+
+Finally your class's edit methods should check to determine whether
+your object is locked using the 'ws_isLocked' method. If someone
+attempts to change your object when it is locked you should raise the
+'ResourceLockedError'. For example::
+
+  from webdav import ResourceLockedError
+
+  class MyContentClass(...):
+      ...
+
+      def edit(self, ...):
+          if self.ws_isLocked():
+              raise ResourceLockedError
+          ...
+
+WebDAV support is not difficult to implement, and as more WebDAV
+editors become available, it will become more valuable. If you choose
+to add FTP support to your class you should probably go ahead and
+support WebDAV too since it is so easy once you've added FTP support.
+
+XML-RPC
+-------
+
+`XML-RPC <http://www.xmlrpc.com>`_ is a light-weight Remote Procedure
+Call protocol that uses XML for encoding and HTTP for
+transport. Fredrick Lund maintains a Python <XML-RPC module
+<http://www.pythonware.com/products/xmlrpc>`_ .
+
+All objects in Zope support XML-RPC publishing. Generally you will
+select a published object as the end-point and select one of its
+methods as the method. For example you can call the 'getId' method on
+a Zope folder at 'http://example.com/myfolder' like so::
+
+  import xmlrpclib
+  folder = xmlrpclib.Server('http://example.com/myfolder')
+  ids = folder.getId()
+
+You can also do traversal via a dotted method name. For example::
+
+  import xmlrpclib
+
+  # traversal via dotted method name
+  app = xmlrpclib.Server('http://example.com/app')
+  id1 = app.folderA.folderB.getId()
+
+  # walking directly up to the published object
+  folderB = xmlrpclib.Server('http://example.com/app/folderA/folderB')
+  id2 = folderB.getId()
+
+  print id1 == id2
+
+This example shows different routes to the same object publishing
+call.
+
+XML-RPC supports marshalling of basic Python types for both
+publishing requests and responses. The upshot of this arrangement is
+that when you are designing methods for use via XML-RPC you should
+limit your arguments and return values to simple values such as
+Python strings, lists, numbers and dictionaries. You should not
+accept or return Zope objects from methods that will be called via
+XML-RPC.
+
+
+XML-RPC does not support keyword arguments. This is a problem if your
+method expect keyword arguments.  This problem is noticeable when
+calling DTMLMethods and DTMLDocuments with XML-RPC.  Normally a DTML
+object should be called with the request as the first argument, and
+additional variables as keyword arguments.  You can get around this
+problem by passing a dictionary as the first argument. This will
+allow your DTML methods and documents to reference your variables
+with the 'var' tag.  However, you cannot do the following::
+
+  <dtml-var expr="REQUEST['argument']">
+
+Although the following will work::
+
+  <dtml-var expr="_['argument']">
+
+This is because in this case arguments *are* in the DTML namespace,
+but they are not coming from the web request.
+
+In general it is not a good idea to call DTML from XML-RPC since DTML
+usually expects to be called from normal HTTP requests.
+
+One thing to be aware of is that Zope returns 'false' for published
+objects which return None since XML-RPC has no concept of null.
+
+Another issue you may run into is that 'xmlrpclib' does not yet
+support HTTP basic authentication. This makes it difficult to call
+protected web resources. One solution is to patch
+'xmlrpclib'. Another solution is to accept authentication credentials
+in the signature of your published method.
+
+Summary
+=======
+
+Object publishing is a simple and powerful way to bring objects to
+the web. Two of Zope's most appealing qualities is how it maps
+objects to URLs, and you don't need to concern yourself with web
+plumbing. If you wish, there are quite a few details that you can use
+to customize how your objects are located and published.
+

Copied: zope2docs/trunk/zdgbook/Outline.txt (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/Outline.txt)
===================================================================
--- zope2docs/trunk/zdgbook/Outline.txt	                        (rev 0)
+++ zope2docs/trunk/zdgbook/Outline.txt	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,159 @@
+#######
+Outline
+#######
+
+Covers audience, topic, and scope.  Gives brief description of the
+developers guide and what goals the guide tries to acomplish.  Gives
+simple chapter by chapter overview of entire guide.
+
+
+Interfaces
+==========
+
+Zope is moving toward a more "self-documenting" model, where Zope
+component describe themselves with interfaces.  Many of the prose
+descriptions and examples in this guide will be working with these
+kinds of components.  This chapter gives a brief overview of Zope
+interfaces, how they describe Zope components, and how developers can
+create their own interfaces.
+
+This section is meant to enable the reader to discover the Zope "API"
+for themselves.  One of the goals of this guide is *not* to be an
+exhaustive descrption of the Zope API, that can be found in the
+online help system and from Zope objects through their interfaces.
+
+The majority of the content of this chapter will come from the
+`Interface documentation
+<http://www.zope.org/Wikis/Interfaces/InterfaceUserDocumentation>`_
+
+1. What are interfaces, why are they useful?
+
+2. Reading interfaces
+
+3. Using and testing interfaces
+
+4. Defining interfaces
+
+
+Publishing
+==========
+
+One key facility that Zope provides for a component developer is
+access to a component through various network protocols, like HTTP.
+While a component can be designed to work exclusivly with other
+components through Python only interfaces, most components are
+designed to be used and managed through a network interface, most
+commonly HTTP.
+
+Zope provides network access to components by "publishing" them
+through various network interfaces like HTTP, FTP, WebDAV and
+XML-RPC.  This chapter describes how a component developer can
+publish their components "through the web" and other network
+protocols.
+
+1. Object publishing overview
+
+2. Traversal
+
+3. Network Protocols
+
+4. Publishable Interfaces
+
+5. Object marshalling
+
+6. Creating user interfaces
+
+   - with DTMLFile
+
+   - with presentation templates
+
+
+Products
+========
+
+Zope defines a system that allows component developers to distribute
+their components to other Zope users.  Components can be placed into
+a package called a "Product".  Products can be created either through
+the web, or in Python.  Through the web products are covered in *The
+Zope Book*, and this chapter describes the more advanced Python
+product interfaces that developers can use to distribute their
+Python-based components.
+
+The majority of the content of this chapter will come from
+Amos/Shane's `Product Tutorial
+<http://www.zope.org/Members/hathawsh/PythonProductTutorial>`_
+
+1. Introduction
+
+2. Development Process
+
+3. Product Architecture
+
+4. Building Product Classes
+
+5. Building Management Interfaces
+
+6. Packaging Products
+
+7. Evolving Products
+
+
+Persistence
+===========
+
+Most Zope components live in the Zope Object DataBase (ZODB).
+Components that are stored in ZODB are called *persistent*.  Creating
+persistent components is, for the most part, a trivial exercise, but
+ZODB does impose a few rules that persistent components must obey in
+oder to work properly.  This chapter describes the persistent model
+and the interfaces that persistent objects can use to live inside the
+ZODB.
+
+1. Persistence Architecture
+
+2. Using Persistent components
+
+3. Creating Persistent Objects
+
+4. Transactions
+
+
+Security
+========
+
+Zope has a very fine-grained, uniquely powerful security model.  This
+model allows Zope developers to create components that work safely in
+an environment used by many different users, all with varying levels
+of security privledge.
+
+This section describes Zope's security model and how component
+developers can work with it and manipulate it to define security
+policies specific to their needs or the needs of their components.
+
+The majority of the content of this chapter will come from Chris'
+first cut at `Security documentation
+<http://www.zope.org/Members/mcdonc/PDG/6-1-Security.stx>`_
+
+1. Security architecture
+
+2. Using protected components
+
+3. Implementing Security in your Component
+
+4. Security Policies
+
+
+Debugging and Testing
+=====================
+
+Covers debugging Zope and unit testing.
+
+- pdb debugging
+
+- Control Panel debug view
+
+- -D z2.py switch
+
+- unit testing
+
+  - zope fixtures for unit testing

Copied: zope2docs/trunk/zdgbook/Products.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/Products.rst)
===================================================================
--- zope2docs/trunk/zdgbook/Products.rst	                        (rev 0)
+++ zope2docs/trunk/zdgbook/Products.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,1322 @@
+#############
+Zope Products
+#############
+
+Introduction
+============
+
+Zope *products* extend Zope with new functionality.  Products most
+often provide new addable objects.  In this chapter, we are going to
+look at building products on the file system.  Filesystem products
+require more overhead to build, but offer more power and flexibility,
+and they can be developed with familiar tools such as text editors
+and version controlling systems.
+
+Soon we will make the examples referenced in this chapter available
+for download as an example product.  Until that time, you will see
+references to files in this chapter that are not available yet.  This
+will be made available soon.
+
+Development Process
+===================
+
+This chapter begins with a discussion of how you will develop
+products.  We'll focus on common engineering tasks that you'll
+encounter as you develop products.
+
+Consider Alternatives
+---------------------
+
+Before you jump into the development of a product you should consider
+the alternatives.  Would your problem be better solved with External
+Methods, or Python Scripts? Products excel at extending Zope with new
+addable classes of objects.  If this does not figure centrally in
+your solution, you should look elsewhere.  Products, like External
+Methods allow you to write unrestricted Python code on the
+filesystem.
+
+Starting with Interfaces
+------------------------
+
+The first step in creating a product is to create one or more
+interfaces which describe the product.  See Chapter 2 for more
+information on interfaces and how to create them.
+
+Creating interfaces before you build an implementation is a good idea
+since it helps you see your design and assess how well it fulfills
+your requirements.
+
+Consider this interface for a multiple choice poll component (see
+`Poll.py <examples/Poll.py>`_)::
+
+  from zope.interface import Interface
+
+  class IPoll(Interface):
+      """A multiple choice poll"""
+
+      def castVote(index):
+          """Votes for a choice"""
+
+      def getTotalVotes():
+          """Returns total number of votes cast"""
+
+      def getVotesFor(index):
+          """Returns number of votes cast for a given response"""
+
+      def getResponses():
+          """Returns the sequence of responses"""
+
+      def getQuestion():
+          """Returns the question"""
+
+How you name your interfaces is entirely up to you.  Here we've
+decided to use prefix "I" in the name of the interface.
+
+Implementing Interfaces
+-----------------------
+
+After you have defined an interface for your product, the next step
+is to create a prototype in Python that implements your interface.
+
+Here is a prototype of a ``PollImplemtation`` class that implements the
+interface you just examined (see `PollImplementation.py
+<examples/PollImplementation.py>`_)::
+
+  from poll import Poll
+
+  class PollImplementation:
+      """A multiple choice poll, implements the Poll interface.
+
+      The poll has a question and a sequence of responses. Votes
+      are stored in a dictionary which maps response indexes to a
+      number of votes.
+      """
+
+      implements(IPoll)
+
+      def __init__(self, question, responses):
+          self._question = question
+          self._responses = responses
+          self._votes = {}
+          for i in range(len(responses)):
+              self._votes[i] = 0
+
+      def castVote(self, index):
+          """Votes for a choice"""
+          self._votes[index] = self._votes[index] + 1
+
+      def getTotalVotes(self):
+          """Returns total number of votes cast"""
+          total = 0
+          for v in self._votes.values():
+              total = total + v
+          return total
+
+      def getVotesFor(self, index):
+          """Returns number of votes cast for a given response"""
+          return self._votes[index]
+
+      def getResponses(self):
+          """Returns the sequence of responses"""
+          return tuple(self._responses)
+
+      def getQuestion(self):
+          """Returns the question"""
+          return self._question
+
+You can use this class interactively and test it.  Here's an example
+of interactive testing::
+
+  >>> from PollImplementation import PollImplementation
+  >>> p = PollImplementation("What's your favorite color?",
+  ...                        ["Red", "Green", "Blue", "I forget"])
+  >>> p.getQuestion()
+  "What's your favorite color?"
+  >>> p.getResponses()
+  ('Red', 'Green', 'Blue', 'I forget')
+  >>> p.getVotesFor(0)
+  0
+  >>> p.castVote(0)
+  >>> p.getVotesFor(0)
+  1
+  >>> p.castVote(2)
+  >>> p.getTotalVotes()
+  2
+  >>> p.castVote(4)
+  Traceback (innermost last):
+  File "<stdin>", line 1, in ?
+  File "PollImplementation.py", line 23, in castVote
+  self._votes[index] = self._votes[index] + 1
+  KeyError: 4
+
+Interactive testing is one of Python's great features.  It lets you
+experiment with your code in a simple but powerful way.
+
+At this point you can do a fair amount of work, testing and refining
+your interfaces and classes which implement them.  See Chapter 9 for
+more information on testing.
+
+So far you have learned how to create Python classes that are
+documented with interfaces, and verified with testing.  Next you'll
+examine the Zope product architecture.  Then you'll learn how to fit
+your well crafted Python classes into the product framework.
+
+Building Product Classes
+------------------------
+
+To turn a component into a product you must fulfill many contracts.
+For the most part these contracts are not yet defined in terms of
+interfaces.  Instead you must subclass from base classes that
+implement the contracts.  This makes building products confusing, and
+this is an area that we are actively working on improving.
+
+Base Classes
+------------
+
+Consider an example product class definition::
+
+  from Acquisition import Implicit
+  from Globals import Persistent
+  from AccessControl.Role import RoleManager
+  from OFS.SimpleItem import Item
+
+  class PollProduct(Implicit, Persistent, RoleManager, Item):
+      """
+      Poll product class
+      """
+      ...
+
+The order of the base classes depends on which classes you want to
+take precedence over others.  Most Zope classes do not define similar
+names, so you usually don't need to worry about what order these
+classes are used in your product.  Let's take a look at each of these
+base classes.
+
+
+Acquisition.Implicit
+~~~~~~~~~~~~~~~~~~~~
+
+This is the normal acquisition base class.  See the *API Reference*
+for the full details on this class.  Many Zope services such as
+object publishing and security use acquisition, so inheriting from
+this class is required for products.  Actually, you can choose to
+inherit from ``Acquisition.Explicit`` if you prefer, however, it will
+prevent folks from dynamically binding Python Scripts and DTML
+Methods to instances of your class.  In general you should subclass
+from ``Acquisition.Implicit`` unless you have a good reason not to.
+
+  XXX: is this true?  I thought that any ExtensionClass.Base can be
+  acquired.  The Implicit and Explicit just control how the class can
+  acquire, not how it *is* acquired.
+
+Globals.Persistent
+~~~~~~~~~~~~~~~~~~
+
+This base class makes instances of your product persistent.  For more
+information on persistence and this class see Chapter 4.
+
+In order to make your poll class persistent you'll need to make one
+change.  Since ``_votes`` is a dictionary this means that it's a
+mutable non-persistent sub-object.  You'll need to let the
+persistence machinery know when you change it::
+
+  def castVote(self, index):
+      """Votes for a choice"""
+      self._votes[index] = self._votes[index] + 1
+      self._p_changed = 1
+
+The last line of this method sets the ``_p_changed`` attribute to 1.
+This tells the persistence machinery that this object has changed and
+should be marked as ``dirty``, meaning that its new state should be
+written to the database at the conclusion of the current transaction.
+A more detailed explanation is given in the Persistence chapter of
+this guide.
+
+
+OFS.SimpleItem.Item
+~~~~~~~~~~~~~~~~~~~
+
+This base class provides your product with the basics needed to work
+with the Zope management interface.  By inheriting from ``Item`` your
+product class gains a whole host of features: the ability to be cut
+and pasted, capability with management views, WebDAV support, basic
+FTP support, undo support, ownership support, and traversal controls.
+It also gives you some standard methods for management views and
+error display including ``manage_main()``.  You also get the
+``getId()``, ``title_or_id()``, ``title_and_id()`` methods and the
+``this()`` DTML utility method.  Finally this class gives your
+product basic *dtml-tree* tag support.  ``Item`` is really an
+everything-but-the-kitchen-sink kind of base class.
+
+``Item`` requires that your class and instances have some management
+interface related attributes.
+
+- ``meta_type`` -- This attribute should be a short string which is
+  the name of your product class as it appears in the product add
+  list.  For example, the poll product class could have a
+  ``meta_type`` with value as ``Poll``.
+
+- ``id`` or ``__name__`` -- All ``Item`` instances must have an
+  ``id`` string attribute which uniquely identifies the instance
+  within it's container.  As an alternative you may use ``__name__``
+  instead of ``id``.
+
+- ``title`` -- All ``Item`` instances must have a ``title`` string
+  attribute.  A title may be an empty string if your instance does
+  not have a title.
+
+In order to make your poll class work correctly as an ``Item`` you'll
+need to make a few changes.  You must add a ``meta_type`` class
+attribute, and you may wish to add an ``id`` parameter to the
+constructor::
+
+  class PollProduct(..., Item):
+
+      meta_type = 'Poll'
+      ...
+
+      def __init__(self, id, question, responses):
+          self.id = id
+          self._question = question
+          self._responses = responses
+          self._votes = {}
+          for i in range(len(responses)):
+              self._votes[i] = 0
+
+
+Finally, you should probably place ``Item`` last in your list of base
+classes.  The reason for this is that ``Item`` provides defaults that
+other classes such as ``ObjectManager`` and ``PropertyManager``
+override.  By placing other base classes before ``Item`` you allow
+them to override methods in ``Item``.
+
+AccessControl.Role.RoleManager
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This class provides your product with the ability to have its
+security policies controlled through the web.  See Chapter 6 for more
+information on security policies and this class.
+
+OFS.ObjectManager
+~~~~~~~~~~~~~~~~~
+
+This base class gives your product the ability to contain other
+``Item`` instances.  In other words, it makes your product class like
+a Zope folder.  This base class is optional. See the *API Reference*
+for more details.  This base class gives you facilities for adding
+Zope objects, importing and exporting Zope objects, WebDAV, and FTP.
+It also gives you the ``objectIds``, ``objectValues``, and
+``objectItems`` methods.
+
+``ObjectManager`` makes few requirements on classes that subclass it.
+You can choose to override some of its methods but there is little
+that you must do.
+
+If you wish to control which types of objects can be contained by
+instances of your product you can set the ``meta_types`` class
+attribute.  This attribute should be a tuple of meta_types.  This
+keeps other types of objects from being created in or pasted into
+instances of your product.  The ``meta_types`` attribute is mostly
+useful when you are creating specialized container products.
+
+OFS.PropertyManager
+~~~~~~~~~~~~~~~~~~~
+
+This base class provides your product with the ability to have
+user-managed instance attributes.  See the *API Reference* for more
+details.  This base class is optional.
+
+Your class may specify that it has one or more predefined properties,
+by specifying a '_properties' class attribute.  For example::
+
+  _properties=({'id':'title', 'type': 'string', 'mode': 'w'},
+               {'id':'color', 'type': 'string', 'mode': 'w'},
+              )
+
+The ``_properties`` structure is a sequence of dictionaries, where
+each dictionary represents a predefined property.  Note that if a
+predefined property is defined in the ``_properties`` structure, you
+must provide an attribute with that name in your class or instance
+that contains the default value of the predefined property.
+
+Each entry in the ``_properties`` structure must have at least an
+``id`` and a ``type`` key.  The ``id`` key contains the name of the
+property, and the ``type`` key contains a string representing the
+object's type.  The ``type`` string must be one of the values:
+``float``, ``int``, ``long``, ``string``, ``lines``, ``text``,
+``date``, ``tokens``, ``selection``, or ``multiple section``.  For
+more information on Zope properties see the *Zope Book*.
+
+For ``selection`` and ``multiple selection`` properties, you must
+include an addition item in the property dictionary,
+``select_variable`` which provides the name of a property or method
+which returns a list of strings from which the selection(s) can be
+chosen.  For example::
+
+  _properties=({'id' : 'favorite_color',
+                'type' : 'selection',
+                'select_variable' : 'getColors'
+               },
+              )
+
+Each entry in the ``_properties`` structure may optionally provide a
+``mode`` key, which specifies the mutability of the property. The
+``mode`` string, if present, must be ``w``, ``d``, or ``wd``.
+
+A ``w`` present in the mode string indicates that the value of the
+property may be changed by the user.  A ``d`` indicates that the user
+can delete the property.  An empty mode string indicates that the
+property and its value may be shown in property listings, but that it
+is read-only and may not be deleted.
+
+Entries in the ``_properties`` structure which do not have a ``mode``
+item are assumed to have the mode ``wd`` (writable and deleteable).
+
+Security Declarations
+---------------------
+
+In addition to inheriting from a number of standard base classes, you
+must declare security information in order to turn your component
+into a product.  See Chapter 6 for more information on security and
+instructions for declaring security on your components.
+
+Here's an example of how to declare security on the poll class::
+
+  from AccessControl import ClassSecurityInfo
+
+  class PollProduct(...):
+      ...
+
+      security = ClassSecurityInfo()
+
+      security.declareProtected('Use Poll', 'castVote')
+      def castVote(self, index):
+          ...
+
+      security.declareProtected('View Poll results', 'getTotalVotes')
+      def getTotalVotes(self):
+          ...
+
+      security.declareProtected('View Poll results', 'getVotesFor')
+      def getVotesFor(self, index):
+          ...
+
+      security.declarePublic('getResponses')
+      def getResponses(self):
+          ...
+
+      security.declarePublic('getQuestion')
+      def getQuestion(self):
+          ...
+
+For security declarations to be set up Zope requires that you
+initialize your product class.  Here's how to initialize your poll
+class::
+
+  from Globals import InitializeClass
+
+  class PollProduct(...):
+     ...
+
+  InitializeClass(PollProduct)
+
+Summary
+-------
+
+Congratulations, you've created a product class.  Here it is in all
+its glory (see `examples/PollProduct.py <PollProduct.py>`_)::
+
+  from Poll import Poll
+  from AccessControl import ClassSecurityInfo
+  from Globals import InitializeClass
+  from Acquisition import Implicit
+  from Globals import Persistent
+  from AccessControl.Role import RoleManager
+  from OFS.SimpleItem import Item
+
+  class PollProduct(Implicit, Persistent, RoleManager, Item):
+      """Poll product class, implements Poll interface.
+
+      The poll has a question and a sequence of responses. Votes
+      are stored in a dictionary which maps response indexes to a
+      number of votes.
+      """
+
+      implements(IPoll)
+
+      meta_type = 'Poll'
+
+      security = ClassSecurityInfo()
+
+      def __init__(self, id, question, responses):
+          self.id = id
+          self._question = question
+          self._responses = responses
+          self._votes = {}
+          for i in range(len(responses)):
+              self._votes[i] = 0
+
+      security.declareProtected('Use Poll', 'castVote')
+      def castVote(self, index):
+          "Votes for a choice"
+          self._votes[index] = self._votes[index] + 1
+          self._p_changed = 1
+
+      security.declareProtected('View Poll results', 'getTotalVotes')
+      def getTotalVotes(self):
+          "Returns total number of votes cast"
+          total = 0
+          for v in self._votes.values():
+              total = total + v
+          return total
+
+      security.declareProtected('View Poll results', 'getVotesFor')
+      def getVotesFor(self, index):
+          "Returns number of votes cast for a given response"
+          return self._votes[index]
+
+      security.declarePublic('getResponses')
+      def getResponses(self):
+          "Returns the sequence of responses"
+          return tuple(self._responses)
+
+      security.declarePublic('getQuestion')
+      def getQuestion(self):
+          "Returns the question"
+          return self._question
+
+  InitializeClass(Poll)
+
+Now it's time to test your product class in Zope.  To do this you
+must register your product class with Zope.
+
+Registering Products
+====================
+
+Products are Python packages that live in 'lib/python/Products'.
+Products are loaded into Zope when Zope starts up.  This process is
+called *product initialization*.  During product initialization, each
+product is given a chance to register its capabilities with Zope.
+
+Product Initialization
+----------------------
+
+When Zope starts up it imports each product and calls the product's
+'initialize' function passing it a registrar object.  The
+'initialize' function uses the registrar to tell Zope about its
+capabilities.  Here is an example '__init__.py' file::
+
+  from PollProduct import PollProduct, addForm, addFunction
+
+  def initialize(registrar):
+      registrar.registerClass(
+          PollProduct,
+          constructors=(addForm, addFunction),
+          )
+
+This function makes one call to the *registrar* object which
+registers a class as an addable object.  The *registrar* figures out
+the name to put in the product add list by looking at the 'meta_type'
+of the class.  Zope also deduces a permission based on the class's
+meta-type, in this case *Add Polls* (Zope automatically pluralizes
+"Poll" by adding an "s").  The 'constructors' argument is a tuple of
+objects consisting of two functions: an add form which is called when
+a user selects the object from the product add list, and the add
+method which is the method called by the add form.  Note that these
+functions are protected by the constructor permission.
+
+Note that you cannot restrict which types of containers can contain
+instances of your classes.  In other words, when you register a
+class, it will appear in the product add list in folders if the user
+has the constructor permission.
+
+See the *API Reference* for more information on the
+``ProductRegistrar`` interface.
+
+Factories and Constructors
+--------------------------
+
+Factories allow you to create Zope objects that can be added to
+folders and other object managers.  Factories are discussed in
+Chapter 12 of the *Zope Book*.  The basic work a factory does is to
+put a name into the product add list and associate a permission and
+an action with that name.  If you have the required permission then
+the name will appear in the product add list, and when you select the
+name from the product add list, the action method will be called.
+
+Products use Zope factory capabilities to allow instances of product
+classes to be created with the product add list.  In the above
+example of product initialization you saw how a factory is created by
+the product registrar.  Now let's see how to create the add form and
+the add list.
+
+The add form is a function that returns an HTML form that allows a
+users to create an instance of your product class.  Typically this
+form collects that id and title of the instance along with other
+relevant data.  Here's a very simple add form function for the poll
+class::
+
+  def addForm():
+      """Returns an HTML form."""
+      return """<html>
+      <head><title>Add Poll</title></head>
+      <body>
+      <form action="addFunction">
+      id <input type="type" name="id"><br>
+      question <input type="type" name="question"><br>
+      responses (one per line)
+      <textarea name="responses:lines"></textarea>
+      </form>
+      </body>
+      </html>"""
+
+Notice how the action of the form is ``addFunction``.  Also notice
+how the lines of the response are marshalled into a sequence.  See
+Chapter 2 for more information about argument marshalling and object
+publishing.
+
+It's also important to include a HTML ``head`` tag in the add form.
+This is necessary so that Zope can set the base URL to make sure that
+the relative link to the ``addFunction`` works correctly.
+
+The add function will be passed a ``FactoryDispatcher`` as its first
+argument which proxies the location (usually a Folder) where your
+product was added.  The add function may also be passed any form
+variables which are present in your add form according to normal
+object publishing rules.
+
+Here's an add function for your poll class::
+
+  def addFunction(dispatcher, id, question, responses):
+      """Create a new poll and add it to myself
+      """
+      p = PollProduct(id, question, responses)
+      dispatcher.Destination()._setObject(id, p)
+
+The dispatcher has three methods:
+
+- ``Destination`` -- The ``ObjectManager`` where your product was added.
+
+- ``DestinationURL`` -- The URL of the ``ObjectManager`` where your
+  product was added.
+
+- ``manage_main`` -- Redirects to a management view of the
+  ``ObjectManager`` where your product was added.
+
+Notice how it calls the ``_setObject()`` method of the destination
+``ObjectManager`` class to add the poll to the folder.  See the *API
+Reference* for more information on the ``ObjectManager`` interface.
+
+The add function should also check the validity of its input.  For
+example the add function should complain if the question or response
+arguments are not of the correct type.
+
+Finally you should recognize that the constructor functions are *not*
+methods on your product class.  In fact they are called before any
+instances of your product class are created.  The constructor
+functions are published on the web so they need to have doc strings,
+and are protected by a permission defined in during product
+initialization.
+
+Testing
+-------
+
+Now you're ready to register your product with Zope.  You need to add
+the add form and add method to the poll module.  Then you should
+create a `Poll` directory in your `lib/python/Products` directory and
+add the `Poll.py`, `PollProduct.py`, and `__init__.py` files.  Then
+restart Zope.
+
+Now login to Zope as a manager and visit the web management
+interface.  You should see a 'Poll' product listed inside the
+*Products* folder in the *Control_Panel*.  If Zope had trouble
+initializing your product you will see a traceback here.  Fix your
+problems, if any and restart Zope.  If you are tired of all this
+restarting, take a look at the *Refresh* facility covered in Chapter
+7.
+
+Now go to the root folder.  Select *Poll* from the product add list.
+Notice how you are taken to the add form.  Provide an id, a question,
+and a list of responses and click *Add*.  Notice how you get a black
+screen.  This is because your add method does not return anything.
+Notice also that your poll has a broken icon, and only has the
+management views.  Don't worry about these problems now, you'll find
+out how to fix these problems in the next section.
+
+Now you should build some DTML Methods and Python Scripts to test
+your poll instance.  Here's a Python Script to figure out voting
+percentages::
+
+  ## Script (Python) "getPercentFor"
+  ##parameters=index
+  ##
+  """Returns the percentage of the vote given a response index. Note,
+  this script should be bound a poll by acquisition context."""
+  poll = context
+  return float(poll.getVotesFor(index)) / poll.getTotalVotes()
+
+
+Here's a DTML Method that displays poll results and allows you to
+vote::
+
+  <dtml-var standard_html_header>
+
+  <h2>
+    <dtml-var getQuestion>
+  </h2>
+
+  <form> <!-- calls this dtml method -->
+
+  <dtml-in getResponses>
+    <p>
+      <input type="radio" name="index" value="&dtml-sequence-index;">
+      <dtml-var sequence-item>
+    </p>
+  </dtml-in>
+
+  <input type="submit" value=" Vote ">
+
+  </form>
+
+  <!-- process form -->
+
+  <dtml-if index>
+    <dtml-call expr="castVote(index)">
+  </dtml-if>
+
+  <!-- display results -->
+
+  <h2>Results</h2>
+
+  <p><dtml-var getTotalVotes> votes cast</p>
+
+  <dtml-in getResponses>
+    <p>
+      <dtml-var sequence-item> -
+      <dtml-var expr="getPercentFor(_.get('sequence-index'))">%
+    </p>
+  </dtml-in>
+
+  <dtml-var standard_html_footer>
+
+To use this DTML Method, call it on your poll instance.  Notice how
+this DTML makes calls to both your poll instance and the
+``getPercentFor`` Python script.
+
+At this point there's quite a bit of testing and refinement that you
+can do.  Your main annoyance will be having to restart Zope each time
+you make a change to your product class (but see Chapter 9 for
+information on how to avoid all this restarting).  If you vastly
+change your class you may break existing poll instances, and will
+need to delete them and create new ones.  See Chapter 9 for more
+information on debugging techniques which will come in handy.
+
+Building Management Interfaces
+------------------------------
+
+Now that you have a working product let's see how to beef up its user
+interface and create online management facilities.
+
+Defining Management Views
+-------------------------
+
+All Zope products can be managed through the web.  Products have a
+collection of management tabs or *views* which allow managers to
+control different aspects of the product.
+
+A product's management views are defined in the ``manage_options``
+class attribute.  Here's an example::
+
+        manage_options=(
+            {'label' : 'Edit', 'action' : 'editMethod'},
+            {'label' : 'View', 'action' : 'viewMethod'},
+            )
+
+The ``manage_options`` structure is a tuple that contains
+dictionaries.  Each dictionary defines a management view.  The view
+dictionary can have a number of items.
+
+- 'label' -- This is the name of the management view
+
+- 'action' -- This is the URL that is called when the view is
+  chosen. Normally this is the name of a method that displays a
+  management view.
+
+- 'target' -- An optional target frame to display the action. This
+  item is rarely needed.
+
+- 'help' -- Optional help information associated with the
+  view. You'll find out more about this option later.
+
+Management views are displayed in the order they are defined.
+However, only those management views for which the current user has
+permissions are displayed.  This means that different users may see
+different management views when managing your product.
+
+Normally you will define a couple custom views and reusing some
+existing views that are defined in your base classes.  Here's an
+example::
+
+  class PollProduct(..., Item):
+      ...
+
+      manage_options=(
+          {'label' : 'Edit', 'action' : 'editMethod'},
+          {'label' : 'Options', 'action' : 'optionsMethod'},
+          ) + RoleManager.manage_options + Item.manage_options
+
+This example would include the standard management view defined by
+``RoleManager`` which is *Security* and those defined by ``Item``
+which are *Undo* and *Ownership*.  You should include these standard
+management views unless you have good reason not to. If your class
+has a default view method (``index_html``) you should also include a
+*View* view whose action is an empty string.  See Chapter 2 for more
+information on ``index_html``.
+
+Note: you should not make the *View* view the first view on your
+class.  The reason is that the first management view is displayed
+when you click on an object in the Zope management interface.  If the
+*View* view is displayed first, users will be unable to navigate to
+the other management views since the view tabs will not be visible.
+
+Creating Management Views
+-------------------------
+
+The normal way to create management view methods is to use DTML.  You
+can use the ``DTMLFile`` class to create a DTML Method from a file.
+For example::
+
+  from Globals import DTMLFile
+
+  class PollProduct(...):
+    ...
+
+    editForm = DTMLFile('dtml/edit', globals())
+    ...
+
+This creates a DTML Method on your class which is defined in the
+`dtml/edit.dtml` file.  Notice that you do not have to include the
+``.dtml`` file extension.  Also, don't worry about the forward slash
+as a path separator; this convention will work fine on Windows. By
+convention DTML files are placed in a ``dtml`` subdirectory of your
+product.  The ``globals()`` argument to the ``DTMLFile`` constructor
+allows it to locate your product directory.  If you are running Zope
+in debug mode then changes to DTML files are reflected right away. In
+other words you can change the DTML of your product's views without
+restarting Zope to see the changes.
+
+DTML class methods are callable directly from the web, just like
+other methods.  So now users can see your edit form by calling the
+``editForm`` method on instances of your poll class.  Typically DTML
+methods will make calls back to your instance to gather information
+to display.  Alternatively you may decide to wrap your DTML methods
+with normal methods.  This allows you to calculate information needed
+by your DTML before you call it.  This arrangement also ensures that
+users always access your DTML through your wrapper.  Here's an
+example::
+
+  from Globals import DTMLFile
+
+  class PollProduct(...):
+    ...
+
+    _editForm = DTMLFile('dtml/edit', globals())
+
+    def editForm(self, ...):
+        ...
+
+        return self._editForm(REQUEST, ...)
+
+
+When creating management views you should include the DTML variables
+``manage_page_header`` and ``manage_tabs`` at the top, and
+``manage_page_footer`` at the bottom.  These variables are acquired
+by your product and draw a standard management view header, tabs
+widgets, and footer.  The management header also includes CSS
+information which you can take advantage of if you wish to add CSS
+style information to your management views.  The management CSS
+information is defined in the
+`lib/python/App/dtml/manage_page_style.css.dtml`` file.  Here are the
+CSS classes defined in this file and conventions for their use.
+
+- 'form-help' -- Explanatory text related to forms.  In the future,
+  users may have the option to hide this text.
+
+- 'std-text' -- Declarative text unrelated to forms.  You should
+  rarely use this class.
+
+- 'form-title' -- Form titles.
+
+- 'form-label' -- Form labels for required form elements.
+
+- 'form-optional' -- Form labels for optional form elements.
+
+- 'form-element' -- Form elements.  Note, because of a Netscape bug,
+  you should not use this class on 'textarea' elements.
+
+- 'form-text' -- Declarative text in forms.
+
+- 'form-mono' -- Fixed width text in forms.  You should rarely use
+  this class.
+
+Here's an example management view for your poll class.  It allows you
+to edit the poll question and responses (see ``editPollForm.dtml``)::
+
+  <dtml-var manage_page_header>
+  <dtml-var manage_tabs>
+
+  <p class="form-help">
+  This form allows you to change the poll's question and
+  responses. <b>Changing a poll's question and responses
+  will reset the poll's vote tally.</b>.
+  </p>
+
+  <form action="editPoll">
+  <table>
+
+    <tr valign="top">
+      <th class="form-label">Question</th>
+      <td><input type="text" name="question" class="form-element"
+      value="&dtml-getQuestion;"></td>
+    </tr>
+
+    <tr valign="top">
+      <th class="form-label">Responses</th>
+      <td><textarea name="responses:lines" cols="50" rows="10">
+      <dtml-in getResponses>
+      <dtml-var sequence-item html_quote>
+      </dtml-in>
+      </textarea>
+      </td>
+    </tr>
+
+    <tr>
+      <td></td>
+      <td><input type="submit" value="Change" class="form-element"></td>
+    </tr>
+
+  </table>
+  </form>
+
+  <dtml-var manage_page_header>
+
+This DTML method displays an edit form that allows you to change the
+questions and responses of your poll.  Notice how poll properties are
+HTML quoted either by using ``html_quote`` in the ``dtml-var`` tag,
+or by using the ``dtml-var`` entity syntax.
+
+Assuming this DTML is stored in a file ``editPollForm.dtml`` in your
+product's ``dtml`` directory, here's how to define this method on
+your class::
+
+  class PollProduct(...):
+      ...
+
+      security.declareProtected('View management screens', 'editPollForm')
+      editPollForm = DTML('dtml/editPollForm', globals())
+
+Notice how the edit form is protected by the `View management
+screens` permission.  This ensures that only managers will be able to
+call this method.
+
+Notice also that the action of this form is ``editPoll``.  Since the
+poll as it stands doesn't include any edit methods you must define
+one to accept the changes.  Here's an ``editPoll`` method::
+
+  class PollProduct(...):
+      ...
+
+      def __init__(self, id, question, responses):
+          self.id = id
+          self.editPoll(question, response)
+
+      ...
+
+      security.declareProtected('Change Poll', 'editPoll')
+      def editPoll(self, question, responses):
+          """
+          Changes the question and responses.
+          """
+          self._question = question
+          self._responses = responses
+          self._votes = {}
+          for i in range(len(responses)):
+              self._votes[i] = 0
+
+Notice how the ``__init__`` method has been refactored to use the new
+``editPoll`` method.  Also notice how the ``editPoll`` method is
+protected by a new permissions, ``Change Poll``.
+
+There still is a problem with the ``editPoll`` method.  When you call
+it from the ``editPollForm`` through the web nothing is returned.
+This is a bad management interface.  You want this method to return
+an HTML response when called from the web, but you do not want it to
+do this when it is called from ``__init__``.  Here's the solution::
+
+  class Poll(...):
+      ...
+
+      def editPoll(self, question, responses, REQUEST=None):
+          """Changes the question and responses."""
+          self._question = question
+          self._responses = responses
+          self._votes = {}
+          for i in range(len(responses)):
+              self._votes[i] = 0
+          if REQUEST is not None:
+              return self.editPollForm(REQUEST,
+                  manage_tabs_message='Poll question and responses changed.')
+
+If this method is called from the web, then Zope will automatically
+supply the ``REQUEST`` parameter.  (See chapter 4 for more
+information on object publishing).  By testing the ``REQUEST`` you
+can find out if your method was called from the web or not.  If you
+were called from the web you return the edit form again.
+
+A management interface convention that you should use is the
+``manage_tab_message`` DTML variable.  If you set this variable when
+calling a management view, it displays a status message at the top of
+the page.  You should use this to provide feedback to users
+indicating that their actions have been taken when it is not obvious.
+For example, if you don't return a status message from your
+``editPoll`` method, users may be confused and may not realize that
+their changes have been made.
+
+Sometimes when displaying management views, the wrong tab will be
+highlighted.  This is because 'manage_tabs' can't figure out from the
+URL which view should be highlighted.  The solution is to set the
+'management_view' variable to the label of the view that should be
+highlighted.  Here's an example, using the 'editPoll' method::
+
+  def editPoll(self, question, responses, REQUEST=None):
+      """
+      Changes the question and responses.
+      """
+      self._question = question
+      self._responses = responses
+      self._votes = {}
+      for i in range(len(responses)):
+          self._votes[i] = 0
+      if REQUEST is not None:
+          return self.editPollForm(REQUEST,
+              management_view='Edit',
+              manage_tabs_message='Poll question and responses changed.')
+
+Now let's take a look a how to define an icon for your product.
+
+Icons
+-----
+
+Zope products are identified in the management interface with icons.
+An icon should be a 16 by 16 pixel GIF image with a transparent
+background.  Normally icons files are located in a ``www``
+subdirectory of your product package.  To associate an icon with a
+product class, use the ``icon`` parameter to the ``registerClass``
+method in your product's constructor.  For example::
+
+  def initialize(registrar):
+      registrar.registerClass(
+          PollProduct,
+          constructors=(addForm, addFunction),
+          icon='www/poll.gif'
+          )
+
+Notice how in this example, the icon is identified as being within
+the product's ``www`` subdirectory.
+
+See the *API Reference* for more information on the ``registerClass``
+method of the ``ProductRegistrar`` interface.
+
+Online Help
+-----------
+
+Zope has an online help system that you can use to provide help for
+your products.  Its main features are context-sensitive help and API
+help.  You should provide both for your product.
+
+
+Context Sensitive Help
+----------------------
+
+To create context sensitive help, create one help file per management
+view in your product's ``help`` directory.  You have a choice of
+formats including: HTML, DTML, structured text, GIF, JPG, and PNG.
+
+Register your help files at product initialization with the
+``registerHelp()`` method on the registrar object::
+
+  def initialize(registrar):
+      ...
+      registrar.registerHelp()
+
+This method will take care of locating your help files and creating
+help topics for each help file.  It can recognize these file
+extensions: ``.html``, ``.htm``, ``.dtml``, ``.txt``, ``.stx``,
+``.gif``, ``.jpg``, ``.png``.
+
+If you want more control over how your help topics are created you
+can use the ``registerHelpTopic()`` method which takes an id and a
+help topic object as arguments.  For example::
+
+  from mySpecialHelpTopics import MyTopic
+
+  def initialize(context):
+      ...
+      context.registerHelpTopic('myTopic', MyTopic())
+
+Your help topic should adhere to the 'HelpTopic' interface. See the
+*API Reference* for more details.
+
+The chief way to bind a help topic to a management screen is to
+include information about the help topic in the class's
+manage_options structure. For example::
+
+  manage_options = (
+      {'label': 'Edit',
+       'action': 'editMethod',
+       'help': ('productId','topicId')},
+      )
+
+The `help` value should be a tuple with the name of your product's
+Python package, and the file name (or other id) of your help topic.
+Given this information, Zope will automatically draw a *Help* button
+on your management screen and link it to your help topic.
+
+To draw a help button on a management screen that is not a view (such
+as an add form), use the 'HelpButton' method of the 'HelpSys' object
+like so::
+
+  <dtml-var "HelpSys.HelpButton('productId', 'topicId')">
+
+This will draw a help button linked to the specified help topic.  If
+you prefer to draw your own help button you can use the helpURL
+method instead like so::
+
+  <dtml-var "HelpSys.helpURL(
+    topic='productId',
+    product='topicId')">
+
+This will give you a URL to the help topic.  You can choose to draw
+whatever sort of button or link you wish.
+
+Other User Interfaces
+---------------------
+
+In addition to providing a through the web management interface your
+products may also support many other user interfaces.  You product
+might have no web management interfaces, and might be controlled
+completely through some other network protocol.  Zope provides
+interfaces and support for FTP, WebDAV and XML-RPC.  If this isn't
+enough you can add other protocols.
+
+FTP and WebDAV Interfaces
+-------------------------
+
+Both FTP and WebDAV treat Zope objects like files and
+directories.  See Chapter 3 for more information on FTP and WebDAV.
+
+By simply sub-classing from 'SimpleItem.Item' and 'ObjectManager' if
+necessary, you gain basic FTP and WebDAV support.  Without any work
+your objects will appear in FTP directory listings and if your class
+is an 'ObjectManager' its contents will be accessible via FTP and
+WebDAV.  See Chapter 2 for more information on implementing FTP and
+WebDAV support.
+
+XML-RPC and Network Services
+----------------------------
+
+XML-RPC is covered in Chapter 2.  All your product's methods can be
+accessible via XML-RPC.  However, if your are implementing network
+services, you should explicitly plan one or more methods for use with
+XML-RPC.
+
+Since XML-RPC allows marshalling of simple strings, lists, and
+dictionaries, your XML-RPC methods should only accept and return
+these types.  These methods should never accept or return Zope
+objects.  XML-RPC also does not support 'None' so you should use zero
+or something else in place of 'None'.
+
+Another issue to consider when using XML-RPC is security.  Many
+XML-RPC clients still don't support HTTP basic authorization.
+Depending on which XML-RPC clients you anticipate, you may wish to
+make your XML-RPC methods public and accept authentication
+credentials as arguments to your methods.
+
+Content Management Framework Interface
+--------------------------------------
+
+The `Content Management Framework <http://cmf.zope.org>`_ is an
+evolving content management extension for Zope.  It provides a number
+of interfaces and conventions for content objects.  If you wish to
+support the CMF you should consult the CMF user interface guidelines
+and interface documentation.
+
+Supporting the CMF interfaces is not a large burden if you already
+support the Zope management interface.  You should consider
+supporting the CMF if your product class handles user manageable
+content such as documents, images, business forms, etc.
+
+Packaging Products
+------------------
+
+Zope products are normally packaged as tarballs.  You should create
+your product tarball in such a way as to allow it to be unpacked in
+the Products directory.  For example, `cd` to the Products directory
+and then issue a `tar` comand like so::
+
+  $ tar zcvf MyProduct-1.0.1.tgz MyProduct
+
+This will create a gzipped tar archive containing your product.  You
+should include your product name and version number in file name of
+the archive.
+
+See the `Poll-1.0.tgz <examples/Poll-1.0.tgz>`_ file for an example
+of a fully packaged Python product.
+
+
+Product Information Files
+-------------------------
+
+Along with your Python and ZPT files you should include some
+information about your product in its root directory.
+
+- `README.txt` -- Provides basic information about your product.
+   Zope will parse this file as StructuredText and make it available
+   on the *README* view of your product in the control panel.
+
+- `VERSION.txt` -- Contains the name and version of your product on a
+  single line. For example, 'Multiple Choice Poll 1.1.0'.  Zope will
+  display this information as the 'version' property of your product
+  in the control panel.
+
+- `LICENSE.txt` -- Contains your product license, or a link to it.
+
+You may also wish to provide additional information.  Here are some
+suggested optional files to include with your product.
+
+- `INSTALL.txt` -- Provides special instructions for installing the
+  product and components on which it depends.  This file is only
+  optional if your product does not require more than an ungzip/untar
+  into a Zope installation to work.
+
+- `TODO.txt` -- This file should make clear where this product
+  release needs work, and what the product author intends to do about
+  it.
+
+- `CHANGES.txt` and `HISTORY.txt` -- 'CHANGES.txt' should enumerate
+  changes made in particular product versions from the last release
+  of the product. Optionally, a 'HISTORY.txt' file can be used for
+  older changes, while 'CHANGES.txt' lists only recent changes.
+
+- `DEPENDENCIES.txt` -- Lists dependencies including required os
+  platform, required Python version, required Zope version, required
+  Python packages, and required Zope products.
+
+Product Directory Layout
+------------------------
+
+By convention your product will contain a number of sub-directories.
+Some of these directories have already been discussed in this
+chapter. Here is a summary of them.
+
+- `www` -- Contains your icon & ZPT files.
+
+- `help` -- Contains your help files.
+
+- `tests` -- Contains your unit tests.
+
+It is not necessary to include these directories if your don't have
+anything to go in them.
+
+Evolving Products
+=================
+
+As you develop your product classes you will generally make a series
+of product releases.  While you don't know in advance how your
+product will change, when it does change there are measures that you
+can take to minimize problems.
+
+Evolving Classes
+----------------
+
+Issues can occur when you change your product class because instances
+of these classes are generally persistent.  This means that instances
+created with an old class will start using a new class.  If your
+class changes drastically this can break existing instances.
+
+The simplest way to handle this situation is to provide class
+attributes as defaults for newly added attributes.  For example if
+the latest version of your class expects an 'improved_spam' instance
+attribute while earlier versions only sported 'spam' attributes, you
+may wish to define an 'improved_spam' class attribute in your new
+class so your old objects won't break when they run with your new
+class.  You might set 'improved_spam' to None in your class, and in
+methods where you use this attribute you may have to take into
+account that it may be None.  For example::
+
+  class Sandwich(...):
+
+      improved_spam = None
+      ...
+
+      def assembleSandwichMeats(self):
+          ...
+          # test for old sandwich instances
+          if self.improved_spam is None:
+              self.updateToNewSpam()
+          ...
+
+Another solution is to use the standard Python pickling hook
+'__setstate__', however, this is in general more error prone and
+complex.
+
+A third option is to create a method to update old instances.  Then
+you can manually call this method on instances to update to them.
+Note, this won't work unless the instances function well enough to be
+accessible via the Zope management screens.
+
+While you are developing a product you won't have to worry too much
+about these details, since you can always delete old instances that
+break with new class definitions.  However, once you release your
+product and other people start using it, then you need to start
+planning for the eventuality of upgrading.
+
+Another nasty problem that can occur is breakage caused by renaming
+your product classes.  You should avoid this since it breaks all
+existing instances.  If you really must change your class name,
+provide aliases to it using the old name.  You may however, change
+your class's base classes without causing these kinds of problems.
+
+Evolving Interfaces
+-------------------
+
+The basic rule of evolving interfaces is *don't do it*.  While you
+are working privately you can change your interfaces all you wish.
+But as soon as you make your interfaces public you should freeze
+them.  The reason is that it is not fair to users of your interfaces
+to changes them after the fact.  An interface is contract.  It
+specifies how to use a component and it specifies how to implement
+types of components.  Both users and developers will have problems if
+your change the interfaces they are using or implementing.
+
+The general solution is to create simple interfaces in the first
+place, and create new ones when you need to change an existing
+interface.  If your new interfaces are compatible with your existing
+interfaces you can indicate this by making your new interfaces extend
+your old ones.  If your new interface replaces an old one but does
+not extend it you should give it a new name such as,
+``WidgetWithBellsOn``.  Your components should continue to support
+the old interface in addition to the new one for a few releases.
+
+Conclusion
+==========
+
+Migrating your components into fully fledged Zope products is a
+process with a number of steps.  There are many details to keep track
+of.  However, if you follow the recipe laid out in this chapter you
+should have no problems.
+
+Zope products are a powerful framework for building web applications.
+By creating products you can take advantage of Zope's features
+including security, scalability, through the web management, and
+collaboration.

Copied: zope2docs/trunk/zdgbook/Security.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/Security.rst)
===================================================================
--- zope2docs/trunk/zdgbook/Security.rst	                        (rev 0)
+++ zope2docs/trunk/zdgbook/Security.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,1300 @@
+########
+Security
+########
+
+Introduction
+============
+
+A typical web application needs to be securely managed.  Different
+types of users need different kinds of access to the components that
+make up an application. To this end, Zope includes a comprehensive
+set of security features.  This chapter's goal is to shed light on
+Zope security in the context of Zope Product development.  For a more
+fundamental overview of Zope security, you may wish to refer to the
+*Zope Book*, Chapter 6, Users and Security.  Before diving into this
+chapter, you should have a basic understanding of how to build Zope
+Products as well as an understanding of how the Zope object publisher
+works. These topics are covered in Chapter 2 and Chapter 3,
+respectively.
+
+
+Security Architecture
+=====================
+
+The Zope security architecture is built around a *security policy*,
+which you can think of as the "access control philosophy" of
+Zope. This policy arbitrates the decisions Zope makes about whether
+to allow or deny access to any particular object defined within the
+system.
+
+How The Security Policy Relates to Zope's Publishing Machinery
+--------------------------------------------------------------
+
+When access to Zope is performed via HTTP, WebDAV, or FTP, Zope's
+publishing machinery consults the security policy in order to
+determine whether to allow or deny access to a visitor for a
+particular object.  For example, when a user visits the root
+'index_html' object of your site via HTTP, the security policy is
+consulted by 'ZPublisher' to determine whether the user has
+permission to view the 'index_html' object itself.  For more
+information on this topic, see Chapter 3, "Object Publishing".
+
+The Zope security policy is consulted when an object is accessed the
+publishing machinery, for example when a web request is submitted.
+
+
+How The Security Policy Relates to Restricted Code
+--------------------------------------------------
+
+*Restricted code* is generally any sort of logic that may be edited
+remotely (through the Web, FTP, via WebDAV or by other means). DTML
+Methods, SQLMethods, Python Scripts and Perl Scripts are examples of
+restricted code.
+
+When restricted code runs, any access to objects integrated with Zope
+security is arbitrated by the security policy. For example if you
+write a bit of restricted code with a line that attempts to
+manipulate an object you don't have sufficient permission to use, the
+security policy will deny you access to the object.  This generally
+is accomplished by raising an 'Unauthorized' exception, which is a
+Python string exception caught by a User Folder which signifies that
+Zope should attempt to get user credentials before obeying the
+request.  The particular code used to attempt to obtain the
+credentials is determined by the User Folder "closest" (folder-wise)
+to the object being accessed.
+
+The Zope security policy is consulted when an object is accessed by
+restricted code.
+
+'Unauthorized' Exceptions and Through-The-Web Code
+--------------------------------------------------
+
+The security policy infrastructure will raise an 'Unauthorized'
+exception automatically when access to an object is denied.  When an
+'Unauthorized' exception is raised within Zope, it is handled in a
+sane way by Zope, generally by having the User Folder prompt the user
+for login information.  Using this functionality, it's possible to
+protect Zope objects through access control, only prompting the user
+for authentication when it is necessary to perform an action which
+requires privilege.
+
+An example of this behavior can be witnessed within the Zope
+Management interface itself.  The management interface prompts you to
+log in when visiting, for example, the '/manage' method of any Zope
+object.  This is due to the fact that an anonymous user does not
+generally possess the proper credentials to use the management
+interface.  If you're using Zope in the default configuration with
+the default User Folder, it prompts you to provide login information
+via an HTTP basic authentication dialog.
+
+How The Security Policy Relates To Unrestricted Code
+----------------------------------------------------
+
+There are also types of *unrestricted code* in Zope, where the logic
+is not constrained by the security policy. Examples of unrestricted
+code are the methods of Python classes that implement the objects in
+Python file-based add-on components.  Another example of unrestricted
+code can be found in External Method objects, which are defined in
+files on the filesystem.  These sorts of code are allowed to run
+"unrestricted" because access to the file system is required to
+define such logic.  Zope assumes that code defined on the filesystem
+is "trusted", while code defined "through the web" is not.  All
+filesystem-based code in Zope is unrestricted code.
+
+We'll see later that while the security policy does not constrain
+what your unrestricted code does, it can and should be used to
+control the ability to *call* your unrestricted code from within a
+restricted-code environment.
+
+The Zope security policy is *not* consulted when unrestricted code is
+run.
+
+Details Of The Default Zope Security Policy
+-------------------------------------------
+
+In short, the default Zope security policy ensures the following:
+
+- access to an object which does not have any associated security
+  information is always denied.
+
+- if an object is associated with a permission, access is granted or
+  denied based on the user's roles.  If a user has a role which has
+  been granted the permission in question, access is granted.  If the
+  user does not possess a role that has been granted the permission
+  in question, access is denied.
+
+- if the object has a security assertion declaring it *public* , then
+  access will be granted.
+
+- if the object has a security assertion declaring it *private*, then
+  access will be denied.
+
+- accesses to objects that have names beginning with the underscore
+  character '_' are always denied.
+
+As we delve further into Zope security within this chapter, we'll see
+exactly what it means to associate security information with an
+object.
+
+
+Overview Of Using Zope Security Within Your Product
+---------------------------------------------------
+
+Of course, now that we know what the Zope security policy is, we need
+to know how our Product can make use of it.  Zope developers leverage
+the Zope security policy primarily by making security declarations
+related to methods and objects within their Products.  Using security
+assertions, developers may deny or allow all types of access to a
+particular object or method unilaterally, or they may protect access
+to Zope objects more granularly by using permissions to grant or deny
+access based on the roles of the requesting user to the same objects
+or methods.
+
+
+For a more fundamental overview of Zope users, roles, and
+permissions, see the section titled "Authorization and Managing
+Security" in the Security Chapter of the *Zope Book*.
+
+Security Declarations In Zope Products
+--------------------------------------
+
+Zope security declarations allow developers to make security
+assertions about a Product-defined object and its methods.
+Security declarations come in three basic forms.  These are:
+
+- public -- allow anybody to access the protected object
+  or method
+
+- private -- deny anyone access to the protected object or
+  method
+
+- protected -- protect access to the object or method via a
+  permission
+
+We'll see how to actually "spell" these security assertions a
+little later in this chapter.  In the meantime, just know that
+security declarations are fundamental to Zope Product security,
+and they can be used to protect access to an object by
+associating it with a permission.  We will refer to security
+declarations as "declarations" and "assertions" interchangeably
+within this chapter.
+
+
+Permissions In Zope Products
+============================
+
+A permission is the smallest unit of access to an object in Zope,
+roughly equivalent to the atomic permissions on files seen in Windows
+NT or UNIX: R (Read), W(Write), X(Execute), etc. However, unlike
+these types of mnemonic permissions shared by all sorts of different
+file types in an operating system product, in Zope, a permission
+usually describes a fine-grained logical operation which takes place
+upon an object, such as "View Management Screens" or "Add
+Properties".
+
+Zope administrators associate these permissions with *roles*, which
+they grant to Zope users.  Thus, declaring a protection assertion on
+a method of "View management screens" ensures that only users who
+possess roles which have been granted the "View management screens"
+permission are able to perform the action that the method defines.
+
+It is important to note that Zope's security architecture dictates
+that roles and users remain the domain of administrators, while
+permissions remain the domain of developers.  Developers of Products
+should not attempt to define roles or users, although they may (and
+usually must) define permissions.  Most importantly, a Zope
+administrator who makes use of your product should have the "last
+word" as regards which roles are granted which permissions, allowing
+her to protect her site in a manner that fits her business goals.
+
+Permission names are strings, and these strings are currently
+arbitrary.  There is no permission hierarchy, or list of "approved
+permissions".  Developers are encouraged to reuse Zope core
+permissions (e.g. "View", "Access contents information") when
+appropriate, or they may create their own as the need arises.  It is
+generally wise to reuse existing Zope permission names unless you
+specifically need to define your own.  For a list of existing Zope
+core permissions, see Appendix A, "Zope Core Permissions".
+
+Permissions are often tied to method declarations in Zope.  Any
+number of method declarations may share the same permission.  It's
+useful to declare the same permission on a set of methods which can
+logically be grouped together.  For example, two methods which return
+management forms for the object can be provided with the same
+permission, "View management screens".  Likewise, two entirely
+different objects can share a permission name to denote that the
+operation that's being protected is fundamentally similar.  For
+instance, most Product-defined objects reuse the Zope "View"
+permission, because most Zope objects need to be viewed in a web
+browser.  If you create an addable Zope class named 'MyObject', it
+doesn't make much sense to create a permission "View MyObject",
+because the generic "View" permission may be reused for this action.
+
+There is an exception to the "developers should not try to define
+roles" rule inasmuch as Zope allows developers to assign "default
+roles" to a permission.  This is primarily for the convenience of the
+Zope administrator, as default roles for a permission cause the Zope
+security machinery to provide a permission to a role *by default*
+when instances of a Product class are encountered during security
+operations.  For example, if your Product defines a permission "Add
+Poll Objects", this permission may be associated with a set of
+default roles, perhaps "Manager".  Default roles in Products should
+not be used against roles other than "Manager", "Anonymous", "Owner",
+and "Authenticated" (the four default Zope roles), as other roles are
+not guaranteed to exist in every Zope installation.
+
+Using security assertions in Zope is roughly analogous to assigning
+permission bit settings and ownership information to files in a UNIX
+or Windows filesystem.  Protecting objects via permissions allows
+developers and administrators to secure Zope objects independently of
+statements made in application code.
+
+Implementing Security In Python Products
+========================================
+
+Security Assertions
+-------------------
+
+You may make several kinds of security assertions at the Python
+level.  You do this to declare accessibility of methods and
+subobjects of your classes. Three of the most common assertions that
+you'll want to make on your objects are:
+
+- this object is **public** (always accessible)
+
+- this object is **private** (not accessible by restricted code or by
+  URL traversal)
+
+- this object is **protected** by a specific permission
+
+There are a few other kinds of security assertions that are 
+much less frequently used but may be needed in some cases:
+
+- asserting that access to subobjects that do not have explicit
+  security information should be allowed rather than denied.
+
+- asserting what sort of protection should be used when determining
+  access to an *object itself* rather than a particular method of the
+  object
+
+It is important to understand that security assertions made in your
+Product code *do not* limit the ability of the code that the
+assertion protects.  Assertions only protect *access to this code*.
+The code which constitutes the body of a protected, private, or
+public method of a class defined in a Zope disk-based Product runs
+completely unrestricted, and is not subject to security constraints
+of any kind within Zope.  An exception to this rule occurs when
+disk-based-Product code calls a "through the web" method such as a
+Python Script or a DTML Method.  In this case, the security
+constraints imposed by these objects respective to the current
+request are obeyed.
+
+When Should I Use Security Assertions?
+--------------------------------------
+
+If you are building an object that will be used from DTML or other
+restricted code, or that will be accessible directly through the web
+(or other remote protocols such as FTP or WebDAV) then you need to
+define security information for your object.
+
+Making Security Assertions
+--------------------------
+
+As a Python developer, you make security assertions in your Python
+classes using 'SecurityInfo' objects. A 'SecurityInfo' object
+provides the interface for making security assertions about an object
+in Zope.
+
+The convention of placing security declarations inside Python code
+may at first seem a little strange if you're used to "plain old
+Python" which has no notion at all of security declarations.  But
+because Zope provides the ability to make these security assertions
+at such a low level, the feature is ubiquitous throughout Zope,
+making it easy to make these declarations once in your code, usable
+site-wide without much effort.
+
+Class Security Assertions
+=========================
+
+The most common kind of 'SecurityInfo' you will use as a component
+developer is the 'ClassSecurityInfo' object.  You use
+'ClassSecurityInfo' objects to make security assertions about methods
+on your classes.
+
+Classes that need security assertions are any classes that define
+methods that can be called "through the web".  This means any methods
+that can be called directly with URL traversal, from DTML Methods, or
+from Python-based Script objects.
+
+Declaring Class Security
+------------------------
+
+When writing the classes in your product, you create a
+'ClassSecurityInfo' instance *within each class that needs to play
+with the security model*. You then use the 'ClassSecurityInfo' object
+to make assertions about your class, its subobjects and its methods.
+
+The 'ClassSecurityInfo' class is defined in the 'AccessControl'
+package of the Zope framework. To declare class security information
+create a 'ClassSecurityInfo' class attribute named 'security'.  The
+name 'security' is used for consistency and for the benefit of new
+component authors, who often learn from looking at other people's
+code. You do not have to use the name 'security' for the security
+infrastructure to recognize your assertion information, but it is
+recommended as a convention.  For example::
+
+  from AccessControl import ClassSecurityInfo
+
+  class Mailbox(ObjectManager):
+    """A mailbox object that contains mail message objects."""
+
+    # Create a SecurityInfo for this class. We will use this 
+    # in the rest of our class definition to make security 
+    # assertions.
+    security = ClassSecurityInfo()
+
+    # Here is an example of a security assertion. We are 
+    # declaring that access to messageCount is public.
+    security.declarePublic('messageCount')
+
+    def messageCount(self):
+      """Return a count of messages."""
+      return len(self._messages)
+
+
+Note that in the example above we called the 'declarePublic' method
+of the 'ClassSecurityInfo' instance to declare that access to the
+'messageCount' method be public. To make security assertions for your
+object, you just call the appropriate methods of the
+'ClassSecurityInfo' object, passing the appropriate information for
+the assertion you are making.
+
+'ClassSecurityInfo' approach has a number of benefits. A major
+benefit is that it is very explicit, it allows your security
+assertions to appear in your code near the objects they protect,
+which makes it easier to assess the state of protection of your code
+at a glance. The 'ClassSecurityInfo' interface also allows you as a
+component developer to ignore the implementation details in the
+security infrastructure and protects you from future changes in those
+implementation details.
+
+Let's expand on the example above and see how to make the most common
+security assertions using the 'SecurityInfo' interface.
+
+To assert that a method is *public* (anyone may call it) you may call
+the 'declarePublic' method of the 'SecurityInfo' object, passing the
+name of the method or subobject that you are making the assertion
+on::
+
+  security.declarePublic(methodName)
+
+To assert that a method is *private* you call the 'declarePrivate'
+method of the 'SecurityInfo' object, passing the name of the method
+or subobject that you are making the assertion on::
+
+  security.declarePrivate(methodName)
+
+To assert that a method or subobject is *protected* by a particular
+permission, you call the 'declareProtected' method of the
+'SecurityInfo' object, passing a permission name and the name of a
+method to be protected by that permission::
+
+  security.declareProtected(permissionName, methodName)
+
+If you have lots of methods you want to protect under the same
+permission, you can pass as many methodNames ase you want::
+
+  security.declareProtected(permissionName, methodName1,
+  methodName2, methodName3, ...)
+
+Passing multiple names like this works for all of the 'declare'
+security methods ('declarePublic', 'declarePrivate', and
+'declareProtected').
+
+Deciding To Use 'declareProtected' vs. 'declarePublic' or 'declarePrivate'
+--------------------------------------------------------------------------
+
+      If the method you're making the security declaration against is
+      innocuous, and you're confident that its execution will not
+      disclose private information nor make inappropriate changes to
+      system state, you should declare the method public.
+
+      If a method should never be run under any circumstances via
+      traversal or via through-the-web code, the method should be
+      declared private.  This is the default if a method has no
+      security assertion, so you needn't explicitly protect
+      unprotected methods unless you've used 'setDefaultAccess' to set
+      the object's default access policy to 'allow' (detailed in
+      *Other Assertions*, below).
+
+      If the method should only be executable by a certain class of
+      users, you should declare the method protected.
+
+A Class Security Example
+------------------------
+
+Let's look at an expanded version of our 'Mailbox' example that makes
+use of each of these types of security assertions::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  class Mailbox(ObjectManager):
+    """A mailbox object."""
+
+  # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    security.declareProtected('View management screens', 'manage')
+    manage=HTMLFile('mailbox_manage', globals())
+
+    security.declarePublic('messageCount')
+    def messageCount(self):
+      """Return a count of messages."""
+      return len(self._messages)
+
+    # protect 'listMessages' with the 'View Mailbox' permission
+    security.declareProtected('View Mailbox', 'listMessages')
+
+    def listMessages(self):
+      """Return a sequence of message objects."""
+      return self._messages[:]
+
+    security.declarePrivate('getMessages')
+    def getMessages(self):
+      self._messages=GoGetEm()
+      return self._messages
+
+  # call this to initialize framework classes, which
+  # does the right thing with the security assertions.
+  Globals.InitializeClass(Mailbox)
+
+Note the last line in the example.  In order for security assertions
+to be correctly applied to your class, you must call the global class
+initializer ('Globals.InitializeClass') for all classes that have
+security information. This is very important - the global initializer
+does the "dirty work" required to ensure that your object is
+protected correctly based on the security assertions that you have
+made. If you don't run it on the classes that you've protected with
+security assertions, the security assertions will not be effective.
+
+Deciding Permission Names For Protected Methods
+-----------------------------------------------
+
+When possible, you should make use of an existing Zope permission
+within a 'declareProtected' assertion.  A list of the permissions
+which are available in a default Zope installation is available
+within Appendix A.  When it's not possible to reuse an existing
+permission, you should choose a permission name which is a verb or a
+verb phrase.
+
+Object Assertions
+-----------------
+
+Often you will also want to make a security assertion on the *object
+itself*. This is important for cases where your objects may be
+accessed in a restricted environment such as DTML. Consider the
+example DTML code::
+
+  <dtml-var expr="some_method(someObject)">
+
+Here we are trying to call 'some_method', passing the object
+'someObject'. When this is evaluated in the restricted DTML
+environment, the security policy will attempt to validate access to
+both 'some_method' and 'someObject'. We've seen how to make
+assertions on methods - but in the case of 'someObject' we are not
+trying to access any particular method, but rather the *object
+itself* (to pass it to 'some_method'). Because the security machinery
+will try to validate access to 'someObject', we need a way to let the
+security machinery know how to handle access to the object itself in
+addition to protecting its methods.
+
+To make security assertions that apply to the *object itself* you
+call methods on the 'SecurityInfo' object that are analogous to the
+three that we have already seen::
+
+  security.declareObjectPublic()
+
+  security.declareObjectPrivate()
+
+  security.declareObjectProtected(permissionName)
+
+The meaning of these methods is the same as for the method variety,
+except that the assertion is made on the object itself.
+
+An Object Assertion Example
+---------------------------
+
+Here is the updated 'Mailbox' example, with the addition of a
+security assertion that protects access to the object itself with the
+'View Mailbox' permission::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  class Mailbox(ObjectManager):
+    """A mailbox object."""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    # Set security for the object itself
+    security.declareObjectProtected('View Mailbox')
+
+    security.declareProtected('View management screens', 'manage')
+    manage=HTMLFile('mailbox_manage', globals())
+
+    security.declarePublic('messageCount')
+    def messageCount(self):
+      """Return a count of messages."""
+      return len(self._messages)
+
+    # protect 'listMessages' with the 'View Mailbox' permission
+    security.declareProtected('View Mailbox', 'listMessages')
+
+    def listMessages(self):
+      """Return a sequence of message objects."""
+      return self._messages[:]
+
+    security.declarePrivate('getMessages')
+    def getMessages(self):
+      self._messages=GoGetEm()
+      return self._messages
+
+  # call this to initialize framework classes, which
+  # does the right thing with the security assertions.
+  Globals.InitializeClass(Mailbox)
+
+Other Assertions
+----------------
+
+The SecurityInfo interface also supports the less common
+security assertions noted earlier in this document.
+
+To assert that access to subobjects that do not have explicit
+security information should be *allowed* rather than *denied* by
+the security policy, use::
+
+  security.setDefaultAccess("allow")
+
+This assertion should be used with caution. It will effectively
+change the access policy to "allow-by-default" for all
+attributes in your object instance (not just class attributes)
+that are not protected by explicit assertions.  By default, the
+Zope security policy flatly denies access to attributes and
+methods which are not mentioned within a security assertion.
+Setting the default access of an object to "allow" effectively
+reverses this policy, allowing access to all attributes and
+methods which are not explicitly protected by a security
+assertion.
+
+'setDefaultAccess' applies to attributes that are simple Python
+types as well as methods without explicit protection. This is
+important because some mutable Python types (lists, dicts) can
+then be modified by restricted code. Setting default access to
+"allow" also affects attributes that may be defined by the base
+classes of your class, which can lead to security holes if you
+are not sure that the attributes of your base classes are safe
+to access.
+
+Setting the default access to "allow" should only be done if you
+are sure that all of the attributes of your object are safe to
+access, since the current architecture does not support using
+explicit security assertions on non-method attributes.
+
+What Happens When You Make A Mistake Making 'SecurityInfo' Declarations?
+------------------------------------------------------------------------
+
+It's possible that you will make a mistake when making 'SecurityInfo'
+declarations.  For example, it is not legal to declare two
+conflicting permissions on a method::
+
+  class Foo(SimpleItem):
+      security = ClassSecurityInfo()
+
+      meta_type='Foo'
+
+      security.declareProtected('View foos', 'index_html')
+      def index_html(self):
+          """ make index_html web-publishable """
+          return "<html><body>hi!</body></html>"
+
+security.declareProtected('View', 'index_html')
+# whoops, declared a conflicting permission on index_html!
+
+When you make a mistake like this, the security machinery will
+accept the *first* declaration made in the code and will write
+an error to the Zope debug log upon encountering the second and
+following conflicting declarations during class initialization.
+It's similarly illegal to declare a method both private and
+public, or to declare a method both private and protected, or to
+declare a method both public and protected. A similar error will
+be raised in all of these cases.
+
+Note that Zope *will not* warn you if you misspell the name of
+a method in a declareProtected, declarePublic, or declarePrivate
+assertion.  For instance, you try to protect the 'index_html'
+method with the 'View' permission and make a mistake,
+spelling the name 'index_html' as 'inde_html', like so::
+
+  security.declareProtected('View', 'inde_html')
+  # whoops, declared a permission assertion for 'inde_html'
+  # when I really wanted it to be 'index_html'!
+  def index_html(self):
+      """ make index_html web-publishable """
+      return "<html><body>hi!</body></html>"
+
+You'll need to track down these kinds of problems yourself.
+
+Setting Default Roles For Permissions
+-------------------------------------
+
+When defining operations that are protected by permissions, one thing
+you commonly want to do is to arrange for certain roles to be
+associated with a particular permission *by default* for instances of
+your object.
+
+For example, say you are creating a *News Item* object. You want
+'Anonymous' users to have the ability to view news items by default;
+you don't want the site manager to have to explicitly change the
+security settings for each *News Item* just to give the 'Anonymous"
+role 'View' permission.
+
+What you want as a programmer is a way to specify that certain roles
+should have certain permissions by default on instances of your
+object, so that your objects have sensible and useful security
+settings at the time they are created. Site managers can always
+*change* those settings if they need to, but you can make life easier
+for the site manager by setting up defaults that cover the common
+case by default.
+
+As we saw earlier, the 'SecurityInfo' interface provided a way to
+associate methods with permissions. It also provides a way to
+associate a permission with a set of default roles that should have
+that permission on instances of your object.
+
+To associate a permission with one or more roles, use the following::
+
+  security.setPermissionDefault(permissionName, rolesList)
+
+The *permissionName* argument should be the name of a permission that
+you have used in your object and *rolesList* should be a sequence
+(tuple or list) of role names that should be associated with
+*permissionName* by default on instances of your object.
+
+Note that it is not always necessary to use this method. All
+permissions for which you did not set defaults using
+'setPermissionDefault' are assumed to have a single default role of
+'Manager'.  Notable exceptions to this rule include 'View' and
+'Access contents information', which always have the default roles
+'Manager' and 'Anonymous'.
+
+The 'setPermissionDefault' method of the 'SecurityInfo' object should
+be called only once for any given permission name.
+
+
+An Example of Associating Default Roles With Permissions
+--------------------------------------------------------
+
+Here is our 'Mailbox' example, updated to associate the 'View
+Mailbox' permission with the roles 'Manager' and 'Mailbox Owner' by
+default::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  class Mailbox(ObjectManager):
+    """A mailbox object."""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    # Set security for the object itself
+    security.declareObjectProtected('View Mailbox')
+
+    security.declareProtected('View management screens', 'manage')
+    manage=DTMLFile('mailbox_manage', globals())
+
+    security.declarePublic('messageCount')
+    def messageCount(self):
+      """Return a count of messages."""
+      return len(self._messages)
+
+    security.declareProtected('View Mailbox', 'listMessages')
+    def listMessages(self):
+      """Return a sequence of message objects."""
+      return self._messages[:]
+
+    security.setPermissionDefault('View Mailbox', ('Manager', 'Mailbox Owner'))
+
+  # call this to initialize framework classes, which
+  # does the right thing with the security assertions.
+  Globals.InitializeClass(Mailbox)
+
+What Happens When You Make A Mistake Declaring Default Roles?
+-------------------------------------------------------------
+
+It's possible that you will make a mistake when making default roles
+declarations.  For example, it is not legal to declare two
+conflicting default roles for a permission::
+
+  class Foo(SimpleItem):
+      security = ClassSecurityInfo()
+
+      meta_type='Foo'
+
+      security.declareProtected('View foos', 'index_html')
+      def index_html(self):
+          """ """
+          return "<html><body>hi!</body></html>"
+
+      security.setPermissionDefault('View foos', ('Manager',))
+
+      security.setPermissionDefault('View foos', ('Anonymous',))
+      # whoops, conflicting permission defaults!
+
+When you make a mistake like this, the security machinery will accept
+the *first* declaration made in the code and will write an error to
+the Zope debug log about the second and following conflicting
+declarations upon class initialization.
+
+What Can (And Cannot) Be Protected By Class Security Info?
+----------------------------------------------------------
+
+It is important to note what can and cannot be protected using the
+'ClassSecurityInfo' interface. First, the security policy relies on
+*Acquisition* to aggregate access control information, so any class
+that needs to work in the security policy must have either
+'Acquisition.Implicit' or 'Acquisition.Explicit' in its base class
+hierarchy.
+
+The current security policy supports protection of methods and
+protection of subobjects that are instances. It does *not* currently
+support protection of simple attributes of basic Python types
+(strings, ints, lists, dictionaries). For instance::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  # We subclass ObjectManager, which has Acquisition in its
+  # base class hierarchy, so we can use SecurityInfo.
+
+  class MyClass(ObjectManager):
+    """example class"""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    # Set security for the object itself
+    security.declareObjectProtected('View')
+
+    # This is ok, because subObject is an instance
+    security.declareProtected('View management screens', 'subObject')
+    subObject=MySubObject()
+
+    # This is ok, because sayHello is a method
+    security.declarePublic('sayHello')
+    def sayHello(self):
+      """Return a greeting."""
+      return "hello!"
+
+    # This will not work, because foobar is not a method
+    # or an instance - it is a standard Python type
+    security.declarePublic('foobar')
+    foobar='some string'
+
+Keep this in mind when designing your classes. If you need simple
+attributes of your objects to be accessible (say via DTML), then you
+need to use the 'setDefaultAccess' method of 'SecurityInfo' in your
+class to allow this (see the note above about the security
+implications of this). In general, it is always best to expose the
+functionality of your objects through methods rather than exposing
+attributes directly.
+
+Note also that the actual 'ClassSecurityInfo' instance you use to
+make security assertions is implemented such that it is *never*
+accessible from restricted code or through the Web (no action on the
+part of the programmer is required to protect it).
+
+Inheritance And Class Security Declarations
+-------------------------------------------
+
+Python inheritance can prove confusing in the face of security
+declarations.
+
+If a base class which has already been run through "InitializeClass"
+is inherited by a superclass, nothing special needs to be done to
+protect the base class' methods within the superclass unless you wish
+to modify the declarations made in the base class.  The security
+declarations "filter down" into the superclass.
+
+On the other hand, if a base class hasn't been run through the global
+class initializer ('InitializeClass'), you need to proxy its security
+declarations in the superclass if you wish to access any of its
+methods within through-the-web code or via URL traversal.
+
+In other words, security declarations that you make using
+'ClassSecurityInfo' objects effect instances of the class upon which
+you make the declaration. You only need to make security declarations
+for the methods and subobjects that your class actually *defines*. If
+your class inherits from other classes, the methods of the base
+classes are protected by the security declarations made in the base
+classes themselves. The only time you would need to make a security
+declaration about an object defined by a base class is if you needed
+to *redefine* the security information in a base class for instances
+of your own class. An example below redefines a security assertion in
+a subclass::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  class MailboxBase(ObjectManager):
+    """A mailbox base class."""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    security.declareProtected('View Mailbox', 'listMessages')
+    def listMessages(self):
+      """Return a sequence of message objects."""
+      return self._messages[:]
+
+    security.setPermissionDefault('View Mailbox', ('Manager', 'Mailbox Owner'))
+
+  Globals.InitializeClass(MailboxBase)
+
+  class MyMailbox(MailboxBase):
+    """A mailbox subclass, where we want the security for 
+      listMessages to be public instead of protected (as 
+      defined in the base class)."""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    security.declarePublic('listMessages')
+
+  Globals.InitializeClass(MyMailbox)
+
+Class Security Assertions In Non-Product Code (External Methods/Python Scripts)
+-------------------------------------------------------------------------------
+
+Objects that are returned from Python Scripts or External Methods
+need to have assertions declared for themselves before they can be
+used in restricted code.  For example, assume you have an External
+Method that returns instances of a custom 'Book' class. If you want
+to call this External Method from DTML, and you'd like your DTML to
+be able to use the returned 'Book' instances, you will need to ensure
+that your class supports Acquisition, and you'll need to make
+security assertions on the 'Book' class and initialize it with the
+global class initializer (just as you would with a class defined in a
+Product). For example::
+
+  # an external method that returns Book instances
+
+  from AccessControl import ClassSecurityInfo
+  from Acquisition import Implicit
+  import Globals
+
+  class Book(Implicit):
+
+    def __init__(self, title):
+      self._title=title
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+    security.declareObjectPublic()
+
+    security.declarePublic('getTitle')
+    def getTitle(self):
+      return self._title
+
+  Globals.InitializeClass(Book)
+
+  # The actual external method
+  def GetBooks(self):
+    books=[]
+    books.append(Book('King Lear').__of__(self))
+    books.append(Book('Romeo and Juliet').__of__(self))
+    books.append(Book('The Tempest').__of__(self))
+    return books
+
+Note that we *wrap* the book instances by way of their __of__ methods
+to obtain a security context before returning them.
+
+Note that this particular example is slightly dangerous.  You need to
+be careful that classes defined in external methods not be made
+persistent, as this can cause Zope object database inconsistencies.
+In terms of this example, this would mean that you would need to be
+careful to not attach the Book object returned from the 'GetBook'
+method to a persistent object within the ZODB. See Chapter 4, "ZODB
+Persistent Components" for more information.  Thus it's generally a
+good idea to define the Book class in a Product if you want books to
+be persistent.  It's also less confusing to have all of your security
+declarations in Products.
+
+However, one benefit of the 'SecurityInfo' approach is that it is
+relatively easy to subclass and add security info to classes that you
+did not write. For example, in an External Method, you may want to
+return instances of 'Book' although 'Book' is defined in another
+module out of your direct control. You can still use 'SecurityInfo'
+to define security information for the class by using::
+
+  # an external method that returns Book instances
+
+  from AccessControl import ClassSecurityInfo
+  from Acquisition import Implicit
+  import bookstuff
+  import Globals
+
+  class Book(Implicit, bookstuff.Book):
+    security = ClassSecurityInfo()
+    security.declareObjectPublic()
+    security.declarePublic('getTitle')
+
+  Globals.InitializeClass(Book)
+
+  # The actual external method
+  def GetBooks(self):
+    books=[]
+    books.append(Book('King Lear'))
+    books.append(Book('Romeo and Juliet'))
+    books.append(Book('The Tempest'))
+    return books
+
+Module Security Assertions
+==========================
+
+Another kind of 'SecurityInfo' object you will use as a
+component developer is the 'ModuleSecurityInfo' object.
+
+'ModuleSecurityInfo' objects do for objects defined in modules
+what 'ClassSecurityInfo' objects do for methods defined in
+classes.  They allow module-level objects (generally functions) to
+be protected by security assertions.  This is most useful when
+attempting to allow through-the-web code to 'import' objects
+defined in a Python module.
+
+One major difference between 'ModuleSecurityInfo' objects and
+ClassSecurityInfo objects is that 'ModuleSecurityInfo' objects
+cannot be declared 'protected' by a permission.  Instead,
+ModuleSecurityInfo objects may only declare that an object is
+'public' or 'private'.  This is due to the fact that modules are
+essentially "placeless", global things, while permission
+protection depends heavily on "place" within Zope.
+
+Declaring Module Security
+-------------------------
+
+In order to use a filesystem Python module from restricted code such
+as Python Scripts, the module must have Zope security declarations
+associated with functions within it.  There are a number of ways to
+make these declarations:
+
+- By embedding the security declarations in the target module.  A
+  module that is written specifically for Zope may do so, whereas a
+  module not specifically written for Zope may not be able to do so.
+
+- By creating a wrapper module and embedding security declarations
+  within it.  In many cases it is difficult, impossible, or simply
+  undesirable to edit the target module.  If the number of objects in
+  the module that you want to protect or make public is small, you
+  may wish to simply create a wrapper module.  The wrapper module
+  imports objects from the wrapped module and provides security
+  declarations for them.
+
+- By placing security declarations in a filesystem Product.
+  Filesystem Python code, such as the '__init__.py' of a Product, can
+  make security declarations on behalf of an external module.  This
+  is also known as an "external" module security info declaration.
+
+The 'ModuleSecurityInfo' class is defined in the 'AccessControl'
+package of the Zope framework.
+
+Using ModuleSecurityInfo Objects
+--------------------------------
+
+  Instances of 'ModuleSecurityInfo' are used in two different
+  situations.  In embedded declarations, inside the module they
+  affect.  And in external declarations, made on behalf of a
+  module which may never be imported.
+
+Embedded ModuleSecurityInfo Declarations
+----------------------------------------
+
+An embedded ModuleSecurityInfo declaration causes an object in its
+module to be importable by through-the-web code.
+
+Here's an example of an embedded declaration::
+
+  from AccessControl import ModuleSecurityInfo
+  modulesecurity = ModuleSecurityInfo()
+  modulesecurity.declarePublic('foo')
+
+  def foo():
+      return "hello"
+      # foo
+
+  modulesecurity.apply(globals())
+
+When making embedded ModuleSecurityInfo declarations, you should
+instantiate a ModuleSecurityInfo object and assign it to a name.
+It's wise to use the recommended name 'modulesecurity' for
+consistency's sake.  You may then use the modulesecurity object's
+'declarePublic' method to declare functions inside of the current
+module as public.  Finally, appending the last line
+("modulesecurity.apply(globals())") is an important step.  It's
+necessary in order to poke the security machinery into action.  The
+above example declares the 'foo' function public.
+
+The name 'modulesecurity' is used for consistency and for the benefit
+of new component authors, who often learn from looking at other
+people's code.  You do not have to use the name 'modulesecurity' for
+the security infrastructure to recognize your assertion information,
+but it is recommended as a convention.
+
+External ModuleSecurityInfo Declarations
+----------------------------------------
+
+By creating a ModuleSecurityInfo instance with a module name
+argument, you can make declarations on behalf of a module without
+having to edit or import the module.
+
+Here's an example of an external declaration::
+
+   from AccessControl import ModuleSecurityInfo
+   # protect the 'foo' function within (yet-to-be-imported) 'foomodule'
+   ModuleSecurityInfo('foomodule').declarePublic('foo')
+
+This declaration will cause the following code to work within
+PythonScripts::
+
+   from foomodule import foo
+
+When making external ModuleSecurityInfo declarations, you needn't use
+the "modulesecurity.apply(globals())" idiom demonstrated in the
+embedded declaration section above.  As a result, you needn't assign
+the ModuleSecurityInfo object to the name 'modulesecurity'.
+
+Providing Access To A Module Contained In A Package
+---------------------------------------------------
+
+Note that if you want to provide access to a module inside of a
+package which lives in your PYTHONPATH, you'll need to provide
+security declarations for *all of the the packages and sub-packages
+along the path used to access the module.*
+
+For example, assume you have a function foo, which lives inside a
+module named 'module', which lives inside a package named 'package2',
+which lives inside a package named 'package1' You might declare the
+'foo' function public via this chain of declarations::
+
+  ModuleSecurityInfo('package1').declarePublic('package2')
+  ModuleSecurityInfo('package1.package2').declarePublic('module')
+  ModuleSecurityInfo('package1.package2.module').declarePublic('foo')
+
+Note that in the code above we took the following steps:
+
+- make a ModuleSecurityInfo object for 'package1'
+
+- call the declarePublic method of the 'package1'
+  ModuleSecurityInfo object, specifying 'package2' as what
+  we're declaring public.  This allows through the web code to
+  "see" package2 inside package1.
+
+- make a ModuleSecurityInfo object for 'package1.package2'.
+
+- call the declarePublic method of the 'package1.package2'
+  ModuleSecurityInfo object, specifying 'module' as what we're
+  declaring public.  This allows through the web code to "see"
+  'package1.package2.module'.
+
+- declare 'foo' public inside the ModuleSecurityInfo for
+  'package1.package2.module'. 
+
+Through-the-web code may now perform an import ala: 'import
+package1.package2.module.foo'
+
+Beware that Zope is buggy from 2.3 to 2.5.0b3.  If you make module
+security declarations in more than one Product, only one of the
+Products' security assertions will actually take effect.  This is
+repaired in Zope 2.5.0 and beyond.
+
+Many people who use Zope will be concerned with using
+ModuleSecurityInfo to make declarations on modules which live within
+Zope's Products directory.  This is just an example of declaring
+module security on a module within a package.  Here is an example of
+using ModuleSecurityInfo to make security declarations on behalf of
+the 'CatalogError' class in the 'ZCatalog.py' module.  This could be
+placed, for instance, within the any Product's '__init__.py' module::
+
+  from AccessControl import ModuleSecurityInfo
+  ModuleSecurityInfo('Products').declarePublic('Catalog')
+  ModuleSecurityInfo('Products.Catalog').declarePublic('CatalogError')
+
+Declaring Module Security On Modules Implemented In C
+-----------------------------------------------------
+
+Certain modules, such as the standard Python 'sha' module, provide
+extension types instead of classes, as the 'sha' module is
+implemented in C. Security declarations typically cannot be added to
+extension types, so the only way to use this sort of module is to
+write a Python wrapper class, or use External Methods.
+
+Default Module Security Info Declarations
+-----------------------------------------
+
+Through-the-web Python Scripts are by default able to import a small
+number of Python modules for which there are security
+declarations. These include 'string', 'math', and 'random'. The only
+way to make other Python modules available for import is to add
+security declarations to them in the filesystem.
+
+Utility Functions For Allowing Import of Modules By Through The Web Code
+------------------------------------------------------------------------
+
+Instead of manually providing security declarations for each function
+in a module, the utility function "allow_class" and "allow_module"
+have been created to help you declare the entire contents of a class
+or module as public.
+
+You can handle a module, such as base64, that contains only safe
+functions by writing 'allow_module("module_name")'.  For instance::
+
+  from Products.PythonScripts.Utility import allow_module
+  allow_module("base64")
+
+This statement declares all functions in the 'base64' module (
+'encode', 'decode', 'encodestring', and 'decodestring' ) as public,
+and from a script you will now be able to perform an import statement
+such as "from base64 import encodestring".
+
+
+To allow access to only some names in a module, you can eschew the
+allow_class and allow_module functions for the lessons you learned in
+the previous section and do the protection "manually"::
+
+  from AccessControl import ModuleSecurityInfo
+  ModuleSecurityInfo('module_name').declarePublic('name1','name2', ...)
+
+Making Permission Assertions On A Constructor
+---------------------------------------------
+
+When you develop a Python disk-based product, you will generally be
+required to make "constructor" methods for the objects which you wish
+to make accessible via the Zope management interface by users of your
+Product.  These constructors are usually defined within the modules
+which contain classes which are intended to be turned into Zope
+instances.  For more information on how constructors are used in Zope
+with security, see Chapter 3 "Zope Products".
+
+The Zope Product machinery "bootstraps" Product-based classes with
+proper constructors into the namespace of the Zope management
+interface "Add" list at Zope startup time.  This is done as a
+consequence of registering a class by way of the Product's
+'__init__.py' 'intialize' function.  If you want to make, for
+example, the imaginary 'FooClass' in your Product available from the
+"Add" list, you may construct an '__init__.py' file that looks much
+like this::
+
+      from FooProduct import FooClass
+
+      def initialize(context):
+          """ Initialize classes in the FooProduct module """
+          context.registerClass(
+              FooProduct.FooClass, # the class object
+              permission='Add FooClasses',
+              constructors=(FooProduct.manage_addFooClassForm,
+                            FooProduct.manage_addFooClass),
+              icon='foo.gif'
+              )
+
+The line of primary concern to us above is the one which says
+"permission='Add FooClasses'".  This is a permission declaration
+which, thanks to Zope product initialization, restricts the adding of
+FooClasses to those users who have the 'Add FooClasses' permission by
+way of a role association determined by the system administrator.
+
+If you do not include a 'permission' argument to 'registerClass',
+then Zope will create a default permission named 'Add [meta-type]s'.
+So, for example, if your object had a meta_type of 'Animal', then
+Zope would create a default permission, 'Add Animals'.  For the most
+part, it is much better to be explicit then to rely on Zope to take
+care of security details for you, so be sure to specify a permission
+for your object.
+
+Designing For Security
+======================
+
+"Security is hard." -- Jim Fulton.
+
+When you're under a deadline, and you "just want it to work", dealing
+with security can be difficult.  As a component developer, following
+these basic guidelines will go a long way toward avoiding problems
+with security integration. They also make a good debugging checklist!
+
+- Ensure that any class that needs to work with security has
+  'Acquisition.Implicit' or 'Acquisition.Explicit' somewhere in its
+  base class hierarchy.
+
+- Design the interface to your objects around methods; don't expect
+  clients to access instance attributes directly.
+
+- Ensure that all methods meant for use by restricted code have been
+  protected with appropriate security assertions.
+
+- Ensure that you called the global class initializer on all classes
+  that need to work with security.
+
+Compatibility
+=============
+
+The implementation of the security assertions and 'SecurityInfo'
+interfaces described in this document are available in Zope 2.3 and
+higher.
+
+Older Zope Products do not use the 'SecurityInfo' interfaces for
+security assertions, because these interfaces didn't exist at the
+time.  These Zope products will continue to work without modification
+until further notice.
+
+Using The RoleManager Base Class With Your Zope Product
+=======================================================
+
+After your Product is deployed, system managers and other users of
+your Product often must deal with security settings on instances they
+make from your classes.
+
+Product classes which inherit Zope's standard RoleManager base class
+allow instances of the class to present a security interface.  This
+security interface allows managers and developers of a site to
+control an instance's security settings via the Zope management
+interface.
+
+The user interface is exposed via the *Security* management view.
+From this view, a system administrator may secure instances of your
+Product's class by associating roles with permissions and by
+asserting that your object instance contains "local roles".  It also
+allows them to create "user-defined roles" within the Zope management
+framework in order to associate these roles with the permissions of
+your product and with users.  This user interface and its usage
+patterns are explained in more detail within the Zope Book's security
+chapter.
+
+If your Product's class does not inherit from 'RoleManager', its
+methods will still retain the security assertions associated with
+them, but you will be unable to allow users to associate roles with
+the permissions you've defined respective to instances of your class.
+Your objects will also not allow local role definitions.  Note that
+objects which inherit from the 'SimpleItem.SimpleItem' mixin class
+already inherit from 'RoleManager'.
+
+Conclusion
+==========
+
+Zope security is based upon roles and permissions. Users have
+roles. Security policies map permissions to roles. Classes protect
+methods with permissions. As a developer you main job is to protect
+your classes by associating methods with permissions. Of course there
+are many other details such as protecting modules and functions,
+creating security user interfaces, and initializing security
+settings.

Copied: zope2docs/trunk/zdgbook/TestingAndDebugging.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/TestingAndDebugging.rst)
===================================================================
--- zope2docs/trunk/zdgbook/TestingAndDebugging.rst	                        (rev 0)
+++ zope2docs/trunk/zdgbook/TestingAndDebugging.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,800 @@
+#####################
+Testing and Debugging
+#####################
+
+As you develop Zope applications you may run into problems.  This
+chapter covers debugging and testing techniques that can help you.
+The Zope debugger allow you to peek inside a running process and find
+exactly what is going wrong.  Unit testing allows you to automate the
+testing process to ensure that your code still works correctly as you
+change it.  Finally, Zope provides logging facilities which allow you
+to emit warnings and error messages.
+
+
+Debugging
+=========
+
+Zope provides debugging information through a number of sources.  It
+also allows you a couple avenues for getting information about Zope
+as it runs.
+
+The Control Panel
+-----------------
+
+The control panel provides a number of views that can help you debug
+Zope, especially in the area of performance.  The *Debugging
+Information* link on the control panel provides two views, *Debugging
+Info* and *Profiling*.
+
+Debugging info provides information on the number of object
+references and the status of open requests.  The object references
+list displays the name of the object and the number of references to
+that object in Zope.  Understanding how reference counts help
+debugging is a lengthy subject, but in general you can spot memory
+leaks in your application if the number of references to certain
+objects increases without bound.  The busier your site is, or the
+more content it holds, the more reference counts you will tend to
+have.
+
+Profiling uses the standard Python profiler.  This is turned on by
+setting the 'PROFILE_PUBLISHER' environment variable before executing
+Zope.
+
+When the profiler is running, the performance of your Zope system
+will suffer a lot.  Profiling should only be used for short periods
+of time, or on a separate ZEO client so that your normal users to not
+experience this significant penalty.
+
+Profiling provides you with information about which methods in your
+Zope system are taking the most time to execute.  It builds a
+*profile*, which lists the busiest methods on your system, sorted by
+increasing resource usage.  For details on the meaning of the
+profiler's output, read the `standard Python documentation
+<http://www.python.org/doc/current/lib/profile.html>`_
+
+Product Refresh Settings
+------------------------
+
+As of Zope 2.4 there is a *Refresh* view on all Control Panel
+Products.  Refresh allows you to reload your product's modules as you
+change them, rather than having to restart Zope to see your changes.
+The *Refresh* view provides the same debugging functionality
+previously provided by Shane Hathaway's Refresh Product.
+
+To turn on product refresh capabilities place a 'refresh.txt' file in
+your product's directory.  Then visit the *Refresh* view of your
+product in the management interface.  Here you can manually reload
+your product's modules with the *Refresh this product* button.  This
+allows you to immediately see the effect of your changes, without
+restarting Zope.  You can also turn on automatic refreshing which
+causes Zope to frequently check for changes to your modules and
+refresh your product when it detects that your files have changed.
+Since automatic refresh causes Zope to run more slowly, it is a good
+idea to only turn it on for a few products at a time.
+
+Debug Mode
+----------
+
+Setting the 'Z_DEBUG_MODE=1' environment puts Zope into debug mode.
+This mode reduces the performance of Zope a little bit.  Debug model
+has a number of wide ranging effects:
+
+- Tracebacks are shown on the browser when errors are raised.
+
+- External Methods and DTMLFile objects are checked to see if they
+  have been modified every time they are called.  If modified, they
+  are reloaded.
+
+- Zope will not fork into the background in debug mode, instead, it
+  will remain attached to the terminal that started it and the main
+  logging information will be redirected to that terminal.
+
+Normally, debug mode is set using the '-D' switch when starting Zope,
+though you can set the environment variable directly if you wish.
+
+By using debug mode and product refresh together you will have little
+reason to restart Zope while developing.
+
+The Python Debugger
+-------------------
+
+Zope is integrated with the Python debugger (pdb).  The Python
+debugger is pretty simple as command line debuggers go, and anyone
+familiar with other popular command line debuggers (like gdb) will
+feel right at home in pdb.
+
+For an introduction to pdb see the standard `pdb documentation
+<http://www.python.org/doc/current/lib/module-pdb.html>`_ .
+
+There are a number of ways to debug a Zope process:
+
+  o You can shut down the Zope server and simulate a request on the
+    command line.
+
+  o You can run a special ZEO client that debugs a running server.
+
+  o You can run Zope in debug model and enter the debugger
+    through Zope's terminal session.
+
+The first method is an easy way to debug Zope if you are not running
+ZEO.  First, you must first shut down the Zope process.  It is not
+possible to debug Zope in this way and run it at the same time.
+Starting up the debugger this way will by default start Zope in
+single threaded mode.
+
+For most Zope developer's purposes, the debugger is needed to debug
+some sort of application level programming error.  A common scenario
+is when developing a new product for Zope.  Products extend Zope's
+functionality but they also present the same kind of debugging
+problems that are commonly found in any programming environment.  It
+is useful to have an existing debugging infrastructure to help you
+jump immediately to your new object and debug it and play with it
+directly in pdb.  The Zope debugger lets you do this.
+
+In reality, the "Zope" part of the Zope debugger is actually just a
+handy way to start up Zope with some pre-configured break points and
+to tell the Python debugger where in Zope you want to start
+debugging.
+
+Simulating HTTP Requests
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now for an example. Remember, for this example to work, you *must*
+shut down Zope.  Go to your Zope's 'lib/python' directory and fire up
+Python and import 'Zope' and 'ZPublisher'::
+
+  $ cd lib/python
+  $ python
+  Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32
+  Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
+  >>> import Zope, ZPublisher
+  >>>
+
+Here you have run the Python interpreter (which is where using the
+debugger takes place) and imported two modules, 'Zope' and
+'ZPublisher'.  If Python complains about an 'ImportError' and not
+being able to find either module, then you are probably in the wrong
+directory, or you have not compiled Zope properly.  If you get this
+message::
+
+  ZODB.POSException.StorageSystemError: Could not lock the database
+  file.  There must be another process that has opened the file.
+
+This tells you that Zope is currently running.  Shutdown Zope and try
+again.
+
+The 'Zope' module is the main Zope application module.  When you
+import 'Zope' it sets up Zope.  'ZPublisher' is the Zope ORB.  See
+Chapter 2 for more information about 'ZPublisher'.
+
+You can use the 'ZPublisher.Zope' function to simulate an HTTP
+request.  Pass the function a URL relative the your root Zope object.
+Here is an example of how to simulate an HTTP request from the
+debugger::
+
+  >>> ZPublisher.Zope('')
+  Status: 200 OK
+  X-Powered-By: Zope (www.zope.org), Python (www.python.org)
+  Content-Length: 1238
+  Content-Type: text/html
+
+  <HTML><HEAD><TITLE>Zope</TITLE>
+
+    ... blah blah...
+
+  </BODY></HTML>
+  >>> 
+
+If you look closely, you will see that the content returned is
+*exactly* what is returned when you call your root level object
+through HTTP, including all the HTTP headers.
+
+Keep in mind that calling Zope this way does NOT involve a web
+server.  No ports are opened, the 'ZServer' code is not even
+imported.  In fact, this is just an interpreter front end to the same
+application code the ZServer *does* call.
+
+Interactive Debugging
+~~~~~~~~~~~~~~~~~~~~~
+
+Debugging involves publishing a request up to a point where you think
+it's failing, and then inspecting the state of your variables and
+objects.  The easy part is the actual inspection, the hard part is
+getting your program to stop at the right point.
+
+So, for the sake our example, let's say that you have a 'News' object
+which is defined in a Zope Product called 'ZopeNews', and is located
+in the 'lib/python/Products/ZopeNews' directory.  The class that
+defines the 'News' instance is also called 'News', and is defined in
+the 'News.py' module in your product.
+
+Therefore, from Zope's perspective the fully qualified name of your
+class is 'Products.ZopeNews.News.News'.  All Zope objects have this
+kind of fully qualified name.  For example, the 'ZCatalog' class can
+be found in 'Products.ZCatalog.ZCatalog.ZCatalog' (The redundancy is
+because the product, module, and class are all named 'ZCatalog').
+
+Now let's create an example method to debug.  You want your news
+object to have a 'postnews' method, that posts news::
+
+  class News(...):
+
+      ...
+
+      def postnews(self, news, author="Anonymous"):
+          self.news = news
+
+      def quote(self):
+          return '%s said, "%s"' % (self.author, self.news)
+
+You may notice that there's something wrong with the 'postnews'
+method.  The method assigns 'news' to an instance variable, but it
+does nothing with 'author'.  If the 'quote' method is called, it will
+raise an 'AttributeError' when it tries to look up the name
+'self.author'.  Although this is a pretty obvious goof, we'll use it
+to illustrate using the debugger to fix it.
+
+Running the debugger is done in a very similar way to how you called
+Zope through the python interpreter before, except that you introduce
+one new argument to the call to 'Zope'::
+
+  >>> ZPublisher.Zope('/News/postnews?new=blah', d=1)
+  * Type "s<cr>c<cr>" to jump to beginning of real publishing process.
+  * Then type c<cr> to jump to the beginning of the URL traversal
+    algorithm.
+  * Then type c<cr> to jump to published object call.
+  > <string>(0)?()
+  pdb> 
+
+Here, you call Zope from the interpreter, just like before, but there
+are two differences.  First, you call the 'postnews' method with an
+argument using the URL, '/News/postnews?new=blah'.  Second, you
+provided a new argument to the Zope call, 'd=1'.  The 'd' argument,
+when true, causes Zope to fire up in the Python debugger, pdb.
+Notice how the Python prompt changed from '>>>' to 'pdb>'.  This
+indicates that you are in the debugger.
+
+When you first fire up the debugger, Zope gives you a helpful message
+that tells you how to get to your object.  To understand this
+message, it's useful to know how you have set Zope up to be debugged.
+When Zope fires up in debugger mode, there are three breakpoints set
+for you automatically (if you don't know what a breakpoint is, you
+need to read the python `debugger documentation
+<http://www.python.org/doc/current/lib/module-pdb.html>`_).
+
+The first breakpoint stops the program at the point that ZPublisher
+(the Zope ORB) tries to publish the application module (in this case,
+the application module is 'Zope').  The second breakpoint stops the
+program right before ZPublisher tries to traverse down the provided
+URL path (in this case, '/News/postnews').  The third breakpoint will
+stop the program right before ZPublisher calls the object it finds
+that matches the URL path (in this case, the 'News' object).
+
+So, the little blurb that comes up and tells you some keys to press
+is telling you these things in a terse way.  Hitting 's' will *step*
+you into the debugger, and hitting 'c' will *continue* the execution
+of the program until it hits a breakpoint.
+
+Note however that none of these breakpoints will stop the program at
+'postnews'.  To stop the debugger right there, you need to tell the
+debugger to set a new breakpoint.  Why a new breakpoint?  Because
+Zope will stop you before it traverse your objects path, it will stop
+you before it calls the object, but if you want to stop it *exactly*
+at some point in your code, then you have to be explicit.  Sometimes
+the first three breakpoints are convienent, but often you need to set
+your own special break point to get you exactly where you want to go.
+
+Setting a breakpoint is easy (and see the next section for an even
+easier method).  For example::
+
+  pdb> import Products
+  pdb> b Products.ZopeNews.News.News.postnews
+  Breakpoint 5 at C:\Program Files\WebSite\lib\python\Products\ZopeNews\News.py:42
+  pdb> 
+
+First, you import 'Products'.  Since your module is a Zope product,
+it can be found in the 'Products' package.  Next, you set a new
+breakpoint with the *break* debugger command (pdb allows you to use
+single letter commands, but you could have also used the entire word
+'break').  The breakpoint you set is
+'Products.ZopeNews.News.News.postnews'.  After setting this
+breakpoint, the debugger will respond that it found the method in
+question in a certain file, on a certain line (in this case, the
+fictitious line 42) and return you to the debugger.
+
+Now, you want to get to your 'postnews' method so you can start
+debugging it.  But along the way, you must first *continue* through
+the various breakpoints that Zope has set for you.  Although this may
+seem like a bit of a burden, it's actually quite good to get a feel
+for how Zope works internally by getting down the rhythm that Zope
+uses to publish your object.  In these next examples, my comments
+will begin with '#".  Obviously, you won't see these comments when
+you are debugging.  So let's debug::
+
+  pdb> s
+  # 's'tep into the actual debugging
+
+  > <string>(1)?()
+  # this is pdb's response to being stepped into, ignore it
+
+  pdb> c
+  # now, let's 'c'ontinue onto the next breakpoint
+
+  > C:\Program Files\WebSite\lib\python\ZPublisher\Publish.py(112)publish()
+  -> def publish(request, module_name, after_list, debug=0,
+
+  # pdb has stopped at the first breakpoint, which is the point where
+  # ZPubisher tries to publish the application module.
+
+  pdb> c
+  # continuing onto the next breakpoint you get...
+
+  > C:\Program Files\WebSite\lib\python\ZPublisher\Publish.py(101)call_object()
+  -> def call_object(object, args, request):
+
+Here, 'ZPublisher' (which is now publishing the application) has
+found your object and is about to call it.  Calling your object
+consists of applying the arguments supplied by 'ZPublisher' to the
+object.  Here, you can see how 'ZPublisher' is passing three
+arguments into this process.  The first argument is 'object' and is
+the actual object you want to call.  This can be verified by
+*printing* the object::
+
+  pdb> p object
+  <News instance at 00AFE410>
+
+Now you can inspect your object (with the *print* command) and even
+play with it a bit.  The next argument is 'args'.  This is a tuple of
+arguments that 'ZPublisher' will apply to your object call.  The
+final argument is 'request'.  This is the request object and will
+eventually be transformed in to the DTML usable object 'REQUEST'. Now
+continue, your breakpoint is next::
+
+  pdb> c    
+  > C:\Program Files\WebSite\lib\python\Products\ZopeNews\News.py(42)postnews()
+  -> def postnews(self, N)
+
+Now you are here, at your method.  To be sure, tell the debugger to
+show you where you are in the code with the 'l' command.  Now you can
+examine variable and perform all the debugging tasks that the Python
+debugger provides.  From here, with a little knowledge of the Python
+debugger, you should be able to do any kind of debugging task that is
+needed.
+
+Interactive Debugging Triggered From the Web
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you are running in debug mode you can set break points in your
+code and then jump straight to the debugger when Zope comes across
+your break points.  Here's how to set a breakpoint::
+
+  import pdb;pdb.set_trace()
+
+Now start Zope in debug mode and point your web browser at a URL that
+causes Zope to execute the method that includes a breakpoint.  When
+this code is executed, the Python debugger will come up in the
+terminal where you started Zope.  Also note that from your web
+browser it looks like Zope is frozen.  Really it's just waiting for
+you do your debugging.
+
+From the terminal you are inside the debugger as it is executing your
+request.  Be aware that you are just debugging one thread in Zope,
+and other requests may be being served by other threads.  If you go
+to the *Debugging Info* screen while in the debugger, you can see
+your debugging request and how long it has been open.
+
+It is often more convenient to use this method to enter the debugger
+than it is to call 'ZPublisher.Zope' as detailed in the last section.
+
+Post-Mortem Debugging
+~~~~~~~~~~~~~~~~~~~~~
+
+Often, you need to use the debugger to chase down obscure problems in
+your code, but sometimes, the problem is obvious, because an
+exception gets raised.  For example, consider the following method on
+your 'News' class::
+
+  def quote(self):
+      return '%s said, "%s"' % (self.Author, self.news)
+
+Here, you can see that the method tries to substitute 'self.Author'
+in a string, but earlier we saw that this should really be
+'self.author'.  If you tried to run this method from the command
+line, an exception would be raised::
+
+  >>> ZPublisher.Zope('/News/quote')
+  Traceback (most recent call last):
+    File "<stdin>", line 1, in ?
+    File "./News.py", line 4, in test
+      test2()
+    File "./News.py", line 3, in test2
+      return '%s said, "%s"' % (self.Author, self.news)
+  NameError: Author
+  >>>
+
+Using Zope's normal debugging methods, you would typically need to
+start from the "beginning" and step your way down through the
+debugger to find this error (in this case, the error is pretty
+obvious, but more often than not errors can be pretty obscure!).
+
+Post-mortem debugging allows you to jump *directly* to the spot in
+your code that raised the exception, so you do not need to go through
+the possibly tedious task of stepping your way through a sea of
+Python code.  In the case of our example, you can just pass
+'ZPublisher.Zope' call a 'pm' argument that is set to 1::
+
+          >>> ZPublisher.Zope('/News/quote', pm=1)
+          Traceback (most recent call last):
+            File "<stdin>", line 1, in ?
+            File "./News.py", line 4, in test
+              test2()
+            File "./News.py", line 3, in test2
+              return '%s said, "%s"' % (self.Author, self.news)
+          NameError: Author
+          (pdb)
+
+Here, you can see that instead of taking you back to a python prompt,
+the post mortem debugging flag has caused you to go right into the
+debugging, *exactly* at the point in your code where the exception is
+raised.  This can be verified with the debugger's (l)ist
+command. Post mortem debugging offers you a handy way to jump right
+to the section of your code that is failing in some obvious way by
+raising an exception.
+
+Debugging With ZEO
+~~~~~~~~~~~~~~~~~~
+
+ZEO presents some interesting debugging abilities.  ZEO lets you
+debug one ZEO client when other clients continue to server requests
+for your site.  In the above examples, you have to shut down Zope to
+run in the debugger, but with ZEO, you can debug a production site
+while other clients continue to serve requests. Using ZEO is beyond
+the scope of this chapter. However, once you have ZEO running, you
+can debug a client process exactly as you debug a single-process
+Zope.
+
+
+Unit Testing
+============
+
+Unit testing allows you to automatically test your classes to make
+sure they are working correctly. By using unit tests you can make
+sure as you develop and change your classes that you are not breaking
+them. Zope comes with Pyunit. You can find out more information on
+Pyunit at `the Pyunit home page <http://pyunit.sourceforge.net/>`_
+. Pyunit is also part of the Python `standard library
+<http://www.python.org/doc/lib/module-unittest.html>`_ as of Python
+2.1.
+
+
+What Are Unit Tests
+-------------------
+
+A "unit" may be defined as a piece of code with a single intended
+purpose.  A "unit test" is defined as a piece of code which exists
+to codify the intended behavior of a unit and to compare its
+intended behavior against its actual behavior.
+
+Unit tests are a way for developers and quality assurance engineers
+to quickly ascertain whether independent units of code are working as
+expected.  Unit tests are generally written at the same time as the
+code they are intended to test.  A unit testing framework allows a
+collection of unit tests to be run without human intervention,
+producing a minimum of output if all the tests in the collection are
+successful.
+
+It's a good idea to have a sense of the limits of unit testing.  From
+the `Extreme Programming Enthusiast website
+<http://c2.com/cgi/wiki?UnitTestsDefined>`_ here is a list of things
+that unit tests are *not*:
+
+- Manually operated.
+
+- Automated screen-driver tests that simulate user input (these are
+  "functional tests").
+
+- Interactive.  They run "no questions asked."
+
+- Coupled.  They run without dependencies except those native to the
+  thing being tested.
+
+- Complicated.  Unit test code is typically straightforward
+  procedural code that simulates an event.
+
+Writing Unit Tests
+------------------
+
+Here are the times when you should write unit tests:
+
+* When you write new code
+
+* When you change and enhance existing code
+
+* When you fix bugs
+
+It's much better to write tests when you're working on code than to
+wait until you're all done and then write tests.
+
+You should write tests that exercise discrete "units" of
+functionality.  In other words, write simple, specific tests that
+test one capability.  A good place to start is with interfaces and
+classes.  Classes and especially interfaces already define units of
+work which you may wish to test.
+
+Since you can't possibly write tests for every single capability and
+special case, you should focus on testing the riskiest parts of your
+code.  The riskiest parts are those that would be the most disastrous
+if they failed.  You may also want to test particularly tricky or
+frequently changed things.
+
+Here's an example test script that tests the 'News' class defined
+earlier in this chapter::
+
+  import unittest
+  import News
+
+  class NewsTest(unittest.TestCase):
+
+      def testPost(self):
+          n=News()
+          s='example news'
+          n.postnews(s)
+          assert n.news==s
+
+      def testQuote(self):
+          n=News()
+          s='example news'
+          n.postnews(s)
+          assert n.quote()=='Anonymous said: "%s"' % s
+          a='Author'
+          n.postnews(s, a)
+          assert n.quote()=='%s said: "%s"' % (a, s)
+
+  def test_suite():
+     return unittest.makeSuite(NewsTest, 'news test')
+
+  def main():
+     unittest.TextTestRunner().run(test_suite())
+
+  if __name__=="__main__":
+      main()
+
+You should save tests inside a 'tests' sub-directory in your
+product's directory. Test scripts file names should start with test,
+for example 'testNews.py'. You may accumulate many test scripts in
+your product's 'tests' directory.  You can run test your product by
+running the test scripts.
+
+We cannot cover all there is to say about unit testing here. Take a
+look at the Pyunit `documentation
+<http://pyunit.sourceforge.net/pyunit.html>`_ for more background on
+unit testing.
+
+Zope Test Fixtures
+------------------
+
+One issue that you'll run into when unit testing is that you may need
+to set up a Zope environment in order to test your products.  You can
+solve this problem in two ways.  First, you can structure your
+product so that much of it can be tested without Zope (as you did in
+the last section).  Second, you can create a test fixture that sets
+up a Zope environment for testing.
+
+To create a test fixture for Zope you'll need to:
+
+1. Add Zope's 'lib/python' directory to the Python path.
+
+2. Import 'Zope' and any other needed Zope modules and packages.
+
+3. Get a Zope application object.
+
+4. Do your test using the application object.
+
+5. Clean up the test by aborting or committing the transaction and
+   closing the Zope database connection.
+
+Here's an example Zope test fixture that demonstrates how to do each
+of these steps::
+
+  import os, os.path, sys, string
+  try:
+      import unittest
+  except ImportError:
+      fix_path()
+      import unittest
+
+  class MyTest(unittest.TestCase):
+
+      def setUp(self):
+          # Get the Zope application object and store it in an
+          # instance variable for use by test methods
+          import Zope
+          self.app=Zope.app()
+
+      def tearDown(self):
+          # Abort the transaction and shut down the Zope database
+          # connection.
+          get_transaction().abort()
+          self.app._p_jar.close()
+
+      # At this point your test methods can perform tests using
+      # self.app which refers to the Zope application object.
+
+      ...
+
+  def fix_path():
+      # Add Zope's lib/python directory to the Python path
+      file=os.path.join(os.getcwd(), sys.argv[0])
+      dir=os.path.join('lib', 'python')
+      i=string.find(file, dir)
+      sys.path.insert(0, file[:i+len(dir)])
+
+  def test_suite():
+     return unittest.makeSuite(MyTest, 'my test')
+
+  def main():
+     unittest.TextTestRunner().run(test_suite())
+
+  if __name__=="__main__":
+      fix_path()
+      main()
+
+This example shows a fairly complete Zope test fixture.  If your Zope
+tests only needs to import Zope modules and packages you can skip
+getting a Zope application object and closing the database
+transaction.
+
+Some times you may run into trouble if your test assuming that there
+is a current Zope request.  There are two ways to deal with this.
+One is to use the 'makerequest' utility module to create a fake
+request.  For example::
+
+  class MyTest(unittest.TestCase):
+      ...
+
+      def setup(self):
+          import Zope
+          from Testing import makerequest
+          self.app=makerequest.makerequest(Zope.app())
+
+This will create a Zope application object that is wrapped in a
+request.  This will enable code that expects to acquire a 'REQUEST'
+attribute work correctly.
+
+Another solution to testing methods that expect a request is to use
+the 'ZPublisher.Zope' function described earlier.  Using this
+approach you can simulate HTTP requests in your unit tests.  For
+example::
+
+  import ZPublisher
+
+  class MyTest(unittest.TestCase):
+      ...
+
+      def testWebRequest(self):
+          ZPublisher.Zope('/a/url/representing/a/method?with=a&couple=arguments',
+                          u='username:password', 
+                          s=1, 
+                          e={'some':'environment', 'variable':'settings'})
+
+If the 's' argument is passed to 'ZPublisher.Zope' then no output
+will be sent to 'sys.stdout'.  If you want to capture the output of
+the publishing request and compare it to an expected value you'll
+need to do something like this::
+
+  f=StringIO()
+  temp=sys.stdout
+  sys.stdout=f
+  ZPublisher.Zope('/myobject/mymethod')
+  sys.stdout=temp
+  assert f.getvalue() == expected_output
+
+Here's a final note on unit testing with a Zope test fixture: you may
+find Zope helpful.  ZEO allows you to test an application while it
+continues to serve other users.  It also speeds Zope start up time
+which can be a big relief if you start and stop Zope frequently while
+testing.
+
+Despite all the attention we've paid to Zope testing fixtures, you
+should probably concentrate on unit tests that don't require a Zope
+test fixture.  If you can't test much without Zope there is a good
+chance that your product would benefit from some refactoring to make
+it simpler and less dependent on the Zope framework.
+
+Logging
+=======
+
+Zope provides a framework for logging information to Zope's
+application log.  You can configure Zope to write the application log
+to a file, syslog, or other back-end.
+
+The logging API defined in the 'zLOG' module.  This module provides
+the 'LOG' function which takes the following required arguments:
+
+- subsystem -- The subsystem generating the message (e.g. "ZODB")
+
+- severity -- The "severity" of the event.  This may be an integer or
+  a floating point number.  Logging back ends may consider the int()
+  of this value to be significant.  For example, a back-end may
+  consider any severity whose integer value is WARNING to be a
+  warning.
+
+- summary -- A short summary of the event
+
+These arguments to the 'LOG' function are optional:
+
+- detail -- A detailed description
+
+- error -- A three-element tuple consisting of an error type, value,
+  and traceback.  If provided, then a summary of the error is added
+  to the detail.
+
+- reraise -- If provided with a true value, then the error given by
+  error is reraised.
+
+You can use the 'LOG' function to send warning and errors to the Zope
+application log.
+
+Here's an example of how to use the 'LOG' function to write debugging
+messages::
+
+  from zLOG import LOG, DEBUG
+  LOG('my app', DEBUG, 'a debugging message')
+
+You can use 'LOG' in much the same way as you would use print
+statements to log debugging information while Zope is running.  You
+should remember that Zope can be configured to ignore log messages
+below certain levels of severity.  If you are not seeing your logging
+messages, make sure that Zope is configured to write them to the
+application log.
+
+In general the debugger is a much more powerful way to locate
+problems than using the logger.  However, for simple debugging tasks
+and for issuing warnings the logger works just fine.
+
+Other Testing and Debugging Facilities
+======================================
+
+There is a few other testing and debugging techniques and tools not
+commonly used to test Zope.  In this section we'll mention several of
+them.
+
+Debug Logging
+-------------
+
+Zope provides an analysis tool for debugging log output.  This output
+allows may give you hints as to where your application may be
+performing poorly, or not responding at all.  For example, since
+writing Zope products lets your write unrestricted Python code, it's
+very possibly to get yourself in a situation where you "hang" a Zope
+request, possibly by getting into a infinite loop.
+
+To try and detect at which point your application hangs, use the
+*requestprofiler.py* script in the *utilities* directory of your Zope
+installation.  To use this script, you must run Zope with the '-M'
+command line option.  This will turn on "detailed debug logging" that
+is necessary for the *requestprofiler.py* script to run.  The
+*requestprofiler.py* script has quite a few options which you can
+learn about with the '--help' switch.
+
+In general debug log analysis should be a last resort.  Use it when
+Zope is hanging and normal debugging and profiling is not helping you
+solve your problem.
+
+HTTP Benchmarking
+-----------------
+
+HTTP load testing is notoriously inaccurate.  However, it is useful
+to have a sense of how many requests your server can support.  Zope
+does not come with any HTTP load testing tools, but there are many
+available.  Apache's 'ab' program is a widely used free tool that can
+load your server with HTTP requests.
+
+Summary
+=======
+
+Zope provides a number of different debugging and testing facilities.
+The debugger allows you to interactively test your applications.
+Unit tests allow help you make sure that your application is develops
+correctly.  The logger allows you to do simple debugging and issue
+warnings.

Copied: zope2docs/trunk/zdgbook/ZODBPersistentComponents.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/ZODBPersistentComponents.rst)
===================================================================
--- zope2docs/trunk/zdgbook/ZODBPersistentComponents.rst	                        (rev 0)
+++ zope2docs/trunk/zdgbook/ZODBPersistentComponents.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,596 @@
+##########################
+ZODB Persistent Components
+##########################
+
+Most Zope components live in the Zope Object DataBase (ZODB).
+Components that are stored in ZODB are said to be *persistent*.
+Creating persistent components is, for the most part, a trivial
+exercise, but ZODB does impose a few rules that persistent components
+must obey in order to work properly.  This chapter describes the
+persistence model and the interfaces that persistent objects can use
+to live inside the ZODB.
+
+Persistent Objects
+==================
+
+Persistent objects are Python objects that live for a long time. Most
+objects are created when a program is run and die when the program
+finishes. Persistent objects are not destroyed when the program ends,
+they are saved in a database.
+
+A great benefit of persistent objects is their transparency.  As a
+developer, you do not need to think about loading and unloading the
+state of the object from memory.  Zope's persistent machinery handles
+all of that for you.
+
+This is also a great benefit for application designers; you do not
+need to create your own kind of "data format" that gets saved to a
+file and reloaded again when your program stops and starts.  Zope's
+persistence machinery works with *any* kind of Python objects (within
+the bounds of a few simple rules) and as your types of objects grow,
+your database simply grows transparently with it.
+
+Persistence Example
+-------------------
+
+Here is a simple example of using ZODB outside of Zope.  If all you
+plan on doing is using persistent objects with Zope, you can skip
+this section if you wish.
+
+The first thing you need to do to start working with ZODB is to
+create a "root object".  This process involves first opening a
+"storage" , which is the actual backend storage location for your
+data.
+
+ZODB supports many pluggable storage back-ends, but for the purposes
+of this article we're going to show you how to use the 'FileStorage'
+back-end storage, which stores your object data in a file.  Other
+storages include storing objects in relational databases, Berkeley
+databases, and a client to server storage that stores objects on a
+remote storage server.
+
+
+To set up a ZODB, you must first install it.  ZODB comes with Zope,
+so the easiest way to install ZODB is to install Zope and use the
+ZODB that comes with your Zope installation.  For those of you who
+don't want all of Zope, but just ZODB, see the instructions for
+downloading ZODB from the `ZODB web page
+<http://wiki.zope.org/ZODB>`_.
+
+After installing ZODB, you can start to experiment with it right from
+the Python command line interpreter.  If you've installed Zope,
+before running this set of commands, shut down your Zope server, and
+"cd" to the "lib/python" directory of your Zope instance.  If you're
+using a "standalone" version of ZODB, you likely don't need to do
+this, and you'll be able to use ZODB by importing it from a standard
+Python package directory.  In either case, try the following set of
+commands::
+
+  chrism at saints:/opt/zope/lib/python$ python
+  Python 2.1.1 (#1, Aug  8 2001, 21:17:50) 
+  [GCC 2.95.2 20000220 (Debian GNU/Linux)] on linux2
+  Type "copyright", "credits" or "license" for more information. 
+  >>> from ZODB import FileStorage, DB
+  >>> storage = FileStorage.FileStorage('mydatabase.fs')
+  >>> db = DB( storage )
+  >>> connection = db.open()
+  >>> root = connection.root()
+
+Here, you create storage and use the 'mydatabse.fs' file to store the
+object information.  Then, you create a database that uses that
+storage.
+
+
+Next, the database needs to be "opened" by calling the 'open()'
+method.  This will return a connection object to the database.  The
+connection object then gives you access to the 'root' of the database
+with the 'root()' method.
+
+The 'root' object is the dictionary that holds all of your persistent
+objects.  For example, you can store a simple list of strings in the
+root object::
+
+      root['employees'] = ['Bob', 'Mary', 'Jo']
+
+Now, you have changed the persistent database by adding a new object,
+but this change is so far only temporary.  In order to make the
+change permanent, you must commit the current transaction::
+
+      get_transaction().commit()
+
+Transactions are ways to make a lot of changes in one atomic
+operation.  In a later article, we'll show you how this is a very
+powerful feature.  For now, you can think of committing transactions
+as "checkpoints" where you save the changes you've made to your
+objects so far.  Later on, we'll show you how to abort those changes,
+and how to undo them after they are committed.
+
+If you had used a relational database, you would have had to issue a
+SQL query to save even a simple python list like the above example.
+You would have also needed some code to convert a SQL query back into
+the list when you wanted to use it again.  You don't have to do any
+of this work when using ZODB.  Using ZODB is almost completely
+transparent, in fact, ZODB based programs often look suspiciously
+simple!
+
+Working with simple python types is useful, but the real power of
+ZODB comes out when you store your own kinds of objects in the
+database.  For example, consider a class that represents a employee::
+
+  from Persistence import Persistent
+
+  class Employee(Persistent):
+
+      def setName(self, name):
+          self.name = name
+
+
+Calling 'setName' will set a name for the employee.  Now, you can put
+Employee objects in your database::
+
+  for name in ['Bob', 'Mary', 'Joe']:
+      employee = Employee()
+      employee.setName(name)
+      root['employees'].append(employee)
+
+  get_transaction().commit()
+
+Don't forget to call 'commit()', so that the changes you have made so
+far are committed to the database, and a new transaction is begun.
+
+Persistent Rules
+================
+
+There are a few rules that must be followed when your objects are
+persistent.
+
+- Your objects, and their attributes, must be "pickleable".
+
+- Your object cannot have any attributes that begin with '_p_'.
+
+- Attributes of your object that begin with '_v_' are "volatile" and
+  are not saved to the database (see next section).
+
+- You must explicitly signal any changes made to mutable attributes
+  (such as instances, lists, and dictionaries) or use persistent
+  versions of mutable objects, like 'ZODB.PersistentMapping' (see
+  below for more information on 'PersistentMapping'.)
+
+In this section, we'll look at each of these special rules one by
+one.
+
+The first rules says that your objects must be pickleable.  This
+means that they can be serialized into a data format with the
+"pickle" module.  Most python data types (numbers, lists,
+dictionaries) can be pickled.  Code objects (method, functions,
+classes) and file objects (files, sockets) *cannot* be pickled.
+Instances can be persistent objects if:
+
+- They subclass 'Persistence.Persistent'
+
+- All of their attributes are pickleable
+
+The second rule is that none of your objects attributes can begin
+with '_p_'.  For example, '_p_b_and_j' would be an illegal object
+attribute.  This is because the persistence machinery reserves all of
+these names for its own purposes.
+
+The third rule is that all object attributes that begin with '_v_'
+are "volatile" and are not saved to the database.  This means that as
+long as the persistent object is in Zope memory cache, volatile
+attributes can be used.  When the object is deactivated (removed from
+memory) volatile attributes are thrown away.
+
+Volatile attributes are useful for data that is good to cache for a
+while but can often be thrown away and easily recreated.  File
+connections, cached calculations, rendered templates, all of these
+kinds of things are useful applications of volatile attributes. You
+must exercise care when using volatile attributes.  Since you have
+little control over when your objects are moved in and out of memory,
+you never know when your volatile attributes may disappear.
+
+The fourth rule is that you must signal changes to mutable types.
+This is because persistent objects can't detect when mutable types
+change, and therefore, doesn't know whether or not to save the
+persistent object or not.
+
+For example, say you had a list of names as an attribute of your
+object called 'departments' that you changed in a method called
+'addDepartment'::
+
+  class DepartmentManager(Persistent):
+
+      def __init__(self):
+          self.departments = []
+
+      def addDepartment(self, department):
+          self.departments.append(department)
+
+When you call the 'addDepartment' method you change a mutable type,
+'departments' but your persistent object will not save that change.
+
+There are two solutions to this problem.  First, you can assign a
+special flag, '_p_changed'::
+
+  def addDepartment(self, department):
+      self.department.append(department)
+      self._p_changed = 1
+
+Remember, '_p_' attributes do something special to the persistence
+machinery and are reserved names. Assigning 1 to '_p_changed' tells
+the persistence machinery that you changed the object, and that it
+should be saved.
+
+Another technique is to use the mutable attribute as though it were
+immutable. In other words, after you make changes to a mutable
+object, reassign it::
+
+  def addDepartment(self, department):
+      departments = self.departments
+      departments.append(department)
+      self.department = departments
+
+Here, the 'self.departments' attribute was re-assigned at the end of
+the function to the "working copy" object 'departments'.  This
+technique is cleaner because it doesn't have any explicit
+'_p_changed' settings in it, but this implicit triggering of the
+persistence machinery should always be understood, otherwise use the
+explicit syntax.
+
+A final option is to use persistence-aware mutable attributes such as
+'PersistentMapping', and 'IOBTree'. 'PersistentMapping' is a mapping
+class that notifies ZODB when you change the mapping. You can use
+instances of 'PersistentMapping' in place of standard Python
+dictionaries and not worry about signaling change by reassigning the
+attribute or using '_p_changed'. Zope's Btree classes are also
+persistent-aware mutable containers. This solution can be cleaner
+than using mutable objects immutably, or signaling change manually
+assuming that there is a persistence-aware class available that meets
+your needs.
+
+Transactions and Persistent Objects
+===================================
+
+When changes are saved to ZODB, they are saved in a *transaction*.
+This means that either all changes are saved, or none are saved.  The
+reason for this is data consistency.  Imagine the following scenario:
+
+1. A user makes a credit card purchase at the sandwich.com website.
+
+2. The bank debits their account.
+
+3. An electronic payment is made to sandwich.com.
+
+Now imagine that an error happens during the last step of this
+process, sending the payment to sandwich.com.  Without transactions,
+this means that the account was debited, but the payment never went
+to sandwich.com!  Obviously this is a bad situation.  A better
+solution is to make all changes in a transaction:
+
+1. A user makes a credit card purchase at the sandwich.com website.
+
+2. The transaction begins
+
+3. The bank debits their account.
+
+4. An electronic payment is made to sandwich.com.
+
+5. The transaction commits
+
+Now, if an error is raised anywhere between steps 2 and 5, *all*
+changes made are thrown away, so if the payment fails to go to
+sandwich.com, the account won't be debited, and if debiting the
+account raises an error, the payment won't be made to sandwich.com,
+so your data is always consistent.
+
+When using your persistent objects with Zope, Zope will automatically
+*begin* a transaction when a web request is made, and *commit* the
+transaction when the request is finished.  If an error occurs at any
+time during that request, then the transaction is *aborted*, meaning
+all the changes made are thrown away.
+
+If you want to *intentionally* abort a transaction in the middle of a
+request, then just raise an error at any time.  For example, this
+snippet of Python will raise an error and cause the transaction to
+abort::
+
+  raise SandwichError('Not enough peanut butter.')
+
+A more likely scenario is that your code will raise an exception when
+a problem arises. The great thing about transactions is that you
+don't have to include cleanup code to catch exceptions and undo
+everything you've done up to that point. Since the transaction is
+aborted the changes made in the transaction will not be saved.
+
+Because Zope does transaction management for you, most of the time
+you do not need to explicitly begin, commit or abort your own
+transactions.  For more information on doing transaction management
+manually, see the links at the end of this chapter that lead to more
+detailed tutorials of doing your own ZODB programming.
+
+
+Subtransactions
+---------------
+
+Zope waits until the transaction is committed to save all the changes
+to your objects.  This means that the changes are saved in memory.
+If you try to change more objects than you have memory in your
+computer, your computer will begin to swap and thrash, and maybe even
+run you out of memory completely.  This is bad. The easiest solution
+to this problem is to not change huge quantities of data in one
+transaction.
+
+If you need to spread a transaction out of lots of data, however, you
+can use subtransactions.  Subtransactions allow you to manage Zope's
+memory usage yourself, so as to avoid swapping during large
+transactions.
+
+Subtransactions allow you to make huge transactions. Rather than
+being limited by available memory, you are limited by available disk
+space.  Each subtransaction commit writes the current changes out to
+disk and frees memory to make room for more changes.
+
+To commit a subtransaction, you first need to get a hold of a
+transaction object.  Zope adds a function to get the transaction
+objects in your global namespace, 'get_transaction', and then call
+'commit(1)' on the transaction::
+
+  get_transaction().commit(1)
+
+You must balance speed, memory, and temporary storage concerns when
+deciding how frequently to commit subtransactions. The more
+subtransactions, the less memory used, the slower the operation, and
+the more temporary space used. Here's and example of how you might
+use subtransactions in your Zope code::
+
+  tasks_per_subtransaction = 10
+  i = 0
+  for task in tasks:
+      process(task)
+      i = i + 1
+      if i % tasks_per_subtransaction == 0:
+          get_transaction().commit(1)
+
+This example shows how to commit a subtransaction at regular
+intervals while processing a number of tasks.
+
+Threads and Conflict Errors
+---------------------------
+
+Zope is a multi-threaded server.  This means that many different
+clients may be executing your Python code in different threads.  For
+most cases, this is not an issue and you don't need to worry about
+it, but there are a few cases you should look out for.
+
+The first case involves threads making lots of changes to objects and
+writing to the database.  The way ZODB and threading works is that
+each thread that uses the database gets its own *connection* to the
+database.  Each connection gets its own *copy* of your object.  All
+of the threads can read and change any of the objects.  ZODB keeps
+all of these objects synchronized between the threads. The upshot is
+that you don't have to do any locking or thread synchronization
+yourself. Your code can act as though it is single threaded.
+
+However, synchronization problems can occur when objects are changed
+by two different threads at the same time.
+
+Imagine that thread 1 gets its own copy of object A, as does thread
+2.  If thread 1 changes its copy of A, then thread 2 will not see
+those changes until thread 1 commits them.  In cases where lots of
+objects are changing, this can cause thread 1 and 2 to try and commit
+changes to object 1 at the same time.
+
+When this happens, ZODB lets one transaction do the commit (it
+"wins") and raises a 'ConflictError' in the other thread (which
+"looses"). The looser can elect to try again, but this may raise yet
+another 'ConflictError' if many threads are trying to change object
+A. Zope does all of its own transaction management and will retry a
+losing transaction three times before giving up and raising the
+'ConflictError' all the way up to the user.
+
+
+Resolving Conflicts
+-------------------
+
+If a conflict happens, you have two choices. The first choice is that
+you live with the error and you try again. Statistically, conflicts
+are going to happen, but only in situations where objects are
+"hot-spots".  Most problems like this can be "designed away"; if you
+can redesign your application so that the changes get spread around
+to many different objects then you can usually get rid of the hot
+spot.
+
+
+Your second choice is to try and *resolve* the conflict. In many
+situations, this can be done. For example, consider the following
+persistent object::
+
+  class Counter(Persistent):
+
+      self.count = 0
+
+      def hit(self):
+          self.count = self.count + 1
+
+This is a simple counter.  If you hit this counter with a lot of
+requests though, it will cause conflict errors as different threads
+try to change the count attribute simultaneously.
+
+But resolving the conflict between conflicting threads in this case
+is easy.  Both threads want to increment the self.count attribute by
+a value, so the resolution is to increment the attribute by the sum
+of the two values and make both commits happy; no 'ConflictError' is
+raised.
+
+
+To resolve a conflict, a class should define an '_p_resolveConflict'
+method. This method takes three arguments.
+
+'oldState' -- The state of the object that the changes made by the
+current transaction were based on. The method is permitted to modify
+this value.
+
+'savedState' -- The state of the object that is currently stored in
+the database. This state was written after 'oldState' and reflects
+changes made by a transaction that committed before the current
+transaction. The method is permitted to modify this value.
+
+'newState' -- The state after changes made by the current
+transaction.  The method is *not* permitted to modify this
+value. This method should compute a new state by merging changes
+reflected in 'savedState' and 'newState', relative to 'oldState'.
+
+The method should return the state of the object after resolving the
+differences.
+
+Here is an example of a '_p_resolveConflict' in the 'Counter' class::
+
+  class Counter(Persistent):
+
+      self.count = 0
+
+      def hit(self):
+          self.count = self.count + 1
+
+      def _p_resolveConflict(self, oldState, savedState, newState):
+
+          # Figure out how each state is different:
+          savedDiff= savedState['count'] - oldState['count']
+          newDiff= newState['count']- oldState['count']
+
+          # Apply both sets of changes to old state:
+          oldState['count'] = oldState['count'] + savedDiff + newDiff
+
+          return oldState
+
+In the above example, '_p_resolveConflict' resolves the difference
+between the two conflicting transactions.
+
+Threadsafety of Non-Persistent Objects
+======================================
+
+ZODB takes care of threadsafety for persistent objects. However, you
+must handle threadsafey yourself for non-persistent objects which are
+shared between threads.
+
+Mutable Default Arguments
+-------------------------
+
+One tricky type of non-persistent, shared objects are mutable default
+arguments to functions, and methods.  Default arguments are useful
+because they are cached for speed, and do not need to be recreated
+every time the method is called.  But if these cached default
+arguments are mutable, one thread may change (mutate) the object when
+another thread is using it, and that can be bad.  So, code like::
+
+        def foo(bar=[]):
+            bar.append('something')
+
+
+Could get in trouble if two threads execute this code because lists
+are mutable.  There are two solutions to this problem:
+
+- Don't use mutable default arguments. (Good)
+
+- If you use them, you cannot change them.  If you want to change
+  them, you will need to implement your own locking. (Bad)
+
+We recommend the first solution because mutable default arguments are
+confusing, generally a bad idea in the first place.
+
+Shared Module Data
+------------------
+
+Objects stored in modules but not in the ZODB are not persistent and
+not-thread safe. In general it's not a good idea to store data (as
+opposed to functions, and class definitions) in modules when using
+ZODB.
+
+
+If you decide to use module data which can change you'll need to
+protect it with a lock to ensure that only one thread at a time can
+make changes.
+
+
+For example::
+
+  from threading import Lock
+  queue=[]
+  l=Lock()
+
+  def put(obj):
+      l.acquire()
+      try:
+          queue.append(obj)
+      finally:
+          l.release()
+
+  def get():
+      l.acquire()
+      try:
+          return queue.pop()
+      finally:
+          l.release()
+
+Note, in most cases where you are tempted to use shared module data,
+you can likely achieve the same result with a single persistent
+object. For example, the above queue could be replaced with a single
+instance of this class::
+
+  class Queue(Persistent):
+
+      def __init__(self):
+          self.list=[]
+
+      def put(self, obj):
+          self.list=self.list + [obj]
+
+      def get(self):
+          obj=self.list[-1]
+          self.list=self.list[0:-1]
+          return obj
+
+Notice how this class uses the mutable object 'self.list'
+immutably. If this class used 'self.list.pop' and 'self.list.append',
+then the persistence machinary would not notice that 'self.list' had
+changed.
+
+Shared External Resources
+=========================
+
+A final category of data for which you'll need to handle
+thread-safety is external resources such as files in the filesystem,
+and other processes. In practice, these concerns rarely come up.
+
+Other ZODB Resources
+====================
+
+This chapter has only covered the most important features of ZODB
+from a Zope developer's perspective. Check out some of these sources
+for more in depth information:
+
+- Andrew Kuchling's `ZODB pages <http://www.kuchling.com/zodb/>`_
+  include lots of information included a programmer's guide and links
+  to ZODB mailing lists.
+
+- `ZODB Wiki <http://wiki.zope.org/ZODB>`_ has information about
+  current ZODB projects.
+
+- `ZODB UML
+  Model <http://www.zope.org/Documentation/Developer/Models/ZODB>`_ has
+  the nitty gritty details on ZODB.
+
+- Paper `Introduction to the Zope Object Database
+  <http://www.python.org/workshops/2000-01/proceedings/papers/fulton/zodb3.html>`_
+  by Jim Fulton, presented at the 8th Python Conference.
+
+Summary
+=======
+
+The ZODB is a complex and powerful system. However using persistent
+objects is almost completely painless. Seldom do you need to concern
+yourself with thread safety, transactions, conflicts, memory
+management, and database replication. ZODB takes care of these things
+for you. By following a few simple rules you can create persistent
+objects that just work.
+

Deleted: zope2docs/trunk/zdgbook/bootstrap.py
===================================================================
--- zope2docs/trunk/zdgbook/bootstrap.py	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/bootstrap.py	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zdgbook/buildout.cfg
===================================================================
--- zope2docs/trunk/zdgbook/buildout.cfg	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/buildout.cfg	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zdgbook/index.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zdgbook/index.rst)
===================================================================
--- zope2docs/trunk/zdgbook/index.rst	                        (rev 0)
+++ zope2docs/trunk/zdgbook/index.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -0,0 +1,17 @@
+Zope Developer's Guide
+======================
+
+.. toctree::
+   :numbered:
+   :maxdepth: 2
+
+   Introduction.rst
+   GettingStarted.rst
+   ComponentsAndInterfaces.rst
+   ObjectPublishing.rst
+   Products.rst
+   ZODBPersistentComponents.rst
+   Acquisition.rst
+   Security.rst
+   TestingAndDebugging.rst
+   AppendixA.rst

Deleted: zope2docs/trunk/zdgbook/source/Acquisition.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/Acquisition.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/Acquisition.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,457 +0,0 @@
-###########
-Acquisition
-###########
-
-Acquisition is a mechanism that allows objects to obtain attributes
-from their environment.  It is similar to inheritance, except that,
-rather than searching an inheritance hierarchy to obtain attributes,
-a containment hierarchy is traversed.
-
-
-Introductory Example
-====================
-
-Zope implements acquisition with "Extension Class" mix-in classes. To
-use acquisition your classes must inherit from an acquisition base
-class. For example::
-
-  import ExtensionClass, Acquisition
-
-  class C(ExtensionClass.Base):
-    color = 'red'
-
-  class A(Acquisition.Implicit):
-
-    def report(self):
-      print self.color
-
-  a = A()
-  c = C()
-  c.a = A()
-
-  c.a.report() # prints 'red'
-
-  d = C()
-  d.color = 'green'
-  d.a = a
-
-  d.a.report() # prints 'green'
-
-  a.report() # raises an attribute error
-
-The class 'A' inherits acquisition behavior from
-'Acquisition.Implicit'.  The object, 'a', "has" the color of objects
-'c' and 'd' when it is accessed through them, but it has no color by
-itself.  The object 'a' obtains attributes from its environment,
-where its environment is defined by the access path used to reach
-'a'.
-
-Acquisition Wrappers
-====================
-
-When an object that supports acquisition is accessed through an
-extension class instance, a special object, called an acquisition
-wrapper, is returned.  In the example above, the expression 'c.a'
-returns an acquisition wrapper that contains references to both 'c'
-and 'a'.  It is this wrapper that performs attribute lookup in 'c'
-when an attribute cannot be found in 'a'.
-
-Acquisition wrappers provide access to the wrapped objects through
-the attributes 'aq_parent', 'aq_self', 'aq_base'.  In the example
-above, the expressions::
-
-  'c.a.aq_parent is c'
-
-and::
-
-  'c.a.aq_self is a'
-
-
-both evaluate to true, but the expression::
-
-  'c.a is a'
-
-evaluates to false, because the expression 'c.a' evaluates to an
-acquisition wrapper around 'c' and 'a', not 'a' itself.
-
-The attribute 'aq_base' is similar to 'aq_self'.  Wrappers may be
-nested and 'aq_self' may be a wrapped object.  The 'aq_base'
-attribute is the underlying object with all wrappers removed.
-
-You can manually wrap an instance of an object that inherits from an
-acquisition base class by using its '__of__' method. For example::
-
-  class A(Acquisition.Implicit):
-      pass
-
-  a = A()
-  a.color = 'red'
-  b = A()
-  a.b = b
-
-  print b.__of__(a).color # prints red
-
-
-The expression 'b.__of__(a)' wraps 'b' in an acquisition wrapper
-explicitly, and returns the acquisition wrapper.  The 'color'
-attrribute of 'a' is found via acquisition when this expression is
-executed.
-
-
-Explicit and Implicit Acquisition
-=================================
-
-Two styles of acquisition are supported: implicit and explicit
-acquisition.
-
-Implicit acquisition
---------------------
-
-Implicit acquisition is so named because it searches for
-attributes from the environment automatically whenever an
-attribute cannot be obtained directly from an object or through
-inheritance.
-
-An attribute can be implicitly acquired if its name does not
-begin with an underscore.
-
-To support implicit acquisition, your class should inherit from
-the mix-in class 'Acquisition.Implicit'.
-
-Explicit Acquisition
---------------------
-
-When explicit acquisition is used, attributes are not automatically
-obtained from the environment.  Instead, the method 'aq_acquire' must
-be used. For example::
-
-  print c.a.aq_acquire('color')
-
-To support explicit acquisition, your class should inherit from the
-mix-in class 'Acquisition.Explicit'.
-
-Controlling Acquisition
-=======================
-
-A class (or instance) can provide attribute by attribute control over
-acquisition.  Your should subclass from 'Acquisition.Explicit', and
-set all attributes that should be acquired to the special value
-'Acquisition.Acquired'.  Setting an attribute to this value also
-allows inherited attributes to be overridden with acquired ones.  For
-example::
-
-  class C(Acquisition.Explicit):
-     id=1
-     secret=2
-     color=Acquisition.Acquired
-     __roles__=Acquisition.Acquired
-
-The *only* attributes that are automatically acquired from containing
-objects are 'color', and '__roles__'.  Note that the '__roles__'
-attribute is acquired even though its name begins with an underscore.
-In fact, the special 'Acquisition.Acquired' value can be used in
-'Acquisition.Implicit' objects to implicitly acquire selected objects
-that smell like private objects.
-
-Sometimes, you want to dynamically make an implicitly acquiring
-object acquire explicitly. You can do this by getting the object's
-'aq_explicit' attribute. This attribute provides the object with an
-explicit wrapper that places the original implicit wrapper.
-
-Filtered Acquisition
-====================
-
-The acquisition method, 'aq_acquire', accepts two optional
-arguments. The first of the additional arguments is a "filtering"
-function that is used when considering whether to acquire an object.
-The second of the additional arguments is an object that is passed as
-extra data when calling the filtering function and which defaults to
-'None'.  The filter function is called with five arguments:
-
-- The object that the 'aq_acquire' method was called on,
-
-- The object where an object was found,
-
-- The name of the object, as passed to 'aq_acquire',
-
-- The object found, and
-
-- The extra data passed to 'aq_acquire'.
-
-If the filter returns a true object that the object found is
-returned, otherwise, the acquisition search continues.
-
-For example, in::
-
-  from Acquisition import Explicit
-
-  class HandyForTesting:
-      def __init__(self, name):
-          self.name = name
-      def __str__(self):
-          return "%s(%s)" % (self.name, self.__class__.__name__)
-      __repr__ = __str__
-
-  class E(Explicit, HandyForTesting): pass
-
-  class Nice(HandyForTesting):
-      isNice = 1
-      def __str__(self):
-          return HandyForTesting.__str__(self) + ' and I am nice!'
-      __repr__ = __str__
-
-  a = E('a')
-  a.b = E('b')
-  a.b.c = E('c')
-  a.p = Nice('spam')
-  a.b.p = E('p')
-
-  def find_nice(self, ancestor, name, object, extra):
-      return hasattr(object,'isNice') and object.isNice
-
-  print a.b.c.aq_acquire('p', find_nice)
-
-The filtered acquisition in the last line skips over the first
-attribute it finds with the name 'p', because the attribute doesn't
-satisfy the condition given in the filter. The output of the last
-line is::
-
-  spam(Nice) and I am nice!
-
-Filtered acquisition is rarely used in Zope.
-
-Acquiring from Context
-======================
-
-Normally acquisition allows objects to acquire data from their
-containers. However an object can acquire from objects that aren't
-its containers.
-
-Most of the example's we've seen so far show establishing of an
-acquisition *context* using 'getattr' symanitics. For example, 'a.b'
-is a reference to 'b' in the context of 'a'.
-
-
-You can also manuallyset acquisition context using the '__of__'
-method.  For example::
-
-  from Acquisition import Implicit
-  class C(Implicit): pass
-  a = C()
-  b = C()
-  a.color = "red"
-  print b.__of__(a).color # prints red
-
-In this case, 'a' does not contain 'b', but it is put in 'b''s
-context using the '__of__' method.
-
-Here's another subtler example that shows how you can construct an
-acquisition context that includes non-container objects::
-
-  from Acquisition import Implicit
-
-  class C(Implicit):
-      def __init__(self, name):
-          self.name = name
-
-  a = C("a")
-  a.b = C("b")
-  a.b.color = "red"
-  a.x = C("x")
-
-  print a.b.x.color # prints red
-
-Even though 'b' does not contain 'x', 'x' can acquire the 'color'
-attribute from 'b'. This works because in this case, 'x' is accessed
-in the context of 'b' even though it is not contained by 'b'.
-
-Here acquisition context is defined by the objects used to access
-another object.
-
-Containment Before Context
-==========================
-
-If in the example above suppose both 'a' and 'b' have an 'color'
-attribute::
-
-  a = C("a")
-  a.color = "green"
-  a.b = C("b")
-  a.b.color = "red"
-  a.x = C("x")
-
-  print a.b.x.color # prints green
-
-
-Why does 'a.b.x.color' acquire 'color' from 'a' and not from 'b'?
-The answer is that an object acquires from its containers before
-non-containers in its context.
-
-To see why consider this example in terms of expressions using the
-'__of__' method::
-
-   a.x -> x.__of__(a)
-
-   a.b -> b.__of__(a)
-
-   a.b.x -> x.__of__(a).__of__(b.__of__(a))
-
-Keep in mind that attribute lookup in a wrapper is done by trying to
-look up the attribute in the wrapped object first and then in the
-parent object.  So in the expressions above proceeds from left to
-right.
-
-
-The upshot of these rules is that attributes are looked up by
-containment before context.
-
-This rule holds true also for more complex examples. For example,
-'a.b.c.d.e.f.g.attribute' would search for 'attribute' in 'g' and all
-its containers first. (Containers are searched in order from the
-innermost parent to the outermost container.) If the attribute is not
-found in g or any of its containers, then the search moves to 'f' and
-all its containers, and so on.
-
-Additional Attributes and Methods
-=================================
-
-You can use the special method 'aq_inner' to access an object wrapped
-only by containment. So in the example above::
-
-  a.b.x.aq_inner
-
-is equivalent to::
-
-  a.x
-
-You can find out the acquisition context of an object using the
-'aq_chain' method like so::
-
-  a.b.x.aq_chain # returns [x, b, a]
-
-You can find out if an object is in the acquisition context of
-another object using the 'aq_inContextOf' method. For example::
-
-  a.b.x.aq_inContextOf(a.b) # returns 1
-
-
-You can also pass an additional argument to 'aq_inContextOf' to
-indicate whether to only check containment rather than the full
-acquisition context. For example::
-
-  a.b.x.aq_inContextOf(a.b, 1) # returns 0
-
-Note: as of this writing the 'aq_inContextOf' examples don't
-work. According to Jim, this is because 'aq_inContextOf' works by
-comparing object pointer addresses, which (because they are actually
-different wrapper objects) doesn't give you the expected results. He
-acknowledges that this behavior is controversial, and says that there
-is a collector entry to change it so that you would get the answer
-you expect in the above. (We just need to get to it).
-
-
-Acquisition Module Functions
-----------------------------
-
-In addition to using acquisition attributes and methods directly on
-objects you can use similar functions defined in the 'Acquisition'
-module. These functions have the advantage that you don't need to
-check to make sure that the object has the method or attribute before
-calling it.
-
-'aq_acquire(object, name [, filter, extra, explicit, default, containment])' -- Acquires an object with the given name.
-
-This function can be used to explictly acquire when using explicit
-acquisition and to acquire names that wouldn't normally be acquired.
-
-The function accepts a number of optional arguments:
-
-- 'filter' -- A callable filter object that is used to decide if an
-  object should be acquired.
-
-  The filter is called with five arguments:
-
-  - The object that the aq_acquire method was called on,
-
-  - The object where an object was found,
-
-  - The name of the object, as passed to aq_acquire,
-
-  - The object found, and
-
-  - The extra argument passed to aq_acquire.
-
-  If the filter returns a true object that the object found is
-  returned, otherwise, the acquisition search continues.
-
-- 'extra' -- extra data to be passed as the last argument to the
-  filter.
-
-- 'explicit' -- A flag (boolean value) indicating whether explicit
-  acquisition should be used. The default value is true.  If the flag
-  is true, then acquisition will proceed regardless of whether
-  wrappers encountered in the search of the acquisition hierarchy are
-  explicit or implicit wrappers. If the flag is false, then parents
-  of explicit wrappers are not searched.
-
-  This argument is useful if you want to apply a filter without
-  overriding explicit wrappers.
-
-- 'default' -- A default value to return if no value can be acquired.
-
-- 'containment' -- A flag indicating whether the search should be
-  limited to the containment hierarchy.
-
-In addition, arguments can be provided as keywords.
-
-- 'aq_base(object)' -- Return the object with all wrapping removed.
-
-- 'aq_chain(object [, containment])' -- Return a list containing the
-  object and it's acquisition parents. The optional argument,
-  'containment', controls whether the containment or access hierarchy
-  is used.
-
-- 'aq_get(object, name [, default, containment])' -- Acquire an
-  attribute, name. A default value can be provided, as can a flag
-  that limits search to the containment hierarchy.
-
-- 'aq_inner(object)' -- Return the object with all but the innermost
-  layer of wrapping removed.
-
-- 'aq_parent(object)' -- Return the acquisition parent of the object
-  or 'None' if the object is unwrapped.
-
-- 'aq_self(object)' -- Return the object with one layer of wrapping
-  removed, unless the object is unwrapped, in which case the object
-  is returned.
-
-In most cases it is more convenient to use these module functions
-instead of the acquisition attributes and methods directly.
-
-Acquisition and Methods
-=======================
-
-Python methods of objects that support acquisition can use acquired
-attributes.  When a Python method is called on an object that is
-wrapped by an acquisition wrapper, the wrapper is passed to the
-method as the first argument.  This rule also applies to user-defined
-method types and to C methods defined in pure mix-in classes.
-
-Unfortunately, C methods defined in extension base classes that
-define their own data structures, cannot use aquired attributes at
-this time.  This is because wrapper objects do not conform to the
-data structures expected by these methods. In practice, you will
-seldom find this a problem.
-
-Conclusion
-==========
-
-Acquisition provides a powerful way to dynamically share information
-between objects. Zope using acquisition for a number of its key
-features including security, object publishing, and DTML variable
-lookup. Acquisition also provides an elegant solution to the problem
-of circular references for many classes of problems. While
-acquisition is powerful, you should take care when using acquisition
-in your applications. The details can get complex, especially with
-the differences between acquiring from context and acquiring from
-containment.

Deleted: zope2docs/trunk/zdgbook/source/AppendixA.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/AppendixA.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/AppendixA.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,123 +0,0 @@
-#################################
-Appendix A: Zope Core Permissions
-#################################
-
-This is a list of standard permissions included with Zope.  It is a
-good idea to use these permissions when applicable with your Zope
-products, rather than creating new ones.  A list of built-in Zope
-permissions are available in Zope source code:
-``src/AccessControl/Permissions.py``.
-
-Core Permissions
-================
-
-- Access contents information -- get "directory listing" info
-
-- Add Accelerated HTTP Cache Managers -- add HTTP Cache Manager objects
-
-- Add Database Methods -- add ZSQL Method objects
-
-- Add Documents, Images, and Files -- add DTML Method/Document objects,
-  Image objects, and File objects
-
-- Add External Methods  -- add External Method objects
-
-- Add Folders -- add Folder objects
-
-- Add MailHost objects  -- add MailHost objects
-
-- Add Python Scripts  -- Add Python Script objects
-
-- Add RAM Cache Managers  -- Add RAM Cache manager objects
-
-- Add Site Roots -- add Site Root objects
-
-- Add User Folders  -- add User Folder objects
-
-- Add Versions  -- add Version objects
-
-- Add Virtual Host Monsters  -- add Virtual Host Monster objects
-
-- Add Vocabularies  -- add Vocabulary objects (ZCatalog-related)
-
-- Add ZCatalogs  -- add ZCatalog objects
-
-- Add Zope Tutorials  -- add Zope Tutorial objects
-
-- Change DTML Documents -- modify DTML Documents
-
-- Change DTML Methods  -- modify DTML Methods
-
-- Change Database Connections  -- change database connection objects
-
-- Change Database Methods  -- change ZSQL method objects
-
-- Change External Methods -- change External Method objects
-
-- Change Images and Files  -- change Image and File objects
-
-- Change Python Scripts  -- change Python Script objects
-
-- Change Versions  -- change Version objects
-
-- Change bindings  -- change bindings (for Python Scripts)
-
-- Change cache managers  -- change cache manager objects
-
-- Change cache settings  -- change cache settings (cache mgr parameters)
-
-- Change configuration  -- generic
-
-- Change permissions  -- change permissions
-
-- Change proxy roles  -- change proxy roles
-
-- Create class instances  -- used for ZClass permission mappings
-
-- Delete objects  -- delete objects
-
-- Edit Factories  -- edit Factory objects (ZClass)
-
-- FTP access  -- allow FTP access to this object
-
-- Import/Export objects  -- export and import objects
-
-- Join/leave Versions  -- join and leave Zope versions
-
-- Manage Access Rules -- manage access rule objects
-
-- Manage Vocabulary  -- manage Vocabulary objects
-
-- Manage Z Classes  -- Manage ZClass objects (in the control panel)
-
-- Manage ZCatalog Entries  -- catalog and uncatalog objects
-
-- Manage properties -- manage properties of an object
-
-- Manage users  -- manage Zope users
-
-- Open/Close Database Connections  -- open and close database connections    
-
-- Query Vocabulary -- query Vocabulary objects (ZCatalog-related)
-
-- Save/discard Version changes -- save or discard Zope version changes
-
-- Search ZCatalog -- search a ZCatalog instance
-
-- Take ownership  -- take ownership of an object
-
-- Test Database Connections  -- test database connection objects
-
-- Undo changes  -- undo changes to the ZODB (e.g. use the Undo tab)
-
-- Use Database Methods  -- use ZSQL methods
-
-- Use Factories  -- use Factory objects (ZClass-related)
-
-- Use mailhost services -- use MailHost object services
-
-- View -- view or execute an object
-
-- View History -- view ZODB history of an object
-
-- View management screens -- view management screens related to an object

Deleted: zope2docs/trunk/zdgbook/source/ComponentsAndInterfaces.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/ComponentsAndInterfaces.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/ComponentsAndInterfaces.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,333 +0,0 @@
-#########################
-Components and Interfaces
-#########################
-
-Zope uses a component architecture internally in many places.  Zope
-components is nothing but Python objects with interfaces that
-describe them.  As a Zope developer you can use interfaces right now
-to build your Zope components.
-
-Zope Components
-===============
-
-Components are objects that are associated with interfaces.  An
-interface is a Python object that describes how you work with other
-Python objects.  In this chapter, you'll see some simple examples of
-creating components, and a description of interfaces and how they
-work.
-
-Here is a very simple component that says hello.  Like all
-components, this one generally consists of two pieces, an interface,
-and an implementation::
-
-  from zope.interface import Interface
-  from zope.interface import implements
-
-  class IHello(Interface):
-      """The Hello interface provides greetings."""
-
-      def hello(name):
-          """Say hello to the name"""
-
-  class HelloComponent(object):
-
-      implements(IHello)
-
-      def hello(self, name):
-          return "hello %s!" % name
-
-Let's take a look at this step by step.  Here, you see two Python
-class statements.  The first class statement creates the *interface*,
-and the second class statement creates the *implementation*.
-
-The first class statement creates the ``IHello`` interface.  This
-interface describes one method, called ``hello``.  Notice that there
-is no implementation for this method, interfaces do not define
-behavior, they just describe a specification.
-
-The second ``class`` statement creates the ``HelloComponent`` class.
-This class is the actual component that *does* what ``IHello``
-*describes*.  This is usually referred to as the *implementation* of
-``IHello``.  In order for you to know what interfaces
-``HelloComponent`` implements, it must somehow associate itself with
-an interface.  The ``implements`` function call inside the class does
-just that.  It says, "I implement these interfaces".  In this case,
-``HelloComponent`` asserts that it implements one interface,
-``IHello``.
-
-The interface describes how you would work with the object, but it
-doesn't dictate how that description is implemented.  For example,
-here's a more complex implementation of the ``Hello`` interface::
-
-  import xmlrpclib
-  class XMLRPCHello:
-
-      implementats(IHello)
-
-      def hello(self, name):
-          """Delegates the hello call to a remote object
-          using XML-RPC.
-
-          """
-          s = xmlrpclib.Server('http://www.zope.org/')
-          return s.hello(name)
-
-This component contacts a remote server and gets its hello greeting
-from a remote component.
-
-And that's all there is to components, really.  The rest of this
-chapter describes interfaces and how you can work with them from the
-perspective of components.  In Chapter 3, we'll put all this together
-into a Zope product.
-
-Python Interfaces
-=================
-
-Interface describe the behavior of an object by containing useful
-information about the object.  This information includes:
-
-- Prose documentation about the object.  In Python terms, this is
-  called the "doc string" of the interface.  In this element, you
-  describe how the object works in prose language and any other
-  useful information about the object.
-
-- Descriptions of attributes.  Attribute descriptions include the
-  name of the attribute and prose documentation describing the
-  attributes usage.
-
-- Descriptions of methods.  Method descriptions can include:
-
-  - Prose "doc string" documentation about the method and its usage.
-
-  - A sequence of parameter objects that describes the parameters
-    expected by the method.
-
-- Optional tagged data.  Interface objects (and their attributes,
-  methods, and method parameters) can have optional, application
-  specific tagged data associated with them.  Examples uses for this
-  are security assertions, pre/post conditions, unit tests, and other
-  possible information you may want to associate with an Interface or
-  its attributes.
-
-Not all of this information is mandatory.  For example, you may only
-want the methods of your interface to have prose documentation and
-not describe the arguments of the method in exact detail.  Interface
-objects are flexible and let you give or take any of these
-components.
-
-Why Use Interfaces?
-===================
-
-Interfaces solve a number of problems that arise while developing
-large systems with lots of developers.
-
-- Developers waste a lot of time looking at the source code of your
-  system to figure out how objects work.  This is even worse if
-  someone else has already wasted their time doing the same thing.
-
-- Developers who are new to your system may misunderstand how your
-  object works, causing, and possibly propagating, usage errors.
-
-- Because an object's interface is inferred from the source,
-  developers may end up using methods and attributes that are meant
-  for "internal use only".
-
-- Code inspection can be hard, and very discouraging to novice
-  programmers trying to understand code written by gurus.
-
-Interfaces try to solve these problems by providing a way for you to
-describe how to use an object, and a mechanism for discovering that
-description.
-
-Creating Interfaces                                       
-===================
-
-The first step to creating a component, as you've been shown, is to
-create an interface.
-
-Interface objects can be conveniently constructed using the Python
-``class`` statement.  Keep in mind that this syntax can be a little
-misleading, because interfaces are *not* classes.  It is important to
-understand that using Python's class syntax is just a convenience,
-and that the resulting object is an *interface*, not a class.
-
-To create an interface object using Python's class syntax, create a
-Python class that subclasses from ``zope.interface.Interface``::
-
-  from zope.interface import Interface
-
-  class IHello(Interface):
-
-      def hello(name):
-          """Say hello to the world"""
-
-This interface does not implement behavior for its methods, it just
-describes an interface that a typical "Hello" object would realize.
-By subclassing the ``zope.interface.Interface`` interface, the
-resulting object ``Hello`` is an interface object. The Python
-interpreter confirms this::
-
-  >>> IHello
-  <InterfaceClass __main__.IHello>
-
-Now, you can associate the ``Hello`` Interface with your new concrete
-class in which you define your user behavior.  For example::
-
-  class HelloComponent:
-
-      implements(IHello)
-
-      def hello(self, name):
-          return "Hello %s!" % name
-
-This new class, ``HelloComponent`` is a concrete class that
-implements the ``Hello`` interface.  A class can realize more than
-one interface.  For example, say you had an interface called 'Item'
-that described how an object worked as an item in a "Container"
-object.  If you wanted to assert that ``HelloComponent`` instances
-realized the ``Item`` interface as well as ``Hello``, you can provide
-a sequence of Interface objects to the 'HelloComponent' class::
-
-  class HelloComponent:
-
-      implements(IHello, IItem)
-
-
-The Interface Model
-===================
-
-Interfaces can extend other interfaces.  For example, let's extend
-the ``IHello`` interface by adding an additional method::
-
-  class ISmartHello(IHello):
-      """A Hello object that remembers who it's greeted"""
-
-      def lastGreeted(self):
-          """Returns the name of the last person greeted."""
-
-
-``ISmartHello`` extends the ``IHello`` interface.  It does this by
-using the same syntax a class would use to subclass another class.
-
-Now, you can ask the ``ISmartHello`` for a list of the interfaces it
-extends with ``getBases``::
-
-  >>> ISmartHello.getBases()
-  (<InterfaceClass __main__.IHello>,)
-
-An interface can extend any number of other interfaces, and
-``getBases`` will return that list of interfaces for you.  If you
-want to know if ``ISmartHello`` extends any other interface, you
-could call ``getBases`` and search through the list, but a
-convenience method called ``extends`` is provided that returns true
-or false for this purpose::
-
-  >>> ISmartHello.extends(IHello)
-  True
-  >>> ISandwich(Interface):
-  ...     pass
-  >>> ISmartHello.extends(ISandwich)
-  False
-
-Here you can see ``extends`` can be used to determine if one
-interface extends another.
-
-You may notice a similarity between interfaces extending from other
-interfaces and classes sub-classing from other classes.  This *is* a
-similar concept, but the two should not be considered equal.  There
-is no assumption that classes and interfaces exist in a one to one
-relationship; one class may implement several interfaces, and a class
-may not implement its base classes's interfaces.
-
-The distinction between a class and an interface should always be
-kept clear.  The purpose of a class is to share the implementation of
-how an object works.  The purpose of an interface is to document how
-to work *with* an object, not how the object is implemented.  It is
-possible to have several different classes with very different
-implementations realize the same interface.  Because of this,
-interfaces and classes should never be confused.
-
-
-Querying an Interface
-=====================
-
-Interfaces can be queried for information.  The simplest case is to
-ask an interface the names of all the various interface items it
-describes.  From the Python interpreter, for example, you can walk
-right up to an interface and ask it for its *names*::
-
-  >>> User.names()
-  ['getUserName', 'getFavoriteColor', 'getPassword']
-
-Interfaces can also give you more interesting information about their
-items.  Interface objects can return a list of '(name, description)'
-tuples about their items by calling the *namesAndDescriptions*
-method.
-
-For example::
-
-  >>> User.namesAndDescriptions()
-  [('getUserName', <Interface.Method.Method object at 80f38f0>),
-  ('getFavoriteColor', <Interface.Method.Method object at 80b24f0>),
-  ('getPassword', <Interface.Method.Method object at 80fded8>)]
-
-As you can see, the "description" of the Interface's three items in
-these cases are all `Method` objects.  Description objects can be
-either 'Attribute' or `Method` objects.  Attributes, methods, and
-interface objects implement the following interface::
-
-- `getName()` -- Returns the name of the object.
-
-- `getDoc()` -- Returns the documentation for the object.
-
-Method objects provide a way to describe rich meta-data about Python
-methods. Method objects have the following methods:
-
-- `getSignatureInfo()` -- Returns a dictionary describing the method
-  parameters.
-
-- `getSignatureString()` -- Returns a human-readable string
-  representation of the method's signature.
-
-For example::
-
-  >>> m = User.namesAndDescriptions()[0][1]
-  >>> m
-  <Interface.Method.Method object at 80f38f0>
-  >>> m.getSignatureString()
-  '(fullName=1)'
-  >>> m.getSignatureInfo()   
-  {'varargs': None, 'kwargs': None, 'optional': {'fullName': 1}, 
-  'required': (), 'positional': ('fullName',)}  
-
-You can use `getSignatureInfo` to find out the names and types of the
-method parameters.
-
-
-Checking Implementation
-=======================
-
-You can ask an interface if a certain class or instance that you hand
-it implements that interface.  For example, say you want to know if
-instances of the `HelloComponent` class implement 'Hello'::
-
-  IHello.implementedBy(HelloComponent)
-
-This is a true expression.  If you had an instance of
-`HelloComponent`, you can also ask the interface if that instance
-implements the interface::
-
-  IHello.implementedBy(my_hello_instance)
-
-This would also return true if *my_hello_instance* was an instance of
-*HelloComponent*, or any other class that implemented the *Hello*
-Interface.
-
-Conclusion
-==========
-
-Interfaces provide a simple way to describe your Python objects.  By
-using interfaces you document capabilities of objects.  As Zope
-becomes more component oriented, your objects will fit right in.
-While components and interfaces are forward looking technologies,
-they are useful today for documentation and verification.

Deleted: zope2docs/trunk/zdgbook/source/Credits.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/Credits.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/Credits.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,13 +0,0 @@
-#######
-Credits
-#######
-
-- Amos Latteier
-
-- Michel Pelletier
-
-- Shane Hathaway
-
-- Chris McDonough
-
-- Beehive

Deleted: zope2docs/trunk/zdgbook/source/GettingStarted.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/GettingStarted.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/GettingStarted.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,372 +0,0 @@
-###############
-Getting Started
-###############
-
-Introduction
-============
-
-This chapter cover installation and getting started with development
-of a simple application.  This guide use a build system called
-`Buildout <http://www.buildout.org>`_ to build the application.  And
-the Python packages developed as part of the application can be
-distributed as `Python eggs
-<http://peak.telecommunity.com/DevCenter/setuptools>`_.
-
-
-Directory Structure
-===================
-
-To begin the application development, create a directory structure to
-place Python packages and build related files.
-
-::
-
-  $ mkdir poll
-  $ mkdir poll/poll_build
-  $ mkdir poll/poll.main
-
-All build related files can be added inside `poll_build` directory.
-The main Python package can be added inside `poll.main` directory.
-We can make the ``poll``, a namespace package using the functionality
-provided by `pkg_resources` module included in setuptools.
-
-Bootstraping the Build
-======================
-
-You should have Python 2.5 or 2.6 installed in your system.  To start
-the build process, download and run `bootstrap.py`.  The
-`bootstrap.py` will download and install `setuptools` and
-`zc.buildout` packages.  Also it will create the directory structure
-and `buildout` script inside `bin` directory.
-
-::
-
-  $ cd poll/poll.build
-  $ touch buildout.cfg
-  $ wget -c http://svn.zope.org/repos/main/zc.buildout/trunk/bootstrap/bootstrap.py
-  $ python2.6 bootstrap.py
-
-Installing Zope 2
-=================
-
-From Zope 2.12 onwards Zope 2 is distributed in egg format.  To
-install Zope 2 egg and create an instance, update buildout
-configuration file (``buildout.cfg``) with appropriate parts and
-recipes.
-
-::
-
-  [buildout]
-  parts = zope2
-          instance
-  extends = http://download.zope.org/Zope2/index/2.12.0/versions.cfg
-
-  [zope2]
-  recipe = zc.recipe.egg
-  eggs = Zope2
-  interpreter = zopepy
-
-  [instance]
-  recipe = plone.recipe.zope2instance
-  user = admin:admin
-  http-address = 8080
-  eggs = ${zope2:eggs}
-
-The ``[zope2]`` part use `zc.recipe.egg` which will download `Zope2`
-egg and all its dependencies.  It will create few console scripts
-inside `bin` directory.  Also it will create a custom Python
-interpreter named ``zopepy``.
-
-The ``[instance]`` part creates a Zope 2 application instance to
-develop application.  It will create a script named ``instance``
-inside `bin` directory.  We can use that script to run the
-application instance.
-
-After updating the buildout configuration, you can run the `buildout`
-command to build the system.
-
-::
-
-  $ ./bin/buildout
-
-The initial build will take some time to complete.
-
-Running Instance
-================
-
-Once build is completed, you can run Zope 2 instance like this.
-
-::
-
-  $ ./bin/instance fg
-
-
-You can see that Zope is running in 8080 port.  You can go to the
-Zope Management Interface (ZMI).
-
-::
-
-  http://localhost:8080/manage
-
-You can provide the user name & password provided in `[instance]`
-part to access this page.
-
-You can see a list of installable applications in the drop-down box.
-Also you can see it in "Control_Panel" -> "Products".
-
-::
-
-  http://localhost:8080/Control_Panel/Products/manage_main
-
-In the next section we will make the `poll.main` listed here.  And
-later we will make it installable.
-
-
-Developing the main package
-===========================
-
-Now we can move to `poll.main` packae to create the main package to
-develop the application.  We can develop the entire application
-inside `poll.main` package.  But it is reccomended to split packages
-logically and maintain the dependencies between packages properly.
-
-::
-
-  $ cd ../poll.build
-
-Again we need to create the basic directory structure and `setup.py`
-to create egg distribution.  We are going to place python package
-inside `src` directory.
-
-::
-
-  $ touch setup.py
-  $ mkdir src
-  $ mkdir src/poll
-  $ mkdir src/poll/main
-  $ touch src/poll/__init__.py
-  $ touch src/poll/main/__init__.py
-  $ touch src/poll/main/configure.zcml
-
-The last file we created is a configuration file called Zope
-Configuration Markup Language (ZCML). Soon we will add some boiler
-plate code inside ZCML file.
-
-To declare `poll` as a namespace package, we need to add this boiler
-plate code to `src/poll/__init__.py`.
-
-::
-
-  __import__('pkg_resources').declare_namespace(__name__)
-
-Next we need to add the minimum meta data required for the package in
-`setup.py`.
-
-::
-
-  from setuptools import setup, find_packages
-
-  setup(
-      name="poll.main",
-      version="0.1",
-      packages=find_packages("src"),
-      package_dir={"": "src"},
-      namespace_packages=["poll"],
-      install_requires=["setuptools",
-                        "Zope2"],
-      )
-
-We need to add two more files to be recognized by Zope.  First,
-define this call-back function in `src/poll/main/__init__.py`.
-
-::
-
-  def initialize(registrar):
-      pass
-
-And in the ZCML file add these few lines.
-
-::
-
-  <configure
-      xmlns="http://namespaces.zope.org/five">
-
-      <registerPackage package="." initialize=".initialize" />
-
-  </configure>
-
-Creating Installable Application
-================================
-
-We need three things to make an installable application.
-
-- Form object created using ZPT (manage_addPollMain)
-- A function to define form action (addPollMain)
-- A class to define toplevel application object (PollMain).
-
-And we need to register the class along with form and add function
-using the `registrar` object passed to the `initialize` function.
-
-We can define all these things in `app.py` and the form template as
-`manage_addPollMain_form.zpt`.
-
-::
-
-  $ touch src/poll/main/app.py
-  $ touch src/poll/main/manage_addPollMain_form.zpt
-
-Here is the code for `app.py`.
-
-::
-
-  from OFS.Folder import Folder
-  from Products.PageTemplates.PageTemplateFile import PageTemplateFile
-
-  class PollMain(Folder):
-      meta_type = "POLL"
-
-  manage_addPollMain = PageTemplateFile("manage_addPollMain_form", globals())
-
-  def addPollMain(context, id):
-      """ """
-      context._setObject(id, PollMain(id))
-      return "POLL Installed: %s" % id
-
-And `manage_addPollMain_form.zpt`.
-
-::
-
-  <html xmlns="http://www.w3.org/1999/xhtml"
-        xmlns:tal="http://xml.zope.org/namespaces/tal">
-    <body>
-
-      <h2>Add POLL</h2>
-      <form action="addPollMain" method="post">
-        Id: <input type="text" name="id" /><br />
-        Title: <input type="text" name="title" /><br />
-        <input type="submit" value="Add" />
-      </form>
-    </body>
-  </html>
-
-Finally we can register it like this (update `__init__.py`)::
-
-  from poll.main.app import PollMain, manage_addPollMain, addPollMain
-
-  def initialize(registrar):
-      registrar.registerClass(PollMain,
-                              constructors=(manage_addPollMain, addPollMain))
-
-The application is now ready to install.  But we need to make some
-changes in `poll_build` to recognize this package by Zope 2.
-
-Adding poll.main to build
-=========================
-
-First in `[buildout]` part we need to mention that `poll.main` is
-locally developed.  Otherwise buildout will try to get the package
-from package index server, by default http://pypi.python.org/pypi .
-
-::
-
-  [buildout]
-  develop = ../poll.main
-  ...
-
-Also we need to add `poll.main` egg to `eggs` option in `[zope2]`
-part.
-
-::
-
-  ...
-  eggs = Zope2
-         poll.main
-  ...
-
-And finally we need to add a new option to include the ZCML file.  So
-that the package will be recognized by Zope.
-
-::
-
-  ...
-  zcml = poll.main
-
-The final `buildout.cfg` will look like this.
-
-::
-
-  [buildout]
-  develop = ../poll.main
-  parts = zope2
-          instance
-
-  [zope2]
-  recipe = zc.recipe.egg
-  eggs = Zope2
-         poll.main
-  interpreter = zopepy
-
-  [instance]
-  recipe = plone.recipe.zope2instance
-  user = admin:admin
-  http-address = 8080
-  eggs = ${zope2:eggs}
-  zcml = poll.main
-
-Now to make these change effective, run the buildout again.
-
-::
-
-  $ ./bin/buildout
-
-Now we can run application instance again.
-
-::
-
-  $ ./bin/instance fg
-
-Adding application instance
-===========================
-
-Visit ZMI and select `POLL` from the drop-down box.  It will display
-the add-form created earlier.  You can provide the ID as `poll` and
-submit the form.  After submitting, it should display a message:
-"POLL Installed: poll".
-
-Adding the main page to POLL
-============================
-
-In this section we will try to add a main page to POLL application.
-So that we can acces POLL application like this:
-http://localhost:8080/poll .
-
-First create a file named `index_html.zpt` inside `src/poll/main` with
-content like this::
-
-  <html>
-  <head>
-    <title>Welcome to POLL!</title>
-  </head>
-  <body>
-
-  <h2>Welcome to POLL!</h2>
-
-  </body>
-  </html>
-
-Now add an attribute named `index_html` inside PollMain class like
-this::
-
-  class PollMain(Folder):
-      meta_type = "POLL"
-
-      index_html = PageTemplateFile("index_html", globals())
-
-Restart the Zope. Now you can see that it display the main page when
-you access: http://localhost:8080/poll .
-
-Summary
-=======
-
-This chapter covered installation and beginning a simple project in
-Zope 2.

Deleted: zope2docs/trunk/zdgbook/source/Introduction.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/Introduction.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/Introduction.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,97 +0,0 @@
-############
-Introduction
-############
-
-Overview
-========
-
-Zope 2 is a free and open-source, object-oriented web application
-server written in the Python programming language.  The term ZOPE is
-an acronym for "Z Object Publishing Environment" (the Z doesn't
-really mean anything in particular).  However, nowadays ZOPE is
-simply written as Zope.  It has three distinct audiences.
-
-*Site Managers*
-  Individuals who use of Zope's "out of the box" features to build
-  websites.  This audience is interested in making use of Zope's
-  existing array of features to create content management solutions.
-  They will likely make heavy use of "through the web" scripting
-  using DTML, Page Templates, and Python Scripts as well as (of
-  course) HTML and XML.  They are generally less concerned about code
-  reuse than the speed with which they can create a custom
-  application or website.
-
-*Developers*
-  Individuals who wish to extend Zope to create highly customized
-  solutions.  This audience is likely interested in creating highly
-  reusable custom code that makes Zope do something new and
-  interesting.  They will likely make heavy use of "through the
-  file-system" style development.
-
-*Administrators*
-  Individuals responsible for keeping a Zope site running and
-  performing installations and upgrades.
-
-This guide is intended to document Zope for the second audience,
-Developers, as defined above.  If you fit more into the "user"
-audience defined above, you'll probably want to start by reading `The
-Zope Book <http://docs.zope.org/zope2book>`_ .  If you fit more into
-the "administrator" audience defined above, you'll likely be
-interested in `The Zope Administrator's Guide
-<http://www.zope.org/DocProjects/AdminGuide>`_, although it is
-currently unfinished.
-
-Throughout this guide, it is assumed that you know how to program in
-the Python programming language.  Most of the examples in this guide
-will be in Python.  There are a number of great resources and books
-for learning Python; the best online resource is the `python.org web
-site <http://www.python.org/>`_ and many books can be found on the
-shelves of your local bookstore.
-
-Organization of the book
-========================
-
-This book describes Zope's services to the developer from a hands on,
-example-oriented standpoint.  This book is not a complete reference
-to the Zope API, but rather a practical guide to applying Zope's
-services to develop and deploy your own web applications.  This book
-covers the following topics:
-
-*Getting Started*
-  This chapter provides a brief overview of installation and getting
-  started with application development.
-
-*Components and Interfaces*
-  Zope use a component-centric development model.  This chapter
-  describes the component model in Zope and how Zope components are
-  described through interfaces.
-
-*Object Publishing*
-  Developing applications for Zope involves more than just creating a
-  component, that component must be *publishable* on the web.  This
-  chapter describes publication, and how your components need to be
-  designed to be published.
-
-*Zope Products*
-  New Zope components are distributed and installed in packages
-  called "Products".  This chapter explains Products in detail.
-
-*Persistent Components*
-  Zope provides a built-in, transparent Python object database called
-  ZODB.  This chapter describes how to create persistent components,
-  and how they work in conjunction with the ZODB.
-
-*Acquisition*
-  Zope relies heavily on a dynamic technique called acquisition. This
-  chapter explores acquisition thoroughly.
-
-*Security*
-  When your component is used by many different people through the
-  web, security becomes a big concern.  This chapter describes Zope's
-  security API and how you can use it to make security assertions
-  about your object.
-
-*Debugging and Testing*
-  Zope has built in debugging and testing support.  This chapter
-  describes these facilities and how you can debug and test your
-  components.

Deleted: zope2docs/trunk/zdgbook/source/ObjectPublishing.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/ObjectPublishing.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/ObjectPublishing.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,1297 +0,0 @@
-#################
-Object Publishing
-#################
-
-Introduction
-============
-
-Zope puts your objects on the web. This is called *object
-publishing*. One of Zope's unique characteristics is the way it
-allows you to walk up to your objects and call methods on them with
-simple URLs.  In addition to HTTP, Zope makes your objects available
-to other network protocols including FTP, WebDAV and XML-RPC.
-
-
-In this chapter you'll find out exactly how Zope publishes
-objects. You'll learn all you need to know in order to design your
-objects for web publishing.
-
- 
-HTTP Publishing
-===============
-
-When you contact Zope with a web browser, your browser sends an HTTP
-request to Zope's web server. After the request is completely
-received, it is processed by 'ZPublisher', which is Zope's object
-publisher. 'ZPublisher' is a kind of light-weight ORB (Object Request
-Broker). It takes the request and locates an object to handle the
-request. The publisher uses the request URL as a map to locate the
-published object. Finding an object to handle the request is called
-*traversal*, since the publisher moves from object to object as it
-looks for the right one. Once the published object is found, the
-publisher calls a method on the published object, passing it
-parameters as necessary.  The publisher uses information in the
-request to determine which method to call, and what parameters to
-pass. The process of extracting parameters from the request is called
-*argument marshalling*. The published object then returns a response,
-which is passed back to Zope's web server. The web server, then
-passes the response back to your web browser.
-
-
-The publishing process is summarized in [2-1]
-
-.. figure:: ../Figures/2-1.png
-
-   2.1 Object publishing
-
-
-Typically the published object is a persistent object that the
-published module loads from the ZODB.  See Chapter 4 for more
-information on the ZODB.
-
-
-This chapter will cover all the steps of object publishing in
-detail. To summarize, object publishing consists of the main steps:
-
-1. The client sends a request to the publisher
-
-2. The publisher locates the published object using the request
-   URL as a map.
-
-3. The publisher calls the published object with arguments from
-   the request.
-
-4. The publisher interprets and returns the results to the
-   client.
-
-The chapter will also cover all the technical details, special cases
-and extra-steps that this list glosses over.
-
-
-URL Traversal
-=============
-
-Traversal is the process the publisher uses to locate the published
-object. Typically the publisher locates the published object by
-walking along the URL. Take for example a collection of objects::
-
-      class Classification:
-          ...
-
-      class Animal:
-          ...
-
-          def screech(self, ...):
-              ...
-
-      vertebrates=Classification(...)
-      vertebrates.mammals=Classification(...)
-      vertebrates.reptiles=Classification(...)
-      vertebrates.mammals.monkey=Animal(...)
-      vertebrates.mammals.dog=Animal(...)
-      vertebrates.reptiles.lizard=Animal(...)
-
-
-This collection of objects forms an object hierarchy. Using Zope you
-can publish objects with URLs. For example, the URL
-'http://zope/vertebrates/mammals/monkey/screech', will traverse the
-object hierarchy, find the 'monkey' object and call its 'screech'
-method.
-
-.. figure:: ../Figures/2-2.png
-
-   2.2 Traversal path through an object hierarchy
-
-The publisher starts from the root object and takes each step in the
-URL as a key to locate the next object. It moves to the next object
-and continues to move from object to object using the URL as a guide.
-
-Typically the next object is a sub-object of the current object that
-is named by the path segment. So in the example above, when the
-publisher gets to the 'vertebrates' object, the next path segment is
-"mammals", and this tells the publisher to look for a sub-object of
-the current object with that name. Traversal stops when Zope comes to
-the end of the URL. If the final object is found, then it is
-published, otherwise an error is returned.
-
-
-Now let's take a more rigorous look at traversal.
-
-Traversal Interfaces
-====================
-
-Zope defines interfaces for publishable objects, and publishable
-modules.
-
-
-When you are developing for Zope you almost always use the 'Zope'
-package as your published module. However, if you are using
-'ZPublisher' outside of Zope you'll be interested in the published
-module interface.
-
-
-Publishable Object Requirements
-===============================
-
-Zope has few restrictions on publishable objects. The basic rule is
-that the object must have a doc string. This requirement goes for
-method objects too.
-
-Another requirement is that a publishable object must not have a name
-that begin with an underscore. These two restrictions are designed to
-keep private objects from being published.
-
-
-Finally, published objects cannot be Python module objects.
-
-Traversal Methods
-=================
-
-During traversal, 'ZPublisher' cuts the URL into path elements
-delimited by slashes, and uses each path element to traverse from the
-current object to the next object. 'ZPublisher' locates the next
-object in one of three ways:
-
-1. Using '__bobo_traverse__'
-
-2. Using 'getattr'
-
-3. Using dictionary access.
-
-First the publisher attempts to call the traversal hook method,
-'__bobo_traverse__'. If the current object has this method it is
-called with the request and the current path element. The method
-should return the next object or 'None' to indicate that a next
-object can't be found. You can also return a tuple of objects from
-'__bobo_traverse__' indicating a sequence of sub-objects. This allows
-you to add additional parent objects into the request. This is almost
-never necessary.
-
-
-Here's an example of how to use '__bobo_traverse__'::
-
-          def __bobo_traverse__(self, request, key):
-              # if there is a special cookie set, return special
-              # subobjects, otherwise return normal subobjects
-
-              if request.cookies.has_key('special'):
-                  # return a subobject from the special dict
-                  return self.special_subobjects.get(key, None)
-
-              # otherwise return a subobject from the normal dict
-              return self.normal_subobjects.get(key, None)
-
-
-This example shows how you can examine the request during the
-traversal process.
-
-If the current object does not define a '__bobo_traverse__'
-method, then the next object is searched for using 'getattr'.
-This locates sub-objects in the normal Python sense.
-
-If the next object can't be found with 'getattr', 'ZPublisher'
-calls on the current object as though it were a
-dictionary. Note: the path element will be a string, not an
-integer, so you cannot traverse sequences using index numbers
-in the URL.
-
-For example, suppose 'a' is the current object, and 'next' is
-the name of the path element. Here are the three things that
-'ZPublisher' will try in order to find the next object:
-
-  1. 'a.__bobo_traverse__("next")'
-
-  2. 'a.next'
-
-  3. 'a["next"]'
-
-
-Publishing Methods        
-==================
-
-Once the published object is located with traversal, Zope *publishes*
-it in one of three possible ways.
-
-- Calling the published object -- If the published object is a
-  function or method or other callable object, the publisher calls
-  it. Later in the chapter you'll find out how the publisher figures
-  out what arguments to pass when calling.
-
-- Calling the default method -- If the published object is not
-  callable, the publisher uses the default method. For HTTP 'GET' and
-  'POST' requests the default method is 'index_html'. For other HTTP
-  requests such as 'PUT' the publisher looks for a method named by
-  the HTTP method. So for an HTTP 'HEAD' request, the publisher would
-  call the 'HEAD' method on the published object.
-
-- Stringifying the published object -- If the published object isn't
-  callable, and doesn't have a default method, the publisher
-  publishes it using the Python 'str' function to turn it into a
-  string.
-
-
-After the response method has been determined and called, the
-publisher must interpret the results.
-
-Character Encodings for Responses
-=================================
-
-If the published method returns an object of type 'string', a plain
-8-bit character string, the publisher will use it directly as the
-body of the response.
-
-Things are different if the published method returns a unicode
-string, because the publisher has to apply some character
-encoding. The published method can choose which character encoding it
-uses by setting a 'Content-Type' response header which includes a
-'charset' property (setting response headers is explained later in
-this chapter). A common choice of character encoding is UTF-8. To
-cause the publisher to send unicode results as UTF-8 you need to set
-a 'Content-Type' header with the value 'text/html; charset=UTF-8'
-
-If the 'Content-Type' header does not include a charser property (or
-if this header has not been set by the published method) then the
-publisher will choose a default character encoding. Today this
-default is ISO-8859-1 (also known as Latin-1) for compatability with
-old versions of Zope which did not include Unicode support. At some
-time in the future this default is likely to change to UTF-8.
-
-HTTP Responses
-==============
-
-Normally the published method returns a string which is considered
-the body of the HTTP response. The response headers can be controlled
-by calling methods on the response object, which is described later
-in the chapter. Optionally, the published method can return a tuple
-with the title, and body of the response. In this case, the publisher
-returns an generated HTML page, with the first item of the tuple used
-for the HTML 'title' of the page, and the second item as the contents
-of the HTML 'body' tag. For example a response of::
-
-  ('response', 'the response')
-
-
-is turned into this HTML page::
-
-  <html>
-  <head><title>response</title></head>
-  <body>the response</body>
-  </html>
-
-Controlling Base HREF
-=====================
-
-When you publish an object that returns HTML relative links should
-allow you to navigate between methods. Consider this example::
-
-  class Example:
-      "example"
-
-      def one(self):
-          "method one"
-          return """<html>
-                    <head>
-                    <title>one</title>
-                    </head>
-                    <body>
-                    <a href="two">two</a> 
-                    </body>
-                    </html>"""
-
-      def two(self):
-          "method two"
-          return """<html>
-                    <head>
-                    <title>two</title>
-                    </head>
-                    <body>
-                    <a href="one">one</a> 
-                    </body>
-                    </html>"""
-
-
-However, the default method, 'index_html' presents a problem. Since
-you can access the 'index_html' method without specifying the method
-name in the URL, relative links returned by the 'index_html' method
-won't work right. For example::
-
-            class Example:
-                "example"
-
-                 def index_html(self):
-                    return """<html>
-                              <head>
-                              <title>one</title>
-                              </head>
-                              <body>
-                              <a href="one">one</a><br>
-                              <a href="two">two</a> 
-                              </body>
-                              </html>"""
-                 ...
-
-If you publish an instance of the 'Example' class with the URL
-'http://zope/example', then the relative link to method 'one' will be
-'http://zope/one', instead of the correct link,
-'http://zope/example/one'.
-
-
-Zope solves this problem for you by inserting a 'base' tag inside the
-'head' tag in the HTML output of 'index_html' method when it is
-accessed as the default method. You will probably never notice this,
-but if you see a mysterious 'base' tag in your HTML output, know you
-know where it came from. You can avoid this behavior by manually
-setting your own base with a 'base' tag in your 'index_html' method
-output.
-
-
-Response Headers
-----------------
-
-The publisher and the web server take care of setting response
-headers such as 'Content-Length' and 'Content-Type'. Later in
-the chapter you'll find out how to control these headers.
-Later you'll also find out how exceptions are used to set the
-HTTP response code.
-
-Pre-Traversal Hook
-------------------
-
-The pre-traversal hook allows your objects to take special action
-before they are traversed. This is useful for doing things like
-changing the request. Applications of this include special
-authentication controls, and virtual hosting support.
-
-If your object has a method named '__before_publishing_traverse__',
-the publisher will call it with the current object and the request,
-before traversing your object. Most often your method will change the
-request. The publisher ignores anything you return from the
-pre-traversal hook method.
-
-The 'ZPublisher.BeforeTraverse' module contains some functions that
-help you register pre-traversal callbacks. This allows you to perform
-fairly complex callbacks to multiple objects when a given object is
-about to be traversed.
-
-
-Traversal and Acquisition
--------------------------
-
-Acquisition affects traversal in several ways. See Chapter 5,
-"Acquisition" for more information on acquisition. The most obvious
-way in which acquisition affects traversal is in locating the next
-object in a path. As we discussed earlier, the next object during
-traversal is often found using 'getattr'. Since acquisition affects
-'getattr', it will affect traversal. The upshot is that when you are
-traversing objects that support implicit acquisition, you can use
-traversal to walk over acquired objects. Consider the object
-hierarchy rooted in 'fruit'::
-
-        from Acquisition import Implicit
-
-        class Node(Implicit):
-            ...
-
-        fruit=Node()
-        fruit.apple=Node()
-        fruit.orange=Node()
-        fruit.apple.strawberry=Node()
-        fruit.orange.banana=Node()
-
-When publishing these objects, acquisition can come into play. For
-example, consider the URL */fruit/apple/orange*. The publisher would
-traverse from 'fruit', to 'apple', and then using acquisition, it
-would traverse to 'orange'.
-
-Mixing acquisition and traversal can get complex. Consider the URL
-*/fruit/apple/orange/strawberry/banana*. This URL is functional but
-confusing. Here's an even more perverse but legal URL
-*/fruit/apple/orange/orange/apple/apple/banana*.
-
-
-In general you should limit yourself to constructing URLs which use
-acquisition to acquire along containment, rather than context
-lines. It's reasonable to publish an object or method that you
-acquire from your container, but it's probably a bad idea to publish
-an object or method that your acquire from outside your
-container. For example::
-
-        from Acquisition import Implicit
-
-        class Basket(Implicit):
-            ...
-            def numberOfItems(self):
-                "Returns the number of contained items"
-                ...
-
-        class Vegetable(Implicit):
-            ...
-            def texture(self):
-                "Returns the texture of the vegetable."
-
-        class Fruit(Implicit):
-            ...
-            def color(self):
-                "Returns the color of the fruit."
-
-         basket=Basket()
-         basket.apple=Fruit()
-         basket.carrot=Vegetable()
-
-The URL */basket/apple/numberOfItems* uses acquisition along
-containment lines to publish the 'numberOfItems' method (assuming
-that 'apple' doesn't have a 'numberOfItems' attribute). However, the
-URL */basket/carrot/apple/texture* uses acquisition to locate the
-'texture' method from the 'apple' object's context, rather than from
-its container. While this distinction may be obscure, the guiding
-idea is to keep URLs as simple as possible. By keeping acquisition
-simple and along containment lines your application increases in
-clarity, and decreases in fragility.
-
-
-A second usage of acquisition in traversal concerns the request. The
-publisher tries to make the request available to the published object
-via acquisition. It does this by wrapping the first object in an
-acquisition wrapper that allows it to acquire the request with the
-name 'REQUEST'. This means that you can normally acquire the request
-in the published object like so::
-
-        request=self.REQUEST # for implicit acquirers
-
-or like so::
-
-        request=self.aq_acquire('REQUEST') # for explicit acquirers
-
-Of course, this will not work if your objects do not support
-acquisition, or if any traversed objects have an attribute named
-'REQUEST'.
-
-Finally, acquisition has a totally different role in object
-publishing related to security which we'll examine next.
-
-Traversal and Security
-----------------------
-
-As the publisher moves from object to object during traversal it
-makes security checks. The current user must be authorized to access
-each object along the traversal path. The publisher controls access
-in a number of ways. For more information about Zope security, see
-Chapter 6, "Security".
-
-Basic Publisher Security
-------------------------
-
-The publisher imposes a few basic restrictions on traversable
-objects. These restrictions are the same of those for publishable
-objects. As previously stated, publishable objects must have doc
-strings and must not have names beginning with underscore.
-
-The following details are not important if you are using the Zope
-framework. However, if your are publishing your own modules, the rest
-of this section will be helpful.
-
-The publisher checks authorization by examining the '__roles__'
-attribute of each object as it performs traversal. If present, the
-'__roles__' attribute should be 'None' or a list of role names. If it
-is None, the object is considered public. Otherwise the access to the
-object requires validation.
-
-Some objects such as functions and methods do not support creating
-attributes (at least they didn't before Python 2). Consequently, if
-the object has no '__roles__' attribute, the publisher will look for
-an attribute on the object's parent with the name of the object
-followed by '__roles__'. For example, a function named 'getInfo'
-would store its roles in its parent's 'getInfo__roles__' attribute.
-
-If an object has a '__roles__' attribute that is not empty and not
-'None', the publisher tries to find a user database to authenticate
-the user. It searches for user databases by looking for an
-'__allow_groups__' attribute, first in the published object, then in
-the previously traversed object, and so on until a user database is
-found.
-
-When a user database is found, the publisher attempts to validate the
-user against the user database. If validation fails, then the
-publisher will continue searching for user databases until the user
-can be validated or until no more user databases can be found.
-
-The user database may be an object that provides a validate
-method::
-
-  validate(request, http_authorization, roles)
-
-where 'request' is a mapping object that contains request
-information, 'http_authorization' is the value of the HTTP
-'Authorization' header or 'None' if no authorization header was
-provided, and 'roles' is a list of user role names.
-
-The validate method returns a user object if succeeds, and 'None' if
-it cannot validate the user. See Chapter 6 for more information on
-user objects. Normally, if the validate method returns 'None', the
-publisher will try to use other user databases, however, a user
-database can prevent this by raising an exception.
-
-
-If validation fails, Zope will return an HTTP header that causes your
-browser to display a user name and password dialog. You can control
-the realm name used for basic authentication by providing a module
-variable named '__bobo_realm__'. Most web browsers display the realm
-name in the user name and password dialog box.
-
-If validation succeeds the publisher assigns the user object to the
-request variable, 'AUTHENTICATED_USER'. The publisher places no
-restriction on user objects.
-
-
-Zope Security
-
-When using Zope rather than publishing your own modules, the
-publisher uses acquisition to locate user folders and perform
-security checks. The upshot of this is that your published objects
-must inherit from 'Acquisition.Implicit' or
-'Acquisition.Explicit'. See Chapter 5, "Acquisition", for more
-information about these classes. Also when traversing each object
-must be returned in an acquisition context. This is done
-automatically when traversing via 'getattr', but you must wrap
-traversed objects manually when using '__getitem__' and
-'__bobo_traverse__'. For example::
-
-          class Example(Acquisition.Explicit):
-              ...
-
-              def __bobo_traverse__(self, name, request):
-                  ...
-                  next_object=self._get_next_object(name)
-                  return  next_object.__of__(self)      
-
-
-Finally, traversal security can be circumvented with the
-'__allow_access_to_unprotected_subobjects__' attribute as described
-in Chapter 6, "Security".
-
-
-Environment Variables
-=====================
-
-You can control some facets of the publisher's operation by setting
-environment variables.
-
-- 'Z_DEBUG_MODE' -- Sets debug mode. In debug mode tracebacks are not
-  hidden in error pages. Also debug mode causes 'DTMLFile' objects,
-  External Methods and help topics to reload their contents from disk
-  when changed. You can also set debug mode with the '-D' switch when
-  starting Zope.
-
-- 'Z_REALM' -- Sets the basic authorization realm. This controls the
-  realm name as it appears in the web browser's username and password
-  dialog. You can also set the realm with the '__bobo_realm__' module
-  variable, as mentioned previously.
-
-- 'PROFILE_PUBLISHER' -- Turns on profiling and sets the name of the
-  profile file. See the Python documentation for more information
-  about the Python profiler.
-
-
-Many more options can be set using switches on the startup
-script. See the *Zope Administrator's Guide* for more information.
-
-Testing
--------
-
-ZPublisher comes with built-in support for testing and working with
-the Python debugger.  This topic is covered in more detail in Chapter
-7, "Testing and Debugging".
-
-Publishable Module
-------------------
-
-If you are using the Zope framework, this section will be irrelevant
-to you. However, if you are publishing your own modules with
-'ZPublisher' read on.
-
-The publisher begins the traversal process by locating an object in
-the module's global namespace that corresponds to the first element
-of the path. Alternately the first object can be located by one of
-two hooks.
-
-If the module defines a 'web_objects' or 'bobo_application' object,
-the first object is searched for in those objects. The search happens
-according to the normal rules of traversal, using
-'__bobo_traverse__', 'getattr', and '__getitem__'.
-
-The module can receive callbacks before and after traversal. If the
-module defines a '__bobo_before__' object, it will be called with no
-arguments before traversal. Its return value is ignored. Likewise, if
-the module defines a '__bobo_after__' object, it will be called after
-traversal with no arguments. These callbacks can be used for things
-like acquiring and releasing locks.
-
-Calling the Published Object
-----------------------------
-
-Now that we've covered how the publisher located the published object
-and what it does with the results of calling it, let's take a closer
-look at how the published object is called.
-
-The publisher marshals arguments from the request and automatically
-makes them available to the published object. This allows you to
-accept parameters from web forms without having to parse the
-forms. Your objects usually don't have to do anything special to be
-called from the web. Consider this function::
-
-      def greet(name):
-          "greet someone"
-          return "Hello, %s" % name
-
-You can provide the 'name' argument to this function by calling it
-with a URL like *greet?name=World*. You can also call it with a HTTP
-'POST' request which includes 'name' as a form variable.
-
-In the next sections we'll take a closer look at how the publisher
-marshals arguments.
-
-Marshalling Arguments from the Request
---------------------------------------
-
-The publisher marshals form data from GET and POST requests. Simple
-form fields are made available as Python strings. Multiple fields
-such as form check boxes and multiple selection lists become
-sequences of strings. File upload fields are represented with
-'FileUpload' objects. File upload objects behave like normal Python
-file objects and additionally have a 'filename' attribute which is
-the name of the file and a 'headers' attribute which is a dictionary
-of file upload headers.
-
-The publisher also marshals arguments from CGI environment variables
-and cookies. When locating arguments, the publisher first looks in
-CGI environment variables, then other request variables, then form
-data, and finally cookies. Once a variable is found, no further
-searching is done. So for example, if your published object expects
-to be called with a form variable named 'SERVER_URL', it will fail,
-since this argument will be marshaled from the CGI environment first,
-before the form data.
-
-The publisher provides a number of additional special variables such
-as 'URL0' which are derived from the request. These are covered in
-the 'HTTPRequest' API documentation.
-
-Argument Conversion
--------------------
-
-The publisher supports argument conversion. For example consider this
-function::
-
-        def onethird(number):
-            "returns the number divided by three"
-            return number / 3.0
-
-This function cannot be called from the web because by default the
-publisher marshals arguments into strings, not numbers. This is why
-the publisher provides a number of converters. To signal an argument
-conversion you name your form variables with a colon followed by a
-type conversion code. For example, to call the above function with 66
-as the argument you can use this URL *onethird?number:int=66* The
-publisher supports many 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 a Python integer.
-
-- long -- Converts a variable to a Python long integer.
-
-- float -- Converts a variable to a Python floating point number.
-
-- string -- Converts a variable to a Python string.
-
-- ustring -- Converts a variable to a Python unicode string.
-
-- required -- Raises an exception if the variable is not present or
-  is an empty string.
-
-- ignore_empty -- Excludes a variable from the request if the
-  variable is an empty string.
-
-- date -- Converts a string to a *DateTime* object. The formats
-  accepted are fairly flexible, for example '10/16/2000', '12:01:13
-  pm'.
-
-- list -- Converts a variable to a Python list of values, even if
-  there is only one value.
-
-- tuple -- Converts a variable to a Python tuple of values, even if
-  there is only one value.
-
-- lines -- Converts a string to a Python list of values by splitting
-  the string on line breaks.
-
-- tokens -- Converts a string to a Python list of values by splitting
-  the string on spaces.
-
-- text -- Converts a variable to a string with normalized line
-  breaks.  Different browsers on various platforms encode line
-  endings differently, so this converter makes sure the line endings
-  are consistent, regardless of how they were encoded by the browser.
-
-- ulines, utokens, utext -- like lines, tokens, text, but using
-  unicode strings instead of plain strings.
-
-If the publisher cannot coerce a request variable into the type
-required by the type converter it will raise an error. This is useful
-for simple applications, but restricts your ability to tailor error
-messages. If you wish to provide your own error messages, you should
-convert arguments manually in your published objects rather than
-relying on the publisher for coercion. Another possibility is to use
-JavaScript to validate input on the client-side before it is
-submitted to the server.
-
-You can combine type converters to a limited extent. For example you
-could create a list of integers like so::
-
-        <input type="checkbox" name="numbers:list:int" value="1">
-        <input type="checkbox" name="numbers:list:int" value="2">
-        <input type="checkbox" name="numbers:list:int" value="3">
-
-In addition to these type converters, the publisher also supports
-method and record arguments.
-
-Character Encodings for Arguments
----------------------------------
-
-The publisher needs to know what character encoding was used by the
-browser to encode form fields into the request. That depends on
-whether the form was submitted using GET or POST (which the publisher
-can work out for itself) and on the character encoding used by the
-page which contained the form (for which the publisher needs your
-help).
-
-In some cases you need to add a specification of the character
-encoding to each fields type converter. The full details of how this
-works are explained below, however most users do not need to deal
-with the full details:
-
-1. If your pages all use the UTF-8 character encoding (or at least
-   all the pages that contain forms) the browsers will always use
-   UTF-8 for arguments. You need to add ':utf8' into all argument
-   type converts. For example:
-
-   <input type="text" name="name:utf8:ustring">
-   <input type="checkbox" name="numbers:list:int:utf8" value="1">
-   <input type="checkbox" name="numbers:list:int:utf8" value="1">
-
-     % Anonymous User - Apr. 6, 2004 5:56 pm:
-      121
-
-2. If your pages all use a character encoding which has ASCII as a
-   subset (such as Latin-1, UTF-8, etc) then you do not need to
-   specify any chatacter encoding for boolean, int, long, float, and
-   date types.  You can also omit the character encoding type
-   converter from string, tokens, lines, and text types if you only
-   need to handle ASCII characters in that form field.
-
-Character Encodings for Arguments; The Full Story
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you are not in one of those two easy categories, you first need to
-determine which character encoding will be used by the browser to
-encode the arguments in submitted forms.
-
-1. Forms submitted using GET, or using POST with 
-   "application/x-www-form-urlencoded" (the default) 
-
-   1. Page uses an encoding of unicode: Forms are submitted using
-      UTF8, as required by RFC 2718 2.2.5
-
-   2. Page uses another regional 8 bit encoding: Forms are often
-      submitted using the same encoding as the page. If you choose to
-      use such an encoding then you should also verify how browsers
-      behave.
-
-2. Forms submitted using "multipart/form-data":
-
-   According to HTML 4.01 (section 17.13.4) browsers should state
-   which character encoding they are using for each field in a
-   Content-Type header, however this is poorly supported. The current
-   crop of browsers appear to use the same encoding as the page
-   containing the form.
-
-   Every field needs that character encoding name appended to is
-   converter.  The tag parser insists that tags must only use
-   alphanumberic characters or an underscore, so you might need to
-   use a short form of the encoding name from the Python 'encodings'
-   library package (such as utf8 rather than UTF-8).
-
-
-Method Arguments
-----------------
-
-Sometimes you may wish to control which object is published based on
-form data. For example, you might want to have a form with a select
-list that calls different methods depending on the item
-chosen. Similarly, you might want to have multiple submit buttons
-which invoke a different method for each button.
-
-The publisher provides a way to select methods using form variables
-through use of the *method* argument type. The method type allows the
-request 'PATH_INFO' to be augmented using information from a form
-item name or value.
-
-If the name of a form field is ':method', then the value of the field
-is added to 'PATH_INFO'. For example, if the original 'PATH_INFO' is
-'foo/bar' and the value of a ':method' field is 'x/y', then
-'PATH_INFO' is transformed to 'foo/bar/x/y'. This is useful when
-presenting a select list. Method names can be placed in the select
-option values.
-
-If the name of a form field ends in ':method' then the part of the
-name before ':method' is added to 'PATH_INFO'. For example, if the
-original 'PATH_INFO' is 'foo/bar' and there is a 'x/y:method' field,
-then 'PATH_INFO' is transformed to 'foo/bar/x/y'. In this case, the
-form value is ignored. This is useful for mapping submit buttons to
-methods, since submit button values are displayed and should,
-therefore, not contain method names.
-
-Only one method field should be provided. If more than one method
-field is included in the request, the behavior is undefined.
-
-Record Arguments 
-----------------
-
-Sometimes you may wish to consolidate form data into a structure
-rather than pass arguments individually. Record arguments allow you
-to do this.
-
-The 'record' type converter allows you to combine multiple
-form variables into a single input variable. For example::
-
-  <input name="date.year:record:int">
-  <input name="date.month:record:int">
-  <input name="date.day:record:int">
-
-This form will result in a single variable, 'date', with
-attributes 'year', 'month', and 'day'.
-
-You can skip empty record elements with the 'ignore_empty'
-converter. For example::
-
-  <input type="text" name="person.email:record:ignore_empty">
-
-When the email form field is left blank the publisher skips over the
-variable rather than returning a null string as its value. When the
-record 'person' is returned it will not have an 'email' attribute if
-the user did not enter one.
-
-You can also provide default values for record elements with the
-'default' converter. For example::
-
-  <input type="hidden"
-         name="pizza.toppings:record:list:default" 
-         value="All">
-  <select multiple name="pizza.toppings:record:list:ignore_empty">
-  <option>Cheese</option>
-  <option>Onions</option>
-  <option>Anchovies</option>
-  <option>Olives</option>
-  <option>Garlic<option>
-  </select>
-
-The 'default' type allows a specified value to be inserted when the
-form field is left blank. In the above example, if the user does not
-select values from the list of toppings, the default value will be
-used. The record 'pizza' will have the attribute 'toppings' and its
-value will be the list containing the word "All" (if the field is
-empty) or a list containing the selected toppings.
-
-You can even marshal large amounts of form data into multiple records
-with the 'records' type converter. Here's an example::
-
-  <h2>Member One</h2>
-  Name:
-  <input type="text" name="members.name:records"><BR>
-  Email:
-  <input type="text" name="members.email:records"><BR>
-  Age:
-  <input type="text" name="members.age:int:records"><BR>
-
-  <H2>Member Two</H2>
-  Name:
-  <input type="text" name="members.name:records"><BR>
-  Email:
-  <input type="text" name="members.email:records"><BR>
-  Age:
-  <input type="text" name="members.age:int:records"><BR>
-
-This form data will be marshaled into a list of records named
-'members'. Each record will have a 'name', 'email', and 'age'
-attribute.
-
-Record marshalling provides you with the ability to create complex
-forms. However, it is a good idea to keep your web interfaces as
-simple as possible.
-
-Exceptions
-----------
-
-Unhandled exceptions are caught by the object publisher and are
-translated automatically to nicely formatted HTTP output.
-
-When an exception is raised, the exception type is mapped to an HTTP
-code by matching the value of the exception type with a list of
-standard HTTP status names. Any exception types that do not match
-standard HTTP status names are mapped to "Internal Error" (500). The
-standard HTTP status names are: "OK", "Created", "Accepted", "No
-Content", "Multiple Choices", "Redirect", "Moved Permanently", "Moved
-Temporarily", "Not Modified", "Bad Request", "Unauthorized",
-"Forbidden", "Not Found", "Internal Error", "Not Implemented", "Bad
-Gateway", and "Service Unavailable". Variations on these names with
-different cases and without spaces are also valid.
-
-An attempt is made to use the exception value as the body of the
-returned response. The object publisher will examine the exception
-value. If the value is a string that contains some white space, then
-it will be used as the body of the return error message. If it
-appears to be HTML, the error content type will be set to
-'text/html', otherwise, it will be set to 'text/plain'. If the
-exception value is not a string containing white space, then the
-object publisher will generate its own error message.
-
-There are two exceptions to the above rule:
-
-1. If the exception type is: "Redirect", "Multiple Choices" "Moved
-   Permanently", "Moved Temporarily", or "Not Modified", and the
-   exception value is an absolute URI, then no body will be provided
-   and a 'Location' header will be included in the output with the
-   given URI.
-
-2. If the exception type is "No Content", then no body will be
-   returned.
-
-When a body is returned, traceback information will be included in a
-comment in the output. As mentioned earlier, the environment variable
-'Z_DEBUG_MODE' can be used to control how tracebacks are included. If
-this variable is set then tracebacks are included in 'PRE' tags,
-rather than in comments. This is very handy during debugging.
-
-Exceptions and Transactions
----------------------------
-
-When Zope receives a request it begins a transaction. Then it begins
-the process of traversal. Zope automatically commits the transaction
-after the published object is found and called. So normally each web
-request constitutes one transaction which Zope takes care of for
-you. See Chapter 4. for more information on transactions.
-
-If an unhandled exception is raised during the publishing process,
-Zope aborts the transaction. As detailed in Chapter
-4. Zope handles 'ConflictErrors' by re-trying the request up to
-three times.  This is done with the 'zpublisher_exception_hook'.
-
-In addition, the error hook is used to return an error message to the
-user. In Zope the error hook creates error messages by calling the
-'raise_standardErrorMessage' method. This method is implemented by
-'SimpleItem.Item'. It acquires the 'standard_error_message' DTML
-object, and calls it with information about the exception.
-
-You will almost never need to override the
-'raise_standardErrorMessage' method in your own classes, since it is
-only needed to handle errors that are raised by other components. For
-most errors, you can simply catch the exceptions normally in your
-code and log error messages as needed. If you need to, you should be
-able to customize application error reporting by overriding the
-'standard_error_message' DTML object in your application.
-
-Manual Access to Request and Response
--------------------------------------
-
-You do not need to access the request and response directly most of
-the time. In fact, it is a major design goal of the publisher that
-most of the time your objects need not even be aware that they are
-being published on the web. However, you have the ability to exert
-more precise control over reading the request and returning the
-response.
-
-Normally published objects access the request and response by listing
-them in the signature of the published method. If this is not
-possible you can usually use acquisition to get a reference to the
-request. Once you have the request, you can always get the response
-from the request like so::
-
-  response=REQUEST.RESPONSE
-
-The APIs of the request and response are covered in the API
-documentation. Here we'll look at a few common uses of the request
-and response.
-
-One reason to access the request is to get more precise information
-about form data. As we mentioned earlier, argument marshalling comes
-from a number of places including cookies, form data, and the CGI
-environment. For example, you can use the request to differentiate
-between form and cookie data::
-
-  cookies = REQUEST.cookies # a dictionary of cookie data
-  form = REQUEST.form # a dictionary of form data
-
-One common use of the response object is to set response headers.
-Normally the publisher in concert with the web server will take care
-of response headers for you. However, sometimes you may wish manually
-control headers::
-
-  RESPONSE.setHeader('Pragma', 'No-Cache')
-
-Another reason to access the response is to stream response data. You
-can do this with the 'write' method::
-
-  while 1:
-      data=getMoreData() #this call may block for a while
-      if not data:
-          break
-      RESPONSE.write(data)
-
-Here's a final example that shows how to detect if your method is
-being called from the web. Consider this function::
-
-  def feedParrot(parrot_id, REQUEST=None):
-      ...
-
-      if REQUEST is not None:
-          return "<html><p>Parrot %s fed</p></html>" % parrot_id
-
-The 'feedParrot' function can be called from Python, and also from
-the web. By including 'REQUEST=None' in the signature you can
-differentiate between being called from Python and being called form
-the web. When the function is called from Python nothing is returned,
-but when it is called from the web the function returns an HTML
-confirmation message.
-
-Other Network Protocols
-=======================
-
-FTP
----
-
-Zope comes with an FTP server which allows users to treat the Zope
-object hierarchy like a file server. As covered in Chapter 3, Zope
-comes with base classes ('SimpleItem' and 'ObjectManager') which
-provide simple FTP support for all Zope objects. The FTP API is
-covered in the API reference.
-
-To support FTP in your objects you'll need to find a way to represent
-your object's state as a file. This is not possible or reasonable for
-all types of objects. You should also consider what users will do
-with your objects once they access them via FTP.  You should find out
-which tools users are likely to edit your object files.  For example,
-XML may provide a good way to represent your object's state, but it
-may not be easily editable by your users.  Here's an example class
-that represents itself as a file using RFC 822 format::
-
-  from rfc822 import Message
-  from cStringIO import StringIO
-
-  class Person(...):
-
-      def __init__(self, name, email, age):
-          self.name=name
-          self.email=email
-          self.age=age
-
-      def writeState(self):
-          "Returns object state as a string"
-          return "Name: %s\nEmail: %s\nAge: %s" % (self.name,
-                                                   self.email, 
-                                                   self.age)
-      def readState(self, data):
-          "Sets object state given a string"
-          m=Message(StringIO(data))
-          self.name=m['name']
-          self.email=m['email']
-          self.age=int(m['age'])
-
-The 'writeState' and 'readState' methods serialize and unserialize
-the 'name', 'age', and 'email' attributes to and from a string. There
-are more efficient ways besides RFC 822 to store instance attributes
-in a file, however RFC 822 is a simple format for users to edit with
-text editors.
-
-To support FTP all you need to do at this point is implement the
-'manage_FTPget' and 'PUT' methods. For example::
-
-  def manage_FTPget(self):
-      "Returns state for FTP"
-      return self.writeState()
-
-  def PUT(self, REQUEST):
-      "Sets state from FTP"
-       self.readState(REQUEST['BODY'])
-
-You may also choose to implement a 'get_size' method which returns
-the size of the string returned by 'manage_FTPget'. This is only
-necessary if calling 'manage_FTPget' is expensive, and there is a
-more efficient way to get the size of the file. In the case of this
-example, there is no reason to implement a 'get_size' method.
-
-One side effect of implementing 'PUT' is that your object now
-supports HTTP PUT publishing. See the next section on WebDAV for more
-information on HTTP PUT.
-
-That's all there is to making your object work with FTP. As you'll
-see next WebDAV support is similar.
-
-WebDAV
-------
-
-WebDAV is a protocol for collaboratively edit and manage files on
-remote servers. It provides much the same functionality as FTP, but
-it works over HTTP.
-
-It is not difficult to implement WebDAV support for your
-objects. Like FTP, the most difficult part is to figure out how to
-represent your objects as files.
-
-Your class must inherit from 'webdav.Resource' to get basic DAV
-support. However, since 'SimpleItem' inherits from 'Resource', your
-class probably already inherits from 'Resource'. For container
-classes you must inherit from 'webdav.Collection'. However, since
-'ObjectManager' inherits from 'Collection' you are already set so
-long as you inherit from 'ObjectManager'.
-
-In addition to inheriting from basic DAV classes, your classes must
-implement 'PUT' and 'manage_FTPget'. These two methods are also
-required for FTP support. So by implementing WebDAV support, you also
-implement FTP support.
-
-The permissions that you assign to these two methods will control the
-ability to read and write to your class through WebDAV, but the
-ability to see your objects is controlled through the "WebDAV access"
-permission.
-
-Supporting Write Locking
-------------------------
-
-Write locking is a feature of WebDAV that allows users to put lock on
-objects they are working on. Support write locking s easy. To
-implement write locking you must assert that your lass implements the
-'WriteLockInterface'. For example::
-
-  from webdav.WriteLockInterface import WriteLockInterface
-
-  class MyContentClass(OFS.SimpleItem.Item, Persistent):
-      __implements__ = (WriteLockInterface,)
-
-It's sufficient to inherit from 'SimpleItem.Item', since it inherits
-from 'webdav.Resource', which provides write locking long with other
-DAV support.
-
-In addition, your 'PUT' method should begin with calls to dav__init'
-and 'dav_simpleifhandler'. For example::
-
- def PUT(self, REQUEST, RESPONSE):
-     """
-     Implement WebDAV/HTTP PUT/FTP put method for this object.
-     """
-     self.dav__init(REQUEST, RESPONSE)
-     self.dav__simpleifhandler(REQUEST, RESPONSE)
-     ...
-
-Finally your class's edit methods should check to determine whether
-your object is locked using the 'ws_isLocked' method. If someone
-attempts to change your object when it is locked you should raise the
-'ResourceLockedError'. For example::
-
-  from webdav import ResourceLockedError
-
-  class MyContentClass(...):
-      ...
-
-      def edit(self, ...):
-          if self.ws_isLocked():
-              raise ResourceLockedError
-          ...
-
-WebDAV support is not difficult to implement, and as more WebDAV
-editors become available, it will become more valuable. If you choose
-to add FTP support to your class you should probably go ahead and
-support WebDAV too since it is so easy once you've added FTP support.
-
-XML-RPC
--------
-
-`XML-RPC <http://www.xmlrpc.com>`_ is a light-weight Remote Procedure
-Call protocol that uses XML for encoding and HTTP for
-transport. Fredrick Lund maintains a Python <XML-RPC module
-<http://www.pythonware.com/products/xmlrpc>`_ .
-
-All objects in Zope support XML-RPC publishing. Generally you will
-select a published object as the end-point and select one of its
-methods as the method. For example you can call the 'getId' method on
-a Zope folder at 'http://example.com/myfolder' like so::
-
-  import xmlrpclib
-  folder = xmlrpclib.Server('http://example.com/myfolder')
-  ids = folder.getId()
-
-You can also do traversal via a dotted method name. For example::
-
-  import xmlrpclib
-
-  # traversal via dotted method name
-  app = xmlrpclib.Server('http://example.com/app')
-  id1 = app.folderA.folderB.getId()
-
-  # walking directly up to the published object
-  folderB = xmlrpclib.Server('http://example.com/app/folderA/folderB')
-  id2 = folderB.getId()
-
-  print id1 == id2
-
-This example shows different routes to the same object publishing
-call.
-
-XML-RPC supports marshalling of basic Python types for both
-publishing requests and responses. The upshot of this arrangement is
-that when you are designing methods for use via XML-RPC you should
-limit your arguments and return values to simple values such as
-Python strings, lists, numbers and dictionaries. You should not
-accept or return Zope objects from methods that will be called via
-XML-RPC.
-
-
-XML-RPC does not support keyword arguments. This is a problem if your
-method expect keyword arguments.  This problem is noticeable when
-calling DTMLMethods and DTMLDocuments with XML-RPC.  Normally a DTML
-object should be called with the request as the first argument, and
-additional variables as keyword arguments.  You can get around this
-problem by passing a dictionary as the first argument. This will
-allow your DTML methods and documents to reference your variables
-with the 'var' tag.  However, you cannot do the following::
-
-  <dtml-var expr="REQUEST['argument']">
-
-Although the following will work::
-
-  <dtml-var expr="_['argument']">
-
-This is because in this case arguments *are* in the DTML namespace,
-but they are not coming from the web request.
-
-In general it is not a good idea to call DTML from XML-RPC since DTML
-usually expects to be called from normal HTTP requests.
-
-One thing to be aware of is that Zope returns 'false' for published
-objects which return None since XML-RPC has no concept of null.
-
-Another issue you may run into is that 'xmlrpclib' does not yet
-support HTTP basic authentication. This makes it difficult to call
-protected web resources. One solution is to patch
-'xmlrpclib'. Another solution is to accept authentication credentials
-in the signature of your published method.
-
-Summary
-=======
-
-Object publishing is a simple and powerful way to bring objects to
-the web. Two of Zope's most appealing qualities is how it maps
-objects to URLs, and you don't need to concern yourself with web
-plumbing. If you wish, there are quite a few details that you can use
-to customize how your objects are located and published.
-

Deleted: zope2docs/trunk/zdgbook/source/Outline.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/Outline.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/Outline.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,159 +0,0 @@
-#######
-Outline
-#######
-
-Covers audience, topic, and scope.  Gives brief description of the
-developers guide and what goals the guide tries to acomplish.  Gives
-simple chapter by chapter overview of entire guide.
-
-
-Interfaces
-==========
-
-Zope is moving toward a more "self-documenting" model, where Zope
-component describe themselves with interfaces.  Many of the prose
-descriptions and examples in this guide will be working with these
-kinds of components.  This chapter gives a brief overview of Zope
-interfaces, how they describe Zope components, and how developers can
-create their own interfaces.
-
-This section is meant to enable the reader to discover the Zope "API"
-for themselves.  One of the goals of this guide is *not* to be an
-exhaustive descrption of the Zope API, that can be found in the
-online help system and from Zope objects through their interfaces.
-
-The majority of the content of this chapter will come from the
-`Interface documentation
-<http://www.zope.org/Wikis/Interfaces/InterfaceUserDocumentation>`_
-
-1. What are interfaces, why are they useful?
-
-2. Reading interfaces
-
-3. Using and testing interfaces
-
-4. Defining interfaces
-
-
-Publishing
-==========
-
-One key facility that Zope provides for a component developer is
-access to a component through various network protocols, like HTTP.
-While a component can be designed to work exclusivly with other
-components through Python only interfaces, most components are
-designed to be used and managed through a network interface, most
-commonly HTTP.
-
-Zope provides network access to components by "publishing" them
-through various network interfaces like HTTP, FTP, WebDAV and
-XML-RPC.  This chapter describes how a component developer can
-publish their components "through the web" and other network
-protocols.
-
-1. Object publishing overview
-
-2. Traversal
-
-3. Network Protocols
-
-4. Publishable Interfaces
-
-5. Object marshalling
-
-6. Creating user interfaces
-
-   - with DTMLFile
-
-   - with presentation templates
-
-
-Products
-========
-
-Zope defines a system that allows component developers to distribute
-their components to other Zope users.  Components can be placed into
-a package called a "Product".  Products can be created either through
-the web, or in Python.  Through the web products are covered in *The
-Zope Book*, and this chapter describes the more advanced Python
-product interfaces that developers can use to distribute their
-Python-based components.
-
-The majority of the content of this chapter will come from
-Amos/Shane's `Product Tutorial
-<http://www.zope.org/Members/hathawsh/PythonProductTutorial>`_
-
-1. Introduction
-
-2. Development Process
-
-3. Product Architecture
-
-4. Building Product Classes
-
-5. Building Management Interfaces
-
-6. Packaging Products
-
-7. Evolving Products
-
-
-Persistence
-===========
-
-Most Zope components live in the Zope Object DataBase (ZODB).
-Components that are stored in ZODB are called *persistent*.  Creating
-persistent components is, for the most part, a trivial exercise, but
-ZODB does impose a few rules that persistent components must obey in
-oder to work properly.  This chapter describes the persistent model
-and the interfaces that persistent objects can use to live inside the
-ZODB.
-
-1. Persistence Architecture
-
-2. Using Persistent components
-
-3. Creating Persistent Objects
-
-4. Transactions
-
-
-Security
-========
-
-Zope has a very fine-grained, uniquely powerful security model.  This
-model allows Zope developers to create components that work safely in
-an environment used by many different users, all with varying levels
-of security privledge.
-
-This section describes Zope's security model and how component
-developers can work with it and manipulate it to define security
-policies specific to their needs or the needs of their components.
-
-The majority of the content of this chapter will come from Chris'
-first cut at `Security documentation
-<http://www.zope.org/Members/mcdonc/PDG/6-1-Security.stx>`_
-
-1. Security architecture
-
-2. Using protected components
-
-3. Implementing Security in your Component
-
-4. Security Policies
-
-
-Debugging and Testing
-=====================
-
-Covers debugging Zope and unit testing.
-
-- pdb debugging
-
-- Control Panel debug view
-
-- -D z2.py switch
-
-- unit testing
-
-  - zope fixtures for unit testing

Deleted: zope2docs/trunk/zdgbook/source/Products.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/Products.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/Products.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,1322 +0,0 @@
-#############
-Zope Products
-#############
-
-Introduction
-============
-
-Zope *products* extend Zope with new functionality.  Products most
-often provide new addable objects.  In this chapter, we are going to
-look at building products on the file system.  Filesystem products
-require more overhead to build, but offer more power and flexibility,
-and they can be developed with familiar tools such as text editors
-and version controlling systems.
-
-Soon we will make the examples referenced in this chapter available
-for download as an example product.  Until that time, you will see
-references to files in this chapter that are not available yet.  This
-will be made available soon.
-
-Development Process
-===================
-
-This chapter begins with a discussion of how you will develop
-products.  We'll focus on common engineering tasks that you'll
-encounter as you develop products.
-
-Consider Alternatives
----------------------
-
-Before you jump into the development of a product you should consider
-the alternatives.  Would your problem be better solved with External
-Methods, or Python Scripts? Products excel at extending Zope with new
-addable classes of objects.  If this does not figure centrally in
-your solution, you should look elsewhere.  Products, like External
-Methods allow you to write unrestricted Python code on the
-filesystem.
-
-Starting with Interfaces
-------------------------
-
-The first step in creating a product is to create one or more
-interfaces which describe the product.  See Chapter 2 for more
-information on interfaces and how to create them.
-
-Creating interfaces before you build an implementation is a good idea
-since it helps you see your design and assess how well it fulfills
-your requirements.
-
-Consider this interface for a multiple choice poll component (see
-`Poll.py <examples/Poll.py>`_)::
-
-  from zope.interface import Interface
-
-  class IPoll(Interface):
-      """A multiple choice poll"""
-
-      def castVote(index):
-          """Votes for a choice"""
-
-      def getTotalVotes():
-          """Returns total number of votes cast"""
-
-      def getVotesFor(index):
-          """Returns number of votes cast for a given response"""
-
-      def getResponses():
-          """Returns the sequence of responses"""
-
-      def getQuestion():
-          """Returns the question"""
-
-How you name your interfaces is entirely up to you.  Here we've
-decided to use prefix "I" in the name of the interface.
-
-Implementing Interfaces
------------------------
-
-After you have defined an interface for your product, the next step
-is to create a prototype in Python that implements your interface.
-
-Here is a prototype of a ``PollImplemtation`` class that implements the
-interface you just examined (see `PollImplementation.py
-<examples/PollImplementation.py>`_)::
-
-  from poll import Poll
-
-  class PollImplementation:
-      """A multiple choice poll, implements the Poll interface.
-
-      The poll has a question and a sequence of responses. Votes
-      are stored in a dictionary which maps response indexes to a
-      number of votes.
-      """
-
-      implements(IPoll)
-
-      def __init__(self, question, responses):
-          self._question = question
-          self._responses = responses
-          self._votes = {}
-          for i in range(len(responses)):
-              self._votes[i] = 0
-
-      def castVote(self, index):
-          """Votes for a choice"""
-          self._votes[index] = self._votes[index] + 1
-
-      def getTotalVotes(self):
-          """Returns total number of votes cast"""
-          total = 0
-          for v in self._votes.values():
-              total = total + v
-          return total
-
-      def getVotesFor(self, index):
-          """Returns number of votes cast for a given response"""
-          return self._votes[index]
-
-      def getResponses(self):
-          """Returns the sequence of responses"""
-          return tuple(self._responses)
-
-      def getQuestion(self):
-          """Returns the question"""
-          return self._question
-
-You can use this class interactively and test it.  Here's an example
-of interactive testing::
-
-  >>> from PollImplementation import PollImplementation
-  >>> p = PollImplementation("What's your favorite color?",
-  ...                        ["Red", "Green", "Blue", "I forget"])
-  >>> p.getQuestion()
-  "What's your favorite color?"
-  >>> p.getResponses()
-  ('Red', 'Green', 'Blue', 'I forget')
-  >>> p.getVotesFor(0)
-  0
-  >>> p.castVote(0)
-  >>> p.getVotesFor(0)
-  1
-  >>> p.castVote(2)
-  >>> p.getTotalVotes()
-  2
-  >>> p.castVote(4)
-  Traceback (innermost last):
-  File "<stdin>", line 1, in ?
-  File "PollImplementation.py", line 23, in castVote
-  self._votes[index] = self._votes[index] + 1
-  KeyError: 4
-
-Interactive testing is one of Python's great features.  It lets you
-experiment with your code in a simple but powerful way.
-
-At this point you can do a fair amount of work, testing and refining
-your interfaces and classes which implement them.  See Chapter 9 for
-more information on testing.
-
-So far you have learned how to create Python classes that are
-documented with interfaces, and verified with testing.  Next you'll
-examine the Zope product architecture.  Then you'll learn how to fit
-your well crafted Python classes into the product framework.
-
-Building Product Classes
-------------------------
-
-To turn a component into a product you must fulfill many contracts.
-For the most part these contracts are not yet defined in terms of
-interfaces.  Instead you must subclass from base classes that
-implement the contracts.  This makes building products confusing, and
-this is an area that we are actively working on improving.
-
-Base Classes
-------------
-
-Consider an example product class definition::
-
-  from Acquisition import Implicit
-  from Globals import Persistent
-  from AccessControl.Role import RoleManager
-  from OFS.SimpleItem import Item
-
-  class PollProduct(Implicit, Persistent, RoleManager, Item):
-      """
-      Poll product class
-      """
-      ...
-
-The order of the base classes depends on which classes you want to
-take precedence over others.  Most Zope classes do not define similar
-names, so you usually don't need to worry about what order these
-classes are used in your product.  Let's take a look at each of these
-base classes.
-
-
-Acquisition.Implicit
-~~~~~~~~~~~~~~~~~~~~
-
-This is the normal acquisition base class.  See the *API Reference*
-for the full details on this class.  Many Zope services such as
-object publishing and security use acquisition, so inheriting from
-this class is required for products.  Actually, you can choose to
-inherit from ``Acquisition.Explicit`` if you prefer, however, it will
-prevent folks from dynamically binding Python Scripts and DTML
-Methods to instances of your class.  In general you should subclass
-from ``Acquisition.Implicit`` unless you have a good reason not to.
-
-  XXX: is this true?  I thought that any ExtensionClass.Base can be
-  acquired.  The Implicit and Explicit just control how the class can
-  acquire, not how it *is* acquired.
-
-Globals.Persistent
-~~~~~~~~~~~~~~~~~~
-
-This base class makes instances of your product persistent.  For more
-information on persistence and this class see Chapter 4.
-
-In order to make your poll class persistent you'll need to make one
-change.  Since ``_votes`` is a dictionary this means that it's a
-mutable non-persistent sub-object.  You'll need to let the
-persistence machinery know when you change it::
-
-  def castVote(self, index):
-      """Votes for a choice"""
-      self._votes[index] = self._votes[index] + 1
-      self._p_changed = 1
-
-The last line of this method sets the ``_p_changed`` attribute to 1.
-This tells the persistence machinery that this object has changed and
-should be marked as ``dirty``, meaning that its new state should be
-written to the database at the conclusion of the current transaction.
-A more detailed explanation is given in the Persistence chapter of
-this guide.
-
-
-OFS.SimpleItem.Item
-~~~~~~~~~~~~~~~~~~~
-
-This base class provides your product with the basics needed to work
-with the Zope management interface.  By inheriting from ``Item`` your
-product class gains a whole host of features: the ability to be cut
-and pasted, capability with management views, WebDAV support, basic
-FTP support, undo support, ownership support, and traversal controls.
-It also gives you some standard methods for management views and
-error display including ``manage_main()``.  You also get the
-``getId()``, ``title_or_id()``, ``title_and_id()`` methods and the
-``this()`` DTML utility method.  Finally this class gives your
-product basic *dtml-tree* tag support.  ``Item`` is really an
-everything-but-the-kitchen-sink kind of base class.
-
-``Item`` requires that your class and instances have some management
-interface related attributes.
-
-- ``meta_type`` -- This attribute should be a short string which is
-  the name of your product class as it appears in the product add
-  list.  For example, the poll product class could have a
-  ``meta_type`` with value as ``Poll``.
-
-- ``id`` or ``__name__`` -- All ``Item`` instances must have an
-  ``id`` string attribute which uniquely identifies the instance
-  within it's container.  As an alternative you may use ``__name__``
-  instead of ``id``.
-
-- ``title`` -- All ``Item`` instances must have a ``title`` string
-  attribute.  A title may be an empty string if your instance does
-  not have a title.
-
-In order to make your poll class work correctly as an ``Item`` you'll
-need to make a few changes.  You must add a ``meta_type`` class
-attribute, and you may wish to add an ``id`` parameter to the
-constructor::
-
-  class PollProduct(..., Item):
-
-      meta_type = 'Poll'
-      ...
-
-      def __init__(self, id, question, responses):
-          self.id = id
-          self._question = question
-          self._responses = responses
-          self._votes = {}
-          for i in range(len(responses)):
-              self._votes[i] = 0
-
-
-Finally, you should probably place ``Item`` last in your list of base
-classes.  The reason for this is that ``Item`` provides defaults that
-other classes such as ``ObjectManager`` and ``PropertyManager``
-override.  By placing other base classes before ``Item`` you allow
-them to override methods in ``Item``.
-
-AccessControl.Role.RoleManager
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This class provides your product with the ability to have its
-security policies controlled through the web.  See Chapter 6 for more
-information on security policies and this class.
-
-OFS.ObjectManager
-~~~~~~~~~~~~~~~~~
-
-This base class gives your product the ability to contain other
-``Item`` instances.  In other words, it makes your product class like
-a Zope folder.  This base class is optional. See the *API Reference*
-for more details.  This base class gives you facilities for adding
-Zope objects, importing and exporting Zope objects, WebDAV, and FTP.
-It also gives you the ``objectIds``, ``objectValues``, and
-``objectItems`` methods.
-
-``ObjectManager`` makes few requirements on classes that subclass it.
-You can choose to override some of its methods but there is little
-that you must do.
-
-If you wish to control which types of objects can be contained by
-instances of your product you can set the ``meta_types`` class
-attribute.  This attribute should be a tuple of meta_types.  This
-keeps other types of objects from being created in or pasted into
-instances of your product.  The ``meta_types`` attribute is mostly
-useful when you are creating specialized container products.
-
-OFS.PropertyManager
-~~~~~~~~~~~~~~~~~~~
-
-This base class provides your product with the ability to have
-user-managed instance attributes.  See the *API Reference* for more
-details.  This base class is optional.
-
-Your class may specify that it has one or more predefined properties,
-by specifying a '_properties' class attribute.  For example::
-
-  _properties=({'id':'title', 'type': 'string', 'mode': 'w'},
-               {'id':'color', 'type': 'string', 'mode': 'w'},
-              )
-
-The ``_properties`` structure is a sequence of dictionaries, where
-each dictionary represents a predefined property.  Note that if a
-predefined property is defined in the ``_properties`` structure, you
-must provide an attribute with that name in your class or instance
-that contains the default value of the predefined property.
-
-Each entry in the ``_properties`` structure must have at least an
-``id`` and a ``type`` key.  The ``id`` key contains the name of the
-property, and the ``type`` key contains a string representing the
-object's type.  The ``type`` string must be one of the values:
-``float``, ``int``, ``long``, ``string``, ``lines``, ``text``,
-``date``, ``tokens``, ``selection``, or ``multiple section``.  For
-more information on Zope properties see the *Zope Book*.
-
-For ``selection`` and ``multiple selection`` properties, you must
-include an addition item in the property dictionary,
-``select_variable`` which provides the name of a property or method
-which returns a list of strings from which the selection(s) can be
-chosen.  For example::
-
-  _properties=({'id' : 'favorite_color',
-                'type' : 'selection',
-                'select_variable' : 'getColors'
-               },
-              )
-
-Each entry in the ``_properties`` structure may optionally provide a
-``mode`` key, which specifies the mutability of the property. The
-``mode`` string, if present, must be ``w``, ``d``, or ``wd``.
-
-A ``w`` present in the mode string indicates that the value of the
-property may be changed by the user.  A ``d`` indicates that the user
-can delete the property.  An empty mode string indicates that the
-property and its value may be shown in property listings, but that it
-is read-only and may not be deleted.
-
-Entries in the ``_properties`` structure which do not have a ``mode``
-item are assumed to have the mode ``wd`` (writable and deleteable).
-
-Security Declarations
----------------------
-
-In addition to inheriting from a number of standard base classes, you
-must declare security information in order to turn your component
-into a product.  See Chapter 6 for more information on security and
-instructions for declaring security on your components.
-
-Here's an example of how to declare security on the poll class::
-
-  from AccessControl import ClassSecurityInfo
-
-  class PollProduct(...):
-      ...
-
-      security = ClassSecurityInfo()
-
-      security.declareProtected('Use Poll', 'castVote')
-      def castVote(self, index):
-          ...
-
-      security.declareProtected('View Poll results', 'getTotalVotes')
-      def getTotalVotes(self):
-          ...
-
-      security.declareProtected('View Poll results', 'getVotesFor')
-      def getVotesFor(self, index):
-          ...
-
-      security.declarePublic('getResponses')
-      def getResponses(self):
-          ...
-
-      security.declarePublic('getQuestion')
-      def getQuestion(self):
-          ...
-
-For security declarations to be set up Zope requires that you
-initialize your product class.  Here's how to initialize your poll
-class::
-
-  from Globals import InitializeClass
-
-  class PollProduct(...):
-     ...
-
-  InitializeClass(PollProduct)
-
-Summary
--------
-
-Congratulations, you've created a product class.  Here it is in all
-its glory (see `examples/PollProduct.py <PollProduct.py>`_)::
-
-  from Poll import Poll
-  from AccessControl import ClassSecurityInfo
-  from Globals import InitializeClass
-  from Acquisition import Implicit
-  from Globals import Persistent
-  from AccessControl.Role import RoleManager
-  from OFS.SimpleItem import Item
-
-  class PollProduct(Implicit, Persistent, RoleManager, Item):
-      """Poll product class, implements Poll interface.
-
-      The poll has a question and a sequence of responses. Votes
-      are stored in a dictionary which maps response indexes to a
-      number of votes.
-      """
-
-      implements(IPoll)
-
-      meta_type = 'Poll'
-
-      security = ClassSecurityInfo()
-
-      def __init__(self, id, question, responses):
-          self.id = id
-          self._question = question
-          self._responses = responses
-          self._votes = {}
-          for i in range(len(responses)):
-              self._votes[i] = 0
-
-      security.declareProtected('Use Poll', 'castVote')
-      def castVote(self, index):
-          "Votes for a choice"
-          self._votes[index] = self._votes[index] + 1
-          self._p_changed = 1
-
-      security.declareProtected('View Poll results', 'getTotalVotes')
-      def getTotalVotes(self):
-          "Returns total number of votes cast"
-          total = 0
-          for v in self._votes.values():
-              total = total + v
-          return total
-
-      security.declareProtected('View Poll results', 'getVotesFor')
-      def getVotesFor(self, index):
-          "Returns number of votes cast for a given response"
-          return self._votes[index]
-
-      security.declarePublic('getResponses')
-      def getResponses(self):
-          "Returns the sequence of responses"
-          return tuple(self._responses)
-
-      security.declarePublic('getQuestion')
-      def getQuestion(self):
-          "Returns the question"
-          return self._question
-
-  InitializeClass(Poll)
-
-Now it's time to test your product class in Zope.  To do this you
-must register your product class with Zope.
-
-Registering Products
-====================
-
-Products are Python packages that live in 'lib/python/Products'.
-Products are loaded into Zope when Zope starts up.  This process is
-called *product initialization*.  During product initialization, each
-product is given a chance to register its capabilities with Zope.
-
-Product Initialization
-----------------------
-
-When Zope starts up it imports each product and calls the product's
-'initialize' function passing it a registrar object.  The
-'initialize' function uses the registrar to tell Zope about its
-capabilities.  Here is an example '__init__.py' file::
-
-  from PollProduct import PollProduct, addForm, addFunction
-
-  def initialize(registrar):
-      registrar.registerClass(
-          PollProduct,
-          constructors=(addForm, addFunction),
-          )
-
-This function makes one call to the *registrar* object which
-registers a class as an addable object.  The *registrar* figures out
-the name to put in the product add list by looking at the 'meta_type'
-of the class.  Zope also deduces a permission based on the class's
-meta-type, in this case *Add Polls* (Zope automatically pluralizes
-"Poll" by adding an "s").  The 'constructors' argument is a tuple of
-objects consisting of two functions: an add form which is called when
-a user selects the object from the product add list, and the add
-method which is the method called by the add form.  Note that these
-functions are protected by the constructor permission.
-
-Note that you cannot restrict which types of containers can contain
-instances of your classes.  In other words, when you register a
-class, it will appear in the product add list in folders if the user
-has the constructor permission.
-
-See the *API Reference* for more information on the
-``ProductRegistrar`` interface.
-
-Factories and Constructors
---------------------------
-
-Factories allow you to create Zope objects that can be added to
-folders and other object managers.  Factories are discussed in
-Chapter 12 of the *Zope Book*.  The basic work a factory does is to
-put a name into the product add list and associate a permission and
-an action with that name.  If you have the required permission then
-the name will appear in the product add list, and when you select the
-name from the product add list, the action method will be called.
-
-Products use Zope factory capabilities to allow instances of product
-classes to be created with the product add list.  In the above
-example of product initialization you saw how a factory is created by
-the product registrar.  Now let's see how to create the add form and
-the add list.
-
-The add form is a function that returns an HTML form that allows a
-users to create an instance of your product class.  Typically this
-form collects that id and title of the instance along with other
-relevant data.  Here's a very simple add form function for the poll
-class::
-
-  def addForm():
-      """Returns an HTML form."""
-      return """<html>
-      <head><title>Add Poll</title></head>
-      <body>
-      <form action="addFunction">
-      id <input type="type" name="id"><br>
-      question <input type="type" name="question"><br>
-      responses (one per line)
-      <textarea name="responses:lines"></textarea>
-      </form>
-      </body>
-      </html>"""
-
-Notice how the action of the form is ``addFunction``.  Also notice
-how the lines of the response are marshalled into a sequence.  See
-Chapter 2 for more information about argument marshalling and object
-publishing.
-
-It's also important to include a HTML ``head`` tag in the add form.
-This is necessary so that Zope can set the base URL to make sure that
-the relative link to the ``addFunction`` works correctly.
-
-The add function will be passed a ``FactoryDispatcher`` as its first
-argument which proxies the location (usually a Folder) where your
-product was added.  The add function may also be passed any form
-variables which are present in your add form according to normal
-object publishing rules.
-
-Here's an add function for your poll class::
-
-  def addFunction(dispatcher, id, question, responses):
-      """Create a new poll and add it to myself
-      """
-      p = PollProduct(id, question, responses)
-      dispatcher.Destination()._setObject(id, p)
-
-The dispatcher has three methods:
-
-- ``Destination`` -- The ``ObjectManager`` where your product was added.
-
-- ``DestinationURL`` -- The URL of the ``ObjectManager`` where your
-  product was added.
-
-- ``manage_main`` -- Redirects to a management view of the
-  ``ObjectManager`` where your product was added.
-
-Notice how it calls the ``_setObject()`` method of the destination
-``ObjectManager`` class to add the poll to the folder.  See the *API
-Reference* for more information on the ``ObjectManager`` interface.
-
-The add function should also check the validity of its input.  For
-example the add function should complain if the question or response
-arguments are not of the correct type.
-
-Finally you should recognize that the constructor functions are *not*
-methods on your product class.  In fact they are called before any
-instances of your product class are created.  The constructor
-functions are published on the web so they need to have doc strings,
-and are protected by a permission defined in during product
-initialization.
-
-Testing
--------
-
-Now you're ready to register your product with Zope.  You need to add
-the add form and add method to the poll module.  Then you should
-create a `Poll` directory in your `lib/python/Products` directory and
-add the `Poll.py`, `PollProduct.py`, and `__init__.py` files.  Then
-restart Zope.
-
-Now login to Zope as a manager and visit the web management
-interface.  You should see a 'Poll' product listed inside the
-*Products* folder in the *Control_Panel*.  If Zope had trouble
-initializing your product you will see a traceback here.  Fix your
-problems, if any and restart Zope.  If you are tired of all this
-restarting, take a look at the *Refresh* facility covered in Chapter
-7.
-
-Now go to the root folder.  Select *Poll* from the product add list.
-Notice how you are taken to the add form.  Provide an id, a question,
-and a list of responses and click *Add*.  Notice how you get a black
-screen.  This is because your add method does not return anything.
-Notice also that your poll has a broken icon, and only has the
-management views.  Don't worry about these problems now, you'll find
-out how to fix these problems in the next section.
-
-Now you should build some DTML Methods and Python Scripts to test
-your poll instance.  Here's a Python Script to figure out voting
-percentages::
-
-  ## Script (Python) "getPercentFor"
-  ##parameters=index
-  ##
-  """Returns the percentage of the vote given a response index. Note,
-  this script should be bound a poll by acquisition context."""
-  poll = context
-  return float(poll.getVotesFor(index)) / poll.getTotalVotes()
-
-
-Here's a DTML Method that displays poll results and allows you to
-vote::
-
-  <dtml-var standard_html_header>
-
-  <h2>
-    <dtml-var getQuestion>
-  </h2>
-
-  <form> <!-- calls this dtml method -->
-
-  <dtml-in getResponses>
-    <p>
-      <input type="radio" name="index" value="&dtml-sequence-index;">
-      <dtml-var sequence-item>
-    </p>
-  </dtml-in>
-
-  <input type="submit" value=" Vote ">
-
-  </form>
-
-  <!-- process form -->
-
-  <dtml-if index>
-    <dtml-call expr="castVote(index)">
-  </dtml-if>
-
-  <!-- display results -->
-
-  <h2>Results</h2>
-
-  <p><dtml-var getTotalVotes> votes cast</p>
-
-  <dtml-in getResponses>
-    <p>
-      <dtml-var sequence-item> -
-      <dtml-var expr="getPercentFor(_.get('sequence-index'))">%
-    </p>
-  </dtml-in>
-
-  <dtml-var standard_html_footer>
-
-To use this DTML Method, call it on your poll instance.  Notice how
-this DTML makes calls to both your poll instance and the
-``getPercentFor`` Python script.
-
-At this point there's quite a bit of testing and refinement that you
-can do.  Your main annoyance will be having to restart Zope each time
-you make a change to your product class (but see Chapter 9 for
-information on how to avoid all this restarting).  If you vastly
-change your class you may break existing poll instances, and will
-need to delete them and create new ones.  See Chapter 9 for more
-information on debugging techniques which will come in handy.
-
-Building Management Interfaces
-------------------------------
-
-Now that you have a working product let's see how to beef up its user
-interface and create online management facilities.
-
-Defining Management Views
--------------------------
-
-All Zope products can be managed through the web.  Products have a
-collection of management tabs or *views* which allow managers to
-control different aspects of the product.
-
-A product's management views are defined in the ``manage_options``
-class attribute.  Here's an example::
-
-        manage_options=(
-            {'label' : 'Edit', 'action' : 'editMethod'},
-            {'label' : 'View', 'action' : 'viewMethod'},
-            )
-
-The ``manage_options`` structure is a tuple that contains
-dictionaries.  Each dictionary defines a management view.  The view
-dictionary can have a number of items.
-
-- 'label' -- This is the name of the management view
-
-- 'action' -- This is the URL that is called when the view is
-  chosen. Normally this is the name of a method that displays a
-  management view.
-
-- 'target' -- An optional target frame to display the action. This
-  item is rarely needed.
-
-- 'help' -- Optional help information associated with the
-  view. You'll find out more about this option later.
-
-Management views are displayed in the order they are defined.
-However, only those management views for which the current user has
-permissions are displayed.  This means that different users may see
-different management views when managing your product.
-
-Normally you will define a couple custom views and reusing some
-existing views that are defined in your base classes.  Here's an
-example::
-
-  class PollProduct(..., Item):
-      ...
-
-      manage_options=(
-          {'label' : 'Edit', 'action' : 'editMethod'},
-          {'label' : 'Options', 'action' : 'optionsMethod'},
-          ) + RoleManager.manage_options + Item.manage_options
-
-This example would include the standard management view defined by
-``RoleManager`` which is *Security* and those defined by ``Item``
-which are *Undo* and *Ownership*.  You should include these standard
-management views unless you have good reason not to. If your class
-has a default view method (``index_html``) you should also include a
-*View* view whose action is an empty string.  See Chapter 2 for more
-information on ``index_html``.
-
-Note: you should not make the *View* view the first view on your
-class.  The reason is that the first management view is displayed
-when you click on an object in the Zope management interface.  If the
-*View* view is displayed first, users will be unable to navigate to
-the other management views since the view tabs will not be visible.
-
-Creating Management Views
--------------------------
-
-The normal way to create management view methods is to use DTML.  You
-can use the ``DTMLFile`` class to create a DTML Method from a file.
-For example::
-
-  from Globals import DTMLFile
-
-  class PollProduct(...):
-    ...
-
-    editForm = DTMLFile('dtml/edit', globals())
-    ...
-
-This creates a DTML Method on your class which is defined in the
-`dtml/edit.dtml` file.  Notice that you do not have to include the
-``.dtml`` file extension.  Also, don't worry about the forward slash
-as a path separator; this convention will work fine on Windows. By
-convention DTML files are placed in a ``dtml`` subdirectory of your
-product.  The ``globals()`` argument to the ``DTMLFile`` constructor
-allows it to locate your product directory.  If you are running Zope
-in debug mode then changes to DTML files are reflected right away. In
-other words you can change the DTML of your product's views without
-restarting Zope to see the changes.
-
-DTML class methods are callable directly from the web, just like
-other methods.  So now users can see your edit form by calling the
-``editForm`` method on instances of your poll class.  Typically DTML
-methods will make calls back to your instance to gather information
-to display.  Alternatively you may decide to wrap your DTML methods
-with normal methods.  This allows you to calculate information needed
-by your DTML before you call it.  This arrangement also ensures that
-users always access your DTML through your wrapper.  Here's an
-example::
-
-  from Globals import DTMLFile
-
-  class PollProduct(...):
-    ...
-
-    _editForm = DTMLFile('dtml/edit', globals())
-
-    def editForm(self, ...):
-        ...
-
-        return self._editForm(REQUEST, ...)
-
-
-When creating management views you should include the DTML variables
-``manage_page_header`` and ``manage_tabs`` at the top, and
-``manage_page_footer`` at the bottom.  These variables are acquired
-by your product and draw a standard management view header, tabs
-widgets, and footer.  The management header also includes CSS
-information which you can take advantage of if you wish to add CSS
-style information to your management views.  The management CSS
-information is defined in the
-`lib/python/App/dtml/manage_page_style.css.dtml`` file.  Here are the
-CSS classes defined in this file and conventions for their use.
-
-- 'form-help' -- Explanatory text related to forms.  In the future,
-  users may have the option to hide this text.
-
-- 'std-text' -- Declarative text unrelated to forms.  You should
-  rarely use this class.
-
-- 'form-title' -- Form titles.
-
-- 'form-label' -- Form labels for required form elements.
-
-- 'form-optional' -- Form labels for optional form elements.
-
-- 'form-element' -- Form elements.  Note, because of a Netscape bug,
-  you should not use this class on 'textarea' elements.
-
-- 'form-text' -- Declarative text in forms.
-
-- 'form-mono' -- Fixed width text in forms.  You should rarely use
-  this class.
-
-Here's an example management view for your poll class.  It allows you
-to edit the poll question and responses (see ``editPollForm.dtml``)::
-
-  <dtml-var manage_page_header>
-  <dtml-var manage_tabs>
-
-  <p class="form-help">
-  This form allows you to change the poll's question and
-  responses. <b>Changing a poll's question and responses
-  will reset the poll's vote tally.</b>.
-  </p>
-
-  <form action="editPoll">
-  <table>
-
-    <tr valign="top">
-      <th class="form-label">Question</th>
-      <td><input type="text" name="question" class="form-element"
-      value="&dtml-getQuestion;"></td>
-    </tr>
-
-    <tr valign="top">
-      <th class="form-label">Responses</th>
-      <td><textarea name="responses:lines" cols="50" rows="10">
-      <dtml-in getResponses>
-      <dtml-var sequence-item html_quote>
-      </dtml-in>
-      </textarea>
-      </td>
-    </tr>
-
-    <tr>
-      <td></td>
-      <td><input type="submit" value="Change" class="form-element"></td>
-    </tr>
-
-  </table>
-  </form>
-
-  <dtml-var manage_page_header>
-
-This DTML method displays an edit form that allows you to change the
-questions and responses of your poll.  Notice how poll properties are
-HTML quoted either by using ``html_quote`` in the ``dtml-var`` tag,
-or by using the ``dtml-var`` entity syntax.
-
-Assuming this DTML is stored in a file ``editPollForm.dtml`` in your
-product's ``dtml`` directory, here's how to define this method on
-your class::
-
-  class PollProduct(...):
-      ...
-
-      security.declareProtected('View management screens', 'editPollForm')
-      editPollForm = DTML('dtml/editPollForm', globals())
-
-Notice how the edit form is protected by the `View management
-screens` permission.  This ensures that only managers will be able to
-call this method.
-
-Notice also that the action of this form is ``editPoll``.  Since the
-poll as it stands doesn't include any edit methods you must define
-one to accept the changes.  Here's an ``editPoll`` method::
-
-  class PollProduct(...):
-      ...
-
-      def __init__(self, id, question, responses):
-          self.id = id
-          self.editPoll(question, response)
-
-      ...
-
-      security.declareProtected('Change Poll', 'editPoll')
-      def editPoll(self, question, responses):
-          """
-          Changes the question and responses.
-          """
-          self._question = question
-          self._responses = responses
-          self._votes = {}
-          for i in range(len(responses)):
-              self._votes[i] = 0
-
-Notice how the ``__init__`` method has been refactored to use the new
-``editPoll`` method.  Also notice how the ``editPoll`` method is
-protected by a new permissions, ``Change Poll``.
-
-There still is a problem with the ``editPoll`` method.  When you call
-it from the ``editPollForm`` through the web nothing is returned.
-This is a bad management interface.  You want this method to return
-an HTML response when called from the web, but you do not want it to
-do this when it is called from ``__init__``.  Here's the solution::
-
-  class Poll(...):
-      ...
-
-      def editPoll(self, question, responses, REQUEST=None):
-          """Changes the question and responses."""
-          self._question = question
-          self._responses = responses
-          self._votes = {}
-          for i in range(len(responses)):
-              self._votes[i] = 0
-          if REQUEST is not None:
-              return self.editPollForm(REQUEST,
-                  manage_tabs_message='Poll question and responses changed.')
-
-If this method is called from the web, then Zope will automatically
-supply the ``REQUEST`` parameter.  (See chapter 4 for more
-information on object publishing).  By testing the ``REQUEST`` you
-can find out if your method was called from the web or not.  If you
-were called from the web you return the edit form again.
-
-A management interface convention that you should use is the
-``manage_tab_message`` DTML variable.  If you set this variable when
-calling a management view, it displays a status message at the top of
-the page.  You should use this to provide feedback to users
-indicating that their actions have been taken when it is not obvious.
-For example, if you don't return a status message from your
-``editPoll`` method, users may be confused and may not realize that
-their changes have been made.
-
-Sometimes when displaying management views, the wrong tab will be
-highlighted.  This is because 'manage_tabs' can't figure out from the
-URL which view should be highlighted.  The solution is to set the
-'management_view' variable to the label of the view that should be
-highlighted.  Here's an example, using the 'editPoll' method::
-
-  def editPoll(self, question, responses, REQUEST=None):
-      """
-      Changes the question and responses.
-      """
-      self._question = question
-      self._responses = responses
-      self._votes = {}
-      for i in range(len(responses)):
-          self._votes[i] = 0
-      if REQUEST is not None:
-          return self.editPollForm(REQUEST,
-              management_view='Edit',
-              manage_tabs_message='Poll question and responses changed.')
-
-Now let's take a look a how to define an icon for your product.
-
-Icons
------
-
-Zope products are identified in the management interface with icons.
-An icon should be a 16 by 16 pixel GIF image with a transparent
-background.  Normally icons files are located in a ``www``
-subdirectory of your product package.  To associate an icon with a
-product class, use the ``icon`` parameter to the ``registerClass``
-method in your product's constructor.  For example::
-
-  def initialize(registrar):
-      registrar.registerClass(
-          PollProduct,
-          constructors=(addForm, addFunction),
-          icon='www/poll.gif'
-          )
-
-Notice how in this example, the icon is identified as being within
-the product's ``www`` subdirectory.
-
-See the *API Reference* for more information on the ``registerClass``
-method of the ``ProductRegistrar`` interface.
-
-Online Help
------------
-
-Zope has an online help system that you can use to provide help for
-your products.  Its main features are context-sensitive help and API
-help.  You should provide both for your product.
-
-
-Context Sensitive Help
-----------------------
-
-To create context sensitive help, create one help file per management
-view in your product's ``help`` directory.  You have a choice of
-formats including: HTML, DTML, structured text, GIF, JPG, and PNG.
-
-Register your help files at product initialization with the
-``registerHelp()`` method on the registrar object::
-
-  def initialize(registrar):
-      ...
-      registrar.registerHelp()
-
-This method will take care of locating your help files and creating
-help topics for each help file.  It can recognize these file
-extensions: ``.html``, ``.htm``, ``.dtml``, ``.txt``, ``.stx``,
-``.gif``, ``.jpg``, ``.png``.
-
-If you want more control over how your help topics are created you
-can use the ``registerHelpTopic()`` method which takes an id and a
-help topic object as arguments.  For example::
-
-  from mySpecialHelpTopics import MyTopic
-
-  def initialize(context):
-      ...
-      context.registerHelpTopic('myTopic', MyTopic())
-
-Your help topic should adhere to the 'HelpTopic' interface. See the
-*API Reference* for more details.
-
-The chief way to bind a help topic to a management screen is to
-include information about the help topic in the class's
-manage_options structure. For example::
-
-  manage_options = (
-      {'label': 'Edit',
-       'action': 'editMethod',
-       'help': ('productId','topicId')},
-      )
-
-The `help` value should be a tuple with the name of your product's
-Python package, and the file name (or other id) of your help topic.
-Given this information, Zope will automatically draw a *Help* button
-on your management screen and link it to your help topic.
-
-To draw a help button on a management screen that is not a view (such
-as an add form), use the 'HelpButton' method of the 'HelpSys' object
-like so::
-
-  <dtml-var "HelpSys.HelpButton('productId', 'topicId')">
-
-This will draw a help button linked to the specified help topic.  If
-you prefer to draw your own help button you can use the helpURL
-method instead like so::
-
-  <dtml-var "HelpSys.helpURL(
-    topic='productId',
-    product='topicId')">
-
-This will give you a URL to the help topic.  You can choose to draw
-whatever sort of button or link you wish.
-
-Other User Interfaces
----------------------
-
-In addition to providing a through the web management interface your
-products may also support many other user interfaces.  You product
-might have no web management interfaces, and might be controlled
-completely through some other network protocol.  Zope provides
-interfaces and support for FTP, WebDAV and XML-RPC.  If this isn't
-enough you can add other protocols.
-
-FTP and WebDAV Interfaces
--------------------------
-
-Both FTP and WebDAV treat Zope objects like files and
-directories.  See Chapter 3 for more information on FTP and WebDAV.
-
-By simply sub-classing from 'SimpleItem.Item' and 'ObjectManager' if
-necessary, you gain basic FTP and WebDAV support.  Without any work
-your objects will appear in FTP directory listings and if your class
-is an 'ObjectManager' its contents will be accessible via FTP and
-WebDAV.  See Chapter 2 for more information on implementing FTP and
-WebDAV support.
-
-XML-RPC and Network Services
-----------------------------
-
-XML-RPC is covered in Chapter 2.  All your product's methods can be
-accessible via XML-RPC.  However, if your are implementing network
-services, you should explicitly plan one or more methods for use with
-XML-RPC.
-
-Since XML-RPC allows marshalling of simple strings, lists, and
-dictionaries, your XML-RPC methods should only accept and return
-these types.  These methods should never accept or return Zope
-objects.  XML-RPC also does not support 'None' so you should use zero
-or something else in place of 'None'.
-
-Another issue to consider when using XML-RPC is security.  Many
-XML-RPC clients still don't support HTTP basic authorization.
-Depending on which XML-RPC clients you anticipate, you may wish to
-make your XML-RPC methods public and accept authentication
-credentials as arguments to your methods.
-
-Content Management Framework Interface
---------------------------------------
-
-The `Content Management Framework <http://cmf.zope.org>`_ is an
-evolving content management extension for Zope.  It provides a number
-of interfaces and conventions for content objects.  If you wish to
-support the CMF you should consult the CMF user interface guidelines
-and interface documentation.
-
-Supporting the CMF interfaces is not a large burden if you already
-support the Zope management interface.  You should consider
-supporting the CMF if your product class handles user manageable
-content such as documents, images, business forms, etc.
-
-Packaging Products
-------------------
-
-Zope products are normally packaged as tarballs.  You should create
-your product tarball in such a way as to allow it to be unpacked in
-the Products directory.  For example, `cd` to the Products directory
-and then issue a `tar` comand like so::
-
-  $ tar zcvf MyProduct-1.0.1.tgz MyProduct
-
-This will create a gzipped tar archive containing your product.  You
-should include your product name and version number in file name of
-the archive.
-
-See the `Poll-1.0.tgz <examples/Poll-1.0.tgz>`_ file for an example
-of a fully packaged Python product.
-
-
-Product Information Files
--------------------------
-
-Along with your Python and ZPT files you should include some
-information about your product in its root directory.
-
-- `README.txt` -- Provides basic information about your product.
-   Zope will parse this file as StructuredText and make it available
-   on the *README* view of your product in the control panel.
-
-- `VERSION.txt` -- Contains the name and version of your product on a
-  single line. For example, 'Multiple Choice Poll 1.1.0'.  Zope will
-  display this information as the 'version' property of your product
-  in the control panel.
-
-- `LICENSE.txt` -- Contains your product license, or a link to it.
-
-You may also wish to provide additional information.  Here are some
-suggested optional files to include with your product.
-
-- `INSTALL.txt` -- Provides special instructions for installing the
-  product and components on which it depends.  This file is only
-  optional if your product does not require more than an ungzip/untar
-  into a Zope installation to work.
-
-- `TODO.txt` -- This file should make clear where this product
-  release needs work, and what the product author intends to do about
-  it.
-
-- `CHANGES.txt` and `HISTORY.txt` -- 'CHANGES.txt' should enumerate
-  changes made in particular product versions from the last release
-  of the product. Optionally, a 'HISTORY.txt' file can be used for
-  older changes, while 'CHANGES.txt' lists only recent changes.
-
-- `DEPENDENCIES.txt` -- Lists dependencies including required os
-  platform, required Python version, required Zope version, required
-  Python packages, and required Zope products.
-
-Product Directory Layout
-------------------------
-
-By convention your product will contain a number of sub-directories.
-Some of these directories have already been discussed in this
-chapter. Here is a summary of them.
-
-- `www` -- Contains your icon & ZPT files.
-
-- `help` -- Contains your help files.
-
-- `tests` -- Contains your unit tests.
-
-It is not necessary to include these directories if your don't have
-anything to go in them.
-
-Evolving Products
-=================
-
-As you develop your product classes you will generally make a series
-of product releases.  While you don't know in advance how your
-product will change, when it does change there are measures that you
-can take to minimize problems.
-
-Evolving Classes
-----------------
-
-Issues can occur when you change your product class because instances
-of these classes are generally persistent.  This means that instances
-created with an old class will start using a new class.  If your
-class changes drastically this can break existing instances.
-
-The simplest way to handle this situation is to provide class
-attributes as defaults for newly added attributes.  For example if
-the latest version of your class expects an 'improved_spam' instance
-attribute while earlier versions only sported 'spam' attributes, you
-may wish to define an 'improved_spam' class attribute in your new
-class so your old objects won't break when they run with your new
-class.  You might set 'improved_spam' to None in your class, and in
-methods where you use this attribute you may have to take into
-account that it may be None.  For example::
-
-  class Sandwich(...):
-
-      improved_spam = None
-      ...
-
-      def assembleSandwichMeats(self):
-          ...
-          # test for old sandwich instances
-          if self.improved_spam is None:
-              self.updateToNewSpam()
-          ...
-
-Another solution is to use the standard Python pickling hook
-'__setstate__', however, this is in general more error prone and
-complex.
-
-A third option is to create a method to update old instances.  Then
-you can manually call this method on instances to update to them.
-Note, this won't work unless the instances function well enough to be
-accessible via the Zope management screens.
-
-While you are developing a product you won't have to worry too much
-about these details, since you can always delete old instances that
-break with new class definitions.  However, once you release your
-product and other people start using it, then you need to start
-planning for the eventuality of upgrading.
-
-Another nasty problem that can occur is breakage caused by renaming
-your product classes.  You should avoid this since it breaks all
-existing instances.  If you really must change your class name,
-provide aliases to it using the old name.  You may however, change
-your class's base classes without causing these kinds of problems.
-
-Evolving Interfaces
--------------------
-
-The basic rule of evolving interfaces is *don't do it*.  While you
-are working privately you can change your interfaces all you wish.
-But as soon as you make your interfaces public you should freeze
-them.  The reason is that it is not fair to users of your interfaces
-to changes them after the fact.  An interface is contract.  It
-specifies how to use a component and it specifies how to implement
-types of components.  Both users and developers will have problems if
-your change the interfaces they are using or implementing.
-
-The general solution is to create simple interfaces in the first
-place, and create new ones when you need to change an existing
-interface.  If your new interfaces are compatible with your existing
-interfaces you can indicate this by making your new interfaces extend
-your old ones.  If your new interface replaces an old one but does
-not extend it you should give it a new name such as,
-``WidgetWithBellsOn``.  Your components should continue to support
-the old interface in addition to the new one for a few releases.
-
-Conclusion
-==========
-
-Migrating your components into fully fledged Zope products is a
-process with a number of steps.  There are many details to keep track
-of.  However, if you follow the recipe laid out in this chapter you
-should have no problems.
-
-Zope products are a powerful framework for building web applications.
-By creating products you can take advantage of Zope's features
-including security, scalability, through the web management, and
-collaboration.

Deleted: zope2docs/trunk/zdgbook/source/Security.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/Security.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/Security.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,1300 +0,0 @@
-########
-Security
-########
-
-Introduction
-============
-
-A typical web application needs to be securely managed.  Different
-types of users need different kinds of access to the components that
-make up an application. To this end, Zope includes a comprehensive
-set of security features.  This chapter's goal is to shed light on
-Zope security in the context of Zope Product development.  For a more
-fundamental overview of Zope security, you may wish to refer to the
-*Zope Book*, Chapter 6, Users and Security.  Before diving into this
-chapter, you should have a basic understanding of how to build Zope
-Products as well as an understanding of how the Zope object publisher
-works. These topics are covered in Chapter 2 and Chapter 3,
-respectively.
-
-
-Security Architecture
-=====================
-
-The Zope security architecture is built around a *security policy*,
-which you can think of as the "access control philosophy" of
-Zope. This policy arbitrates the decisions Zope makes about whether
-to allow or deny access to any particular object defined within the
-system.
-
-How The Security Policy Relates to Zope's Publishing Machinery
---------------------------------------------------------------
-
-When access to Zope is performed via HTTP, WebDAV, or FTP, Zope's
-publishing machinery consults the security policy in order to
-determine whether to allow or deny access to a visitor for a
-particular object.  For example, when a user visits the root
-'index_html' object of your site via HTTP, the security policy is
-consulted by 'ZPublisher' to determine whether the user has
-permission to view the 'index_html' object itself.  For more
-information on this topic, see Chapter 3, "Object Publishing".
-
-The Zope security policy is consulted when an object is accessed the
-publishing machinery, for example when a web request is submitted.
-
-
-How The Security Policy Relates to Restricted Code
---------------------------------------------------
-
-*Restricted code* is generally any sort of logic that may be edited
-remotely (through the Web, FTP, via WebDAV or by other means). DTML
-Methods, SQLMethods, Python Scripts and Perl Scripts are examples of
-restricted code.
-
-When restricted code runs, any access to objects integrated with Zope
-security is arbitrated by the security policy. For example if you
-write a bit of restricted code with a line that attempts to
-manipulate an object you don't have sufficient permission to use, the
-security policy will deny you access to the object.  This generally
-is accomplished by raising an 'Unauthorized' exception, which is a
-Python string exception caught by a User Folder which signifies that
-Zope should attempt to get user credentials before obeying the
-request.  The particular code used to attempt to obtain the
-credentials is determined by the User Folder "closest" (folder-wise)
-to the object being accessed.
-
-The Zope security policy is consulted when an object is accessed by
-restricted code.
-
-'Unauthorized' Exceptions and Through-The-Web Code
---------------------------------------------------
-
-The security policy infrastructure will raise an 'Unauthorized'
-exception automatically when access to an object is denied.  When an
-'Unauthorized' exception is raised within Zope, it is handled in a
-sane way by Zope, generally by having the User Folder prompt the user
-for login information.  Using this functionality, it's possible to
-protect Zope objects through access control, only prompting the user
-for authentication when it is necessary to perform an action which
-requires privilege.
-
-An example of this behavior can be witnessed within the Zope
-Management interface itself.  The management interface prompts you to
-log in when visiting, for example, the '/manage' method of any Zope
-object.  This is due to the fact that an anonymous user does not
-generally possess the proper credentials to use the management
-interface.  If you're using Zope in the default configuration with
-the default User Folder, it prompts you to provide login information
-via an HTTP basic authentication dialog.
-
-How The Security Policy Relates To Unrestricted Code
-----------------------------------------------------
-
-There are also types of *unrestricted code* in Zope, where the logic
-is not constrained by the security policy. Examples of unrestricted
-code are the methods of Python classes that implement the objects in
-Python file-based add-on components.  Another example of unrestricted
-code can be found in External Method objects, which are defined in
-files on the filesystem.  These sorts of code are allowed to run
-"unrestricted" because access to the file system is required to
-define such logic.  Zope assumes that code defined on the filesystem
-is "trusted", while code defined "through the web" is not.  All
-filesystem-based code in Zope is unrestricted code.
-
-We'll see later that while the security policy does not constrain
-what your unrestricted code does, it can and should be used to
-control the ability to *call* your unrestricted code from within a
-restricted-code environment.
-
-The Zope security policy is *not* consulted when unrestricted code is
-run.
-
-Details Of The Default Zope Security Policy
--------------------------------------------
-
-In short, the default Zope security policy ensures the following:
-
-- access to an object which does not have any associated security
-  information is always denied.
-
-- if an object is associated with a permission, access is granted or
-  denied based on the user's roles.  If a user has a role which has
-  been granted the permission in question, access is granted.  If the
-  user does not possess a role that has been granted the permission
-  in question, access is denied.
-
-- if the object has a security assertion declaring it *public* , then
-  access will be granted.
-
-- if the object has a security assertion declaring it *private*, then
-  access will be denied.
-
-- accesses to objects that have names beginning with the underscore
-  character '_' are always denied.
-
-As we delve further into Zope security within this chapter, we'll see
-exactly what it means to associate security information with an
-object.
-
-
-Overview Of Using Zope Security Within Your Product
----------------------------------------------------
-
-Of course, now that we know what the Zope security policy is, we need
-to know how our Product can make use of it.  Zope developers leverage
-the Zope security policy primarily by making security declarations
-related to methods and objects within their Products.  Using security
-assertions, developers may deny or allow all types of access to a
-particular object or method unilaterally, or they may protect access
-to Zope objects more granularly by using permissions to grant or deny
-access based on the roles of the requesting user to the same objects
-or methods.
-
-
-For a more fundamental overview of Zope users, roles, and
-permissions, see the section titled "Authorization and Managing
-Security" in the Security Chapter of the *Zope Book*.
-
-Security Declarations In Zope Products
---------------------------------------
-
-Zope security declarations allow developers to make security
-assertions about a Product-defined object and its methods.
-Security declarations come in three basic forms.  These are:
-
-- public -- allow anybody to access the protected object
-  or method
-
-- private -- deny anyone access to the protected object or
-  method
-
-- protected -- protect access to the object or method via a
-  permission
-
-We'll see how to actually "spell" these security assertions a
-little later in this chapter.  In the meantime, just know that
-security declarations are fundamental to Zope Product security,
-and they can be used to protect access to an object by
-associating it with a permission.  We will refer to security
-declarations as "declarations" and "assertions" interchangeably
-within this chapter.
-
-
-Permissions In Zope Products
-============================
-
-A permission is the smallest unit of access to an object in Zope,
-roughly equivalent to the atomic permissions on files seen in Windows
-NT or UNIX: R (Read), W(Write), X(Execute), etc. However, unlike
-these types of mnemonic permissions shared by all sorts of different
-file types in an operating system product, in Zope, a permission
-usually describes a fine-grained logical operation which takes place
-upon an object, such as "View Management Screens" or "Add
-Properties".
-
-Zope administrators associate these permissions with *roles*, which
-they grant to Zope users.  Thus, declaring a protection assertion on
-a method of "View management screens" ensures that only users who
-possess roles which have been granted the "View management screens"
-permission are able to perform the action that the method defines.
-
-It is important to note that Zope's security architecture dictates
-that roles and users remain the domain of administrators, while
-permissions remain the domain of developers.  Developers of Products
-should not attempt to define roles or users, although they may (and
-usually must) define permissions.  Most importantly, a Zope
-administrator who makes use of your product should have the "last
-word" as regards which roles are granted which permissions, allowing
-her to protect her site in a manner that fits her business goals.
-
-Permission names are strings, and these strings are currently
-arbitrary.  There is no permission hierarchy, or list of "approved
-permissions".  Developers are encouraged to reuse Zope core
-permissions (e.g. "View", "Access contents information") when
-appropriate, or they may create their own as the need arises.  It is
-generally wise to reuse existing Zope permission names unless you
-specifically need to define your own.  For a list of existing Zope
-core permissions, see Appendix A, "Zope Core Permissions".
-
-Permissions are often tied to method declarations in Zope.  Any
-number of method declarations may share the same permission.  It's
-useful to declare the same permission on a set of methods which can
-logically be grouped together.  For example, two methods which return
-management forms for the object can be provided with the same
-permission, "View management screens".  Likewise, two entirely
-different objects can share a permission name to denote that the
-operation that's being protected is fundamentally similar.  For
-instance, most Product-defined objects reuse the Zope "View"
-permission, because most Zope objects need to be viewed in a web
-browser.  If you create an addable Zope class named 'MyObject', it
-doesn't make much sense to create a permission "View MyObject",
-because the generic "View" permission may be reused for this action.
-
-There is an exception to the "developers should not try to define
-roles" rule inasmuch as Zope allows developers to assign "default
-roles" to a permission.  This is primarily for the convenience of the
-Zope administrator, as default roles for a permission cause the Zope
-security machinery to provide a permission to a role *by default*
-when instances of a Product class are encountered during security
-operations.  For example, if your Product defines a permission "Add
-Poll Objects", this permission may be associated with a set of
-default roles, perhaps "Manager".  Default roles in Products should
-not be used against roles other than "Manager", "Anonymous", "Owner",
-and "Authenticated" (the four default Zope roles), as other roles are
-not guaranteed to exist in every Zope installation.
-
-Using security assertions in Zope is roughly analogous to assigning
-permission bit settings and ownership information to files in a UNIX
-or Windows filesystem.  Protecting objects via permissions allows
-developers and administrators to secure Zope objects independently of
-statements made in application code.
-
-Implementing Security In Python Products
-========================================
-
-Security Assertions
--------------------
-
-You may make several kinds of security assertions at the Python
-level.  You do this to declare accessibility of methods and
-subobjects of your classes. Three of the most common assertions that
-you'll want to make on your objects are:
-
-- this object is **public** (always accessible)
-
-- this object is **private** (not accessible by restricted code or by
-  URL traversal)
-
-- this object is **protected** by a specific permission
-
-There are a few other kinds of security assertions that are 
-much less frequently used but may be needed in some cases:
-
-- asserting that access to subobjects that do not have explicit
-  security information should be allowed rather than denied.
-
-- asserting what sort of protection should be used when determining
-  access to an *object itself* rather than a particular method of the
-  object
-
-It is important to understand that security assertions made in your
-Product code *do not* limit the ability of the code that the
-assertion protects.  Assertions only protect *access to this code*.
-The code which constitutes the body of a protected, private, or
-public method of a class defined in a Zope disk-based Product runs
-completely unrestricted, and is not subject to security constraints
-of any kind within Zope.  An exception to this rule occurs when
-disk-based-Product code calls a "through the web" method such as a
-Python Script or a DTML Method.  In this case, the security
-constraints imposed by these objects respective to the current
-request are obeyed.
-
-When Should I Use Security Assertions?
---------------------------------------
-
-If you are building an object that will be used from DTML or other
-restricted code, or that will be accessible directly through the web
-(or other remote protocols such as FTP or WebDAV) then you need to
-define security information for your object.
-
-Making Security Assertions
---------------------------
-
-As a Python developer, you make security assertions in your Python
-classes using 'SecurityInfo' objects. A 'SecurityInfo' object
-provides the interface for making security assertions about an object
-in Zope.
-
-The convention of placing security declarations inside Python code
-may at first seem a little strange if you're used to "plain old
-Python" which has no notion at all of security declarations.  But
-because Zope provides the ability to make these security assertions
-at such a low level, the feature is ubiquitous throughout Zope,
-making it easy to make these declarations once in your code, usable
-site-wide without much effort.
-
-Class Security Assertions
-=========================
-
-The most common kind of 'SecurityInfo' you will use as a component
-developer is the 'ClassSecurityInfo' object.  You use
-'ClassSecurityInfo' objects to make security assertions about methods
-on your classes.
-
-Classes that need security assertions are any classes that define
-methods that can be called "through the web".  This means any methods
-that can be called directly with URL traversal, from DTML Methods, or
-from Python-based Script objects.
-
-Declaring Class Security
-------------------------
-
-When writing the classes in your product, you create a
-'ClassSecurityInfo' instance *within each class that needs to play
-with the security model*. You then use the 'ClassSecurityInfo' object
-to make assertions about your class, its subobjects and its methods.
-
-The 'ClassSecurityInfo' class is defined in the 'AccessControl'
-package of the Zope framework. To declare class security information
-create a 'ClassSecurityInfo' class attribute named 'security'.  The
-name 'security' is used for consistency and for the benefit of new
-component authors, who often learn from looking at other people's
-code. You do not have to use the name 'security' for the security
-infrastructure to recognize your assertion information, but it is
-recommended as a convention.  For example::
-
-  from AccessControl import ClassSecurityInfo
-
-  class Mailbox(ObjectManager):
-    """A mailbox object that contains mail message objects."""
-
-    # Create a SecurityInfo for this class. We will use this 
-    # in the rest of our class definition to make security 
-    # assertions.
-    security = ClassSecurityInfo()
-
-    # Here is an example of a security assertion. We are 
-    # declaring that access to messageCount is public.
-    security.declarePublic('messageCount')
-
-    def messageCount(self):
-      """Return a count of messages."""
-      return len(self._messages)
-
-
-Note that in the example above we called the 'declarePublic' method
-of the 'ClassSecurityInfo' instance to declare that access to the
-'messageCount' method be public. To make security assertions for your
-object, you just call the appropriate methods of the
-'ClassSecurityInfo' object, passing the appropriate information for
-the assertion you are making.
-
-'ClassSecurityInfo' approach has a number of benefits. A major
-benefit is that it is very explicit, it allows your security
-assertions to appear in your code near the objects they protect,
-which makes it easier to assess the state of protection of your code
-at a glance. The 'ClassSecurityInfo' interface also allows you as a
-component developer to ignore the implementation details in the
-security infrastructure and protects you from future changes in those
-implementation details.
-
-Let's expand on the example above and see how to make the most common
-security assertions using the 'SecurityInfo' interface.
-
-To assert that a method is *public* (anyone may call it) you may call
-the 'declarePublic' method of the 'SecurityInfo' object, passing the
-name of the method or subobject that you are making the assertion
-on::
-
-  security.declarePublic(methodName)
-
-To assert that a method is *private* you call the 'declarePrivate'
-method of the 'SecurityInfo' object, passing the name of the method
-or subobject that you are making the assertion on::
-
-  security.declarePrivate(methodName)
-
-To assert that a method or subobject is *protected* by a particular
-permission, you call the 'declareProtected' method of the
-'SecurityInfo' object, passing a permission name and the name of a
-method to be protected by that permission::
-
-  security.declareProtected(permissionName, methodName)
-
-If you have lots of methods you want to protect under the same
-permission, you can pass as many methodNames ase you want::
-
-  security.declareProtected(permissionName, methodName1,
-  methodName2, methodName3, ...)
-
-Passing multiple names like this works for all of the 'declare'
-security methods ('declarePublic', 'declarePrivate', and
-'declareProtected').
-
-Deciding To Use 'declareProtected' vs. 'declarePublic' or 'declarePrivate'
---------------------------------------------------------------------------
-
-      If the method you're making the security declaration against is
-      innocuous, and you're confident that its execution will not
-      disclose private information nor make inappropriate changes to
-      system state, you should declare the method public.
-
-      If a method should never be run under any circumstances via
-      traversal or via through-the-web code, the method should be
-      declared private.  This is the default if a method has no
-      security assertion, so you needn't explicitly protect
-      unprotected methods unless you've used 'setDefaultAccess' to set
-      the object's default access policy to 'allow' (detailed in
-      *Other Assertions*, below).
-
-      If the method should only be executable by a certain class of
-      users, you should declare the method protected.
-
-A Class Security Example
-------------------------
-
-Let's look at an expanded version of our 'Mailbox' example that makes
-use of each of these types of security assertions::
-
-  from AccessControl import ClassSecurityInfo
-  import Globals
-
-  class Mailbox(ObjectManager):
-    """A mailbox object."""
-
-  # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-
-    security.declareProtected('View management screens', 'manage')
-    manage=HTMLFile('mailbox_manage', globals())
-
-    security.declarePublic('messageCount')
-    def messageCount(self):
-      """Return a count of messages."""
-      return len(self._messages)
-
-    # protect 'listMessages' with the 'View Mailbox' permission
-    security.declareProtected('View Mailbox', 'listMessages')
-
-    def listMessages(self):
-      """Return a sequence of message objects."""
-      return self._messages[:]
-
-    security.declarePrivate('getMessages')
-    def getMessages(self):
-      self._messages=GoGetEm()
-      return self._messages
-
-  # call this to initialize framework classes, which
-  # does the right thing with the security assertions.
-  Globals.InitializeClass(Mailbox)
-
-Note the last line in the example.  In order for security assertions
-to be correctly applied to your class, you must call the global class
-initializer ('Globals.InitializeClass') for all classes that have
-security information. This is very important - the global initializer
-does the "dirty work" required to ensure that your object is
-protected correctly based on the security assertions that you have
-made. If you don't run it on the classes that you've protected with
-security assertions, the security assertions will not be effective.
-
-Deciding Permission Names For Protected Methods
------------------------------------------------
-
-When possible, you should make use of an existing Zope permission
-within a 'declareProtected' assertion.  A list of the permissions
-which are available in a default Zope installation is available
-within Appendix A.  When it's not possible to reuse an existing
-permission, you should choose a permission name which is a verb or a
-verb phrase.
-
-Object Assertions
------------------
-
-Often you will also want to make a security assertion on the *object
-itself*. This is important for cases where your objects may be
-accessed in a restricted environment such as DTML. Consider the
-example DTML code::
-
-  <dtml-var expr="some_method(someObject)">
-
-Here we are trying to call 'some_method', passing the object
-'someObject'. When this is evaluated in the restricted DTML
-environment, the security policy will attempt to validate access to
-both 'some_method' and 'someObject'. We've seen how to make
-assertions on methods - but in the case of 'someObject' we are not
-trying to access any particular method, but rather the *object
-itself* (to pass it to 'some_method'). Because the security machinery
-will try to validate access to 'someObject', we need a way to let the
-security machinery know how to handle access to the object itself in
-addition to protecting its methods.
-
-To make security assertions that apply to the *object itself* you
-call methods on the 'SecurityInfo' object that are analogous to the
-three that we have already seen::
-
-  security.declareObjectPublic()
-
-  security.declareObjectPrivate()
-
-  security.declareObjectProtected(permissionName)
-
-The meaning of these methods is the same as for the method variety,
-except that the assertion is made on the object itself.
-
-An Object Assertion Example
----------------------------
-
-Here is the updated 'Mailbox' example, with the addition of a
-security assertion that protects access to the object itself with the
-'View Mailbox' permission::
-
-  from AccessControl import ClassSecurityInfo
-  import Globals
-
-  class Mailbox(ObjectManager):
-    """A mailbox object."""
-
-    # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-
-    # Set security for the object itself
-    security.declareObjectProtected('View Mailbox')
-
-    security.declareProtected('View management screens', 'manage')
-    manage=HTMLFile('mailbox_manage', globals())
-
-    security.declarePublic('messageCount')
-    def messageCount(self):
-      """Return a count of messages."""
-      return len(self._messages)
-
-    # protect 'listMessages' with the 'View Mailbox' permission
-    security.declareProtected('View Mailbox', 'listMessages')
-
-    def listMessages(self):
-      """Return a sequence of message objects."""
-      return self._messages[:]
-
-    security.declarePrivate('getMessages')
-    def getMessages(self):
-      self._messages=GoGetEm()
-      return self._messages
-
-  # call this to initialize framework classes, which
-  # does the right thing with the security assertions.
-  Globals.InitializeClass(Mailbox)
-
-Other Assertions
-----------------
-
-The SecurityInfo interface also supports the less common
-security assertions noted earlier in this document.
-
-To assert that access to subobjects that do not have explicit
-security information should be *allowed* rather than *denied* by
-the security policy, use::
-
-  security.setDefaultAccess("allow")
-
-This assertion should be used with caution. It will effectively
-change the access policy to "allow-by-default" for all
-attributes in your object instance (not just class attributes)
-that are not protected by explicit assertions.  By default, the
-Zope security policy flatly denies access to attributes and
-methods which are not mentioned within a security assertion.
-Setting the default access of an object to "allow" effectively
-reverses this policy, allowing access to all attributes and
-methods which are not explicitly protected by a security
-assertion.
-
-'setDefaultAccess' applies to attributes that are simple Python
-types as well as methods without explicit protection. This is
-important because some mutable Python types (lists, dicts) can
-then be modified by restricted code. Setting default access to
-"allow" also affects attributes that may be defined by the base
-classes of your class, which can lead to security holes if you
-are not sure that the attributes of your base classes are safe
-to access.
-
-Setting the default access to "allow" should only be done if you
-are sure that all of the attributes of your object are safe to
-access, since the current architecture does not support using
-explicit security assertions on non-method attributes.
-
-What Happens When You Make A Mistake Making 'SecurityInfo' Declarations?
-------------------------------------------------------------------------
-
-It's possible that you will make a mistake when making 'SecurityInfo'
-declarations.  For example, it is not legal to declare two
-conflicting permissions on a method::
-
-  class Foo(SimpleItem):
-      security = ClassSecurityInfo()
-
-      meta_type='Foo'
-
-      security.declareProtected('View foos', 'index_html')
-      def index_html(self):
-          """ make index_html web-publishable """
-          return "<html><body>hi!</body></html>"
-
-security.declareProtected('View', 'index_html')
-# whoops, declared a conflicting permission on index_html!
-
-When you make a mistake like this, the security machinery will
-accept the *first* declaration made in the code and will write
-an error to the Zope debug log upon encountering the second and
-following conflicting declarations during class initialization.
-It's similarly illegal to declare a method both private and
-public, or to declare a method both private and protected, or to
-declare a method both public and protected. A similar error will
-be raised in all of these cases.
-
-Note that Zope *will not* warn you if you misspell the name of
-a method in a declareProtected, declarePublic, or declarePrivate
-assertion.  For instance, you try to protect the 'index_html'
-method with the 'View' permission and make a mistake,
-spelling the name 'index_html' as 'inde_html', like so::
-
-  security.declareProtected('View', 'inde_html')
-  # whoops, declared a permission assertion for 'inde_html'
-  # when I really wanted it to be 'index_html'!
-  def index_html(self):
-      """ make index_html web-publishable """
-      return "<html><body>hi!</body></html>"
-
-You'll need to track down these kinds of problems yourself.
-
-Setting Default Roles For Permissions
--------------------------------------
-
-When defining operations that are protected by permissions, one thing
-you commonly want to do is to arrange for certain roles to be
-associated with a particular permission *by default* for instances of
-your object.
-
-For example, say you are creating a *News Item* object. You want
-'Anonymous' users to have the ability to view news items by default;
-you don't want the site manager to have to explicitly change the
-security settings for each *News Item* just to give the 'Anonymous"
-role 'View' permission.
-
-What you want as a programmer is a way to specify that certain roles
-should have certain permissions by default on instances of your
-object, so that your objects have sensible and useful security
-settings at the time they are created. Site managers can always
-*change* those settings if they need to, but you can make life easier
-for the site manager by setting up defaults that cover the common
-case by default.
-
-As we saw earlier, the 'SecurityInfo' interface provided a way to
-associate methods with permissions. It also provides a way to
-associate a permission with a set of default roles that should have
-that permission on instances of your object.
-
-To associate a permission with one or more roles, use the following::
-
-  security.setPermissionDefault(permissionName, rolesList)
-
-The *permissionName* argument should be the name of a permission that
-you have used in your object and *rolesList* should be a sequence
-(tuple or list) of role names that should be associated with
-*permissionName* by default on instances of your object.
-
-Note that it is not always necessary to use this method. All
-permissions for which you did not set defaults using
-'setPermissionDefault' are assumed to have a single default role of
-'Manager'.  Notable exceptions to this rule include 'View' and
-'Access contents information', which always have the default roles
-'Manager' and 'Anonymous'.
-
-The 'setPermissionDefault' method of the 'SecurityInfo' object should
-be called only once for any given permission name.
-
-
-An Example of Associating Default Roles With Permissions
---------------------------------------------------------
-
-Here is our 'Mailbox' example, updated to associate the 'View
-Mailbox' permission with the roles 'Manager' and 'Mailbox Owner' by
-default::
-
-  from AccessControl import ClassSecurityInfo
-  import Globals
-
-  class Mailbox(ObjectManager):
-    """A mailbox object."""
-
-    # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-
-    # Set security for the object itself
-    security.declareObjectProtected('View Mailbox')
-
-    security.declareProtected('View management screens', 'manage')
-    manage=DTMLFile('mailbox_manage', globals())
-
-    security.declarePublic('messageCount')
-    def messageCount(self):
-      """Return a count of messages."""
-      return len(self._messages)
-
-    security.declareProtected('View Mailbox', 'listMessages')
-    def listMessages(self):
-      """Return a sequence of message objects."""
-      return self._messages[:]
-
-    security.setPermissionDefault('View Mailbox', ('Manager', 'Mailbox Owner'))
-
-  # call this to initialize framework classes, which
-  # does the right thing with the security assertions.
-  Globals.InitializeClass(Mailbox)
-
-What Happens When You Make A Mistake Declaring Default Roles?
--------------------------------------------------------------
-
-It's possible that you will make a mistake when making default roles
-declarations.  For example, it is not legal to declare two
-conflicting default roles for a permission::
-
-  class Foo(SimpleItem):
-      security = ClassSecurityInfo()
-
-      meta_type='Foo'
-
-      security.declareProtected('View foos', 'index_html')
-      def index_html(self):
-          """ """
-          return "<html><body>hi!</body></html>"
-
-      security.setPermissionDefault('View foos', ('Manager',))
-
-      security.setPermissionDefault('View foos', ('Anonymous',))
-      # whoops, conflicting permission defaults!
-
-When you make a mistake like this, the security machinery will accept
-the *first* declaration made in the code and will write an error to
-the Zope debug log about the second and following conflicting
-declarations upon class initialization.
-
-What Can (And Cannot) Be Protected By Class Security Info?
-----------------------------------------------------------
-
-It is important to note what can and cannot be protected using the
-'ClassSecurityInfo' interface. First, the security policy relies on
-*Acquisition* to aggregate access control information, so any class
-that needs to work in the security policy must have either
-'Acquisition.Implicit' or 'Acquisition.Explicit' in its base class
-hierarchy.
-
-The current security policy supports protection of methods and
-protection of subobjects that are instances. It does *not* currently
-support protection of simple attributes of basic Python types
-(strings, ints, lists, dictionaries). For instance::
-
-  from AccessControl import ClassSecurityInfo
-  import Globals
-
-  # We subclass ObjectManager, which has Acquisition in its
-  # base class hierarchy, so we can use SecurityInfo.
-
-  class MyClass(ObjectManager):
-    """example class"""
-
-    # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-
-    # Set security for the object itself
-    security.declareObjectProtected('View')
-
-    # This is ok, because subObject is an instance
-    security.declareProtected('View management screens', 'subObject')
-    subObject=MySubObject()
-
-    # This is ok, because sayHello is a method
-    security.declarePublic('sayHello')
-    def sayHello(self):
-      """Return a greeting."""
-      return "hello!"
-
-    # This will not work, because foobar is not a method
-    # or an instance - it is a standard Python type
-    security.declarePublic('foobar')
-    foobar='some string'
-
-Keep this in mind when designing your classes. If you need simple
-attributes of your objects to be accessible (say via DTML), then you
-need to use the 'setDefaultAccess' method of 'SecurityInfo' in your
-class to allow this (see the note above about the security
-implications of this). In general, it is always best to expose the
-functionality of your objects through methods rather than exposing
-attributes directly.
-
-Note also that the actual 'ClassSecurityInfo' instance you use to
-make security assertions is implemented such that it is *never*
-accessible from restricted code or through the Web (no action on the
-part of the programmer is required to protect it).
-
-Inheritance And Class Security Declarations
--------------------------------------------
-
-Python inheritance can prove confusing in the face of security
-declarations.
-
-If a base class which has already been run through "InitializeClass"
-is inherited by a superclass, nothing special needs to be done to
-protect the base class' methods within the superclass unless you wish
-to modify the declarations made in the base class.  The security
-declarations "filter down" into the superclass.
-
-On the other hand, if a base class hasn't been run through the global
-class initializer ('InitializeClass'), you need to proxy its security
-declarations in the superclass if you wish to access any of its
-methods within through-the-web code or via URL traversal.
-
-In other words, security declarations that you make using
-'ClassSecurityInfo' objects effect instances of the class upon which
-you make the declaration. You only need to make security declarations
-for the methods and subobjects that your class actually *defines*. If
-your class inherits from other classes, the methods of the base
-classes are protected by the security declarations made in the base
-classes themselves. The only time you would need to make a security
-declaration about an object defined by a base class is if you needed
-to *redefine* the security information in a base class for instances
-of your own class. An example below redefines a security assertion in
-a subclass::
-
-  from AccessControl import ClassSecurityInfo
-  import Globals
-
-  class MailboxBase(ObjectManager):
-    """A mailbox base class."""
-
-    # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-
-    security.declareProtected('View Mailbox', 'listMessages')
-    def listMessages(self):
-      """Return a sequence of message objects."""
-      return self._messages[:]
-
-    security.setPermissionDefault('View Mailbox', ('Manager', 'Mailbox Owner'))
-
-  Globals.InitializeClass(MailboxBase)
-
-  class MyMailbox(MailboxBase):
-    """A mailbox subclass, where we want the security for 
-      listMessages to be public instead of protected (as 
-      defined in the base class)."""
-
-    # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-
-    security.declarePublic('listMessages')
-
-  Globals.InitializeClass(MyMailbox)
-
-Class Security Assertions In Non-Product Code (External Methods/Python Scripts)
--------------------------------------------------------------------------------
-
-Objects that are returned from Python Scripts or External Methods
-need to have assertions declared for themselves before they can be
-used in restricted code.  For example, assume you have an External
-Method that returns instances of a custom 'Book' class. If you want
-to call this External Method from DTML, and you'd like your DTML to
-be able to use the returned 'Book' instances, you will need to ensure
-that your class supports Acquisition, and you'll need to make
-security assertions on the 'Book' class and initialize it with the
-global class initializer (just as you would with a class defined in a
-Product). For example::
-
-  # an external method that returns Book instances
-
-  from AccessControl import ClassSecurityInfo
-  from Acquisition import Implicit
-  import Globals
-
-  class Book(Implicit):
-
-    def __init__(self, title):
-      self._title=title
-
-    # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-    security.declareObjectPublic()
-
-    security.declarePublic('getTitle')
-    def getTitle(self):
-      return self._title
-
-  Globals.InitializeClass(Book)
-
-  # The actual external method
-  def GetBooks(self):
-    books=[]
-    books.append(Book('King Lear').__of__(self))
-    books.append(Book('Romeo and Juliet').__of__(self))
-    books.append(Book('The Tempest').__of__(self))
-    return books
-
-Note that we *wrap* the book instances by way of their __of__ methods
-to obtain a security context before returning them.
-
-Note that this particular example is slightly dangerous.  You need to
-be careful that classes defined in external methods not be made
-persistent, as this can cause Zope object database inconsistencies.
-In terms of this example, this would mean that you would need to be
-careful to not attach the Book object returned from the 'GetBook'
-method to a persistent object within the ZODB. See Chapter 4, "ZODB
-Persistent Components" for more information.  Thus it's generally a
-good idea to define the Book class in a Product if you want books to
-be persistent.  It's also less confusing to have all of your security
-declarations in Products.
-
-However, one benefit of the 'SecurityInfo' approach is that it is
-relatively easy to subclass and add security info to classes that you
-did not write. For example, in an External Method, you may want to
-return instances of 'Book' although 'Book' is defined in another
-module out of your direct control. You can still use 'SecurityInfo'
-to define security information for the class by using::
-
-  # an external method that returns Book instances
-
-  from AccessControl import ClassSecurityInfo
-  from Acquisition import Implicit
-  import bookstuff
-  import Globals
-
-  class Book(Implicit, bookstuff.Book):
-    security = ClassSecurityInfo()
-    security.declareObjectPublic()
-    security.declarePublic('getTitle')
-
-  Globals.InitializeClass(Book)
-
-  # The actual external method
-  def GetBooks(self):
-    books=[]
-    books.append(Book('King Lear'))
-    books.append(Book('Romeo and Juliet'))
-    books.append(Book('The Tempest'))
-    return books
-
-Module Security Assertions
-==========================
-
-Another kind of 'SecurityInfo' object you will use as a
-component developer is the 'ModuleSecurityInfo' object.
-
-'ModuleSecurityInfo' objects do for objects defined in modules
-what 'ClassSecurityInfo' objects do for methods defined in
-classes.  They allow module-level objects (generally functions) to
-be protected by security assertions.  This is most useful when
-attempting to allow through-the-web code to 'import' objects
-defined in a Python module.
-
-One major difference between 'ModuleSecurityInfo' objects and
-ClassSecurityInfo objects is that 'ModuleSecurityInfo' objects
-cannot be declared 'protected' by a permission.  Instead,
-ModuleSecurityInfo objects may only declare that an object is
-'public' or 'private'.  This is due to the fact that modules are
-essentially "placeless", global things, while permission
-protection depends heavily on "place" within Zope.
-
-Declaring Module Security
--------------------------
-
-In order to use a filesystem Python module from restricted code such
-as Python Scripts, the module must have Zope security declarations
-associated with functions within it.  There are a number of ways to
-make these declarations:
-
-- By embedding the security declarations in the target module.  A
-  module that is written specifically for Zope may do so, whereas a
-  module not specifically written for Zope may not be able to do so.
-
-- By creating a wrapper module and embedding security declarations
-  within it.  In many cases it is difficult, impossible, or simply
-  undesirable to edit the target module.  If the number of objects in
-  the module that you want to protect or make public is small, you
-  may wish to simply create a wrapper module.  The wrapper module
-  imports objects from the wrapped module and provides security
-  declarations for them.
-
-- By placing security declarations in a filesystem Product.
-  Filesystem Python code, such as the '__init__.py' of a Product, can
-  make security declarations on behalf of an external module.  This
-  is also known as an "external" module security info declaration.
-
-The 'ModuleSecurityInfo' class is defined in the 'AccessControl'
-package of the Zope framework.
-
-Using ModuleSecurityInfo Objects
---------------------------------
-
-  Instances of 'ModuleSecurityInfo' are used in two different
-  situations.  In embedded declarations, inside the module they
-  affect.  And in external declarations, made on behalf of a
-  module which may never be imported.
-
-Embedded ModuleSecurityInfo Declarations
-----------------------------------------
-
-An embedded ModuleSecurityInfo declaration causes an object in its
-module to be importable by through-the-web code.
-
-Here's an example of an embedded declaration::
-
-  from AccessControl import ModuleSecurityInfo
-  modulesecurity = ModuleSecurityInfo()
-  modulesecurity.declarePublic('foo')
-
-  def foo():
-      return "hello"
-      # foo
-
-  modulesecurity.apply(globals())
-
-When making embedded ModuleSecurityInfo declarations, you should
-instantiate a ModuleSecurityInfo object and assign it to a name.
-It's wise to use the recommended name 'modulesecurity' for
-consistency's sake.  You may then use the modulesecurity object's
-'declarePublic' method to declare functions inside of the current
-module as public.  Finally, appending the last line
-("modulesecurity.apply(globals())") is an important step.  It's
-necessary in order to poke the security machinery into action.  The
-above example declares the 'foo' function public.
-
-The name 'modulesecurity' is used for consistency and for the benefit
-of new component authors, who often learn from looking at other
-people's code.  You do not have to use the name 'modulesecurity' for
-the security infrastructure to recognize your assertion information,
-but it is recommended as a convention.
-
-External ModuleSecurityInfo Declarations
-----------------------------------------
-
-By creating a ModuleSecurityInfo instance with a module name
-argument, you can make declarations on behalf of a module without
-having to edit or import the module.
-
-Here's an example of an external declaration::
-
-   from AccessControl import ModuleSecurityInfo
-   # protect the 'foo' function within (yet-to-be-imported) 'foomodule'
-   ModuleSecurityInfo('foomodule').declarePublic('foo')
-
-This declaration will cause the following code to work within
-PythonScripts::
-
-   from foomodule import foo
-
-When making external ModuleSecurityInfo declarations, you needn't use
-the "modulesecurity.apply(globals())" idiom demonstrated in the
-embedded declaration section above.  As a result, you needn't assign
-the ModuleSecurityInfo object to the name 'modulesecurity'.
-
-Providing Access To A Module Contained In A Package
----------------------------------------------------
-
-Note that if you want to provide access to a module inside of a
-package which lives in your PYTHONPATH, you'll need to provide
-security declarations for *all of the the packages and sub-packages
-along the path used to access the module.*
-
-For example, assume you have a function foo, which lives inside a
-module named 'module', which lives inside a package named 'package2',
-which lives inside a package named 'package1' You might declare the
-'foo' function public via this chain of declarations::
-
-  ModuleSecurityInfo('package1').declarePublic('package2')
-  ModuleSecurityInfo('package1.package2').declarePublic('module')
-  ModuleSecurityInfo('package1.package2.module').declarePublic('foo')
-
-Note that in the code above we took the following steps:
-
-- make a ModuleSecurityInfo object for 'package1'
-
-- call the declarePublic method of the 'package1'
-  ModuleSecurityInfo object, specifying 'package2' as what
-  we're declaring public.  This allows through the web code to
-  "see" package2 inside package1.
-
-- make a ModuleSecurityInfo object for 'package1.package2'.
-
-- call the declarePublic method of the 'package1.package2'
-  ModuleSecurityInfo object, specifying 'module' as what we're
-  declaring public.  This allows through the web code to "see"
-  'package1.package2.module'.
-
-- declare 'foo' public inside the ModuleSecurityInfo for
-  'package1.package2.module'. 
-
-Through-the-web code may now perform an import ala: 'import
-package1.package2.module.foo'
-
-Beware that Zope is buggy from 2.3 to 2.5.0b3.  If you make module
-security declarations in more than one Product, only one of the
-Products' security assertions will actually take effect.  This is
-repaired in Zope 2.5.0 and beyond.
-
-Many people who use Zope will be concerned with using
-ModuleSecurityInfo to make declarations on modules which live within
-Zope's Products directory.  This is just an example of declaring
-module security on a module within a package.  Here is an example of
-using ModuleSecurityInfo to make security declarations on behalf of
-the 'CatalogError' class in the 'ZCatalog.py' module.  This could be
-placed, for instance, within the any Product's '__init__.py' module::
-
-  from AccessControl import ModuleSecurityInfo
-  ModuleSecurityInfo('Products').declarePublic('Catalog')
-  ModuleSecurityInfo('Products.Catalog').declarePublic('CatalogError')
-
-Declaring Module Security On Modules Implemented In C
------------------------------------------------------
-
-Certain modules, such as the standard Python 'sha' module, provide
-extension types instead of classes, as the 'sha' module is
-implemented in C. Security declarations typically cannot be added to
-extension types, so the only way to use this sort of module is to
-write a Python wrapper class, or use External Methods.
-
-Default Module Security Info Declarations
------------------------------------------
-
-Through-the-web Python Scripts are by default able to import a small
-number of Python modules for which there are security
-declarations. These include 'string', 'math', and 'random'. The only
-way to make other Python modules available for import is to add
-security declarations to them in the filesystem.
-
-Utility Functions For Allowing Import of Modules By Through The Web Code
-------------------------------------------------------------------------
-
-Instead of manually providing security declarations for each function
-in a module, the utility function "allow_class" and "allow_module"
-have been created to help you declare the entire contents of a class
-or module as public.
-
-You can handle a module, such as base64, that contains only safe
-functions by writing 'allow_module("module_name")'.  For instance::
-
-  from Products.PythonScripts.Utility import allow_module
-  allow_module("base64")
-
-This statement declares all functions in the 'base64' module (
-'encode', 'decode', 'encodestring', and 'decodestring' ) as public,
-and from a script you will now be able to perform an import statement
-such as "from base64 import encodestring".
-
-
-To allow access to only some names in a module, you can eschew the
-allow_class and allow_module functions for the lessons you learned in
-the previous section and do the protection "manually"::
-
-  from AccessControl import ModuleSecurityInfo
-  ModuleSecurityInfo('module_name').declarePublic('name1','name2', ...)
-
-Making Permission Assertions On A Constructor
----------------------------------------------
-
-When you develop a Python disk-based product, you will generally be
-required to make "constructor" methods for the objects which you wish
-to make accessible via the Zope management interface by users of your
-Product.  These constructors are usually defined within the modules
-which contain classes which are intended to be turned into Zope
-instances.  For more information on how constructors are used in Zope
-with security, see Chapter 3 "Zope Products".
-
-The Zope Product machinery "bootstraps" Product-based classes with
-proper constructors into the namespace of the Zope management
-interface "Add" list at Zope startup time.  This is done as a
-consequence of registering a class by way of the Product's
-'__init__.py' 'intialize' function.  If you want to make, for
-example, the imaginary 'FooClass' in your Product available from the
-"Add" list, you may construct an '__init__.py' file that looks much
-like this::
-
-      from FooProduct import FooClass
-
-      def initialize(context):
-          """ Initialize classes in the FooProduct module """
-          context.registerClass(
-              FooProduct.FooClass, # the class object
-              permission='Add FooClasses',
-              constructors=(FooProduct.manage_addFooClassForm,
-                            FooProduct.manage_addFooClass),
-              icon='foo.gif'
-              )
-
-The line of primary concern to us above is the one which says
-"permission='Add FooClasses'".  This is a permission declaration
-which, thanks to Zope product initialization, restricts the adding of
-FooClasses to those users who have the 'Add FooClasses' permission by
-way of a role association determined by the system administrator.
-
-If you do not include a 'permission' argument to 'registerClass',
-then Zope will create a default permission named 'Add [meta-type]s'.
-So, for example, if your object had a meta_type of 'Animal', then
-Zope would create a default permission, 'Add Animals'.  For the most
-part, it is much better to be explicit then to rely on Zope to take
-care of security details for you, so be sure to specify a permission
-for your object.
-
-Designing For Security
-======================
-
-"Security is hard." -- Jim Fulton.
-
-When you're under a deadline, and you "just want it to work", dealing
-with security can be difficult.  As a component developer, following
-these basic guidelines will go a long way toward avoiding problems
-with security integration. They also make a good debugging checklist!
-
-- Ensure that any class that needs to work with security has
-  'Acquisition.Implicit' or 'Acquisition.Explicit' somewhere in its
-  base class hierarchy.
-
-- Design the interface to your objects around methods; don't expect
-  clients to access instance attributes directly.
-
-- Ensure that all methods meant for use by restricted code have been
-  protected with appropriate security assertions.
-
-- Ensure that you called the global class initializer on all classes
-  that need to work with security.
-
-Compatibility
-=============
-
-The implementation of the security assertions and 'SecurityInfo'
-interfaces described in this document are available in Zope 2.3 and
-higher.
-
-Older Zope Products do not use the 'SecurityInfo' interfaces for
-security assertions, because these interfaces didn't exist at the
-time.  These Zope products will continue to work without modification
-until further notice.
-
-Using The RoleManager Base Class With Your Zope Product
-=======================================================
-
-After your Product is deployed, system managers and other users of
-your Product often must deal with security settings on instances they
-make from your classes.
-
-Product classes which inherit Zope's standard RoleManager base class
-allow instances of the class to present a security interface.  This
-security interface allows managers and developers of a site to
-control an instance's security settings via the Zope management
-interface.
-
-The user interface is exposed via the *Security* management view.
-From this view, a system administrator may secure instances of your
-Product's class by associating roles with permissions and by
-asserting that your object instance contains "local roles".  It also
-allows them to create "user-defined roles" within the Zope management
-framework in order to associate these roles with the permissions of
-your product and with users.  This user interface and its usage
-patterns are explained in more detail within the Zope Book's security
-chapter.
-
-If your Product's class does not inherit from 'RoleManager', its
-methods will still retain the security assertions associated with
-them, but you will be unable to allow users to associate roles with
-the permissions you've defined respective to instances of your class.
-Your objects will also not allow local role definitions.  Note that
-objects which inherit from the 'SimpleItem.SimpleItem' mixin class
-already inherit from 'RoleManager'.
-
-Conclusion
-==========
-
-Zope security is based upon roles and permissions. Users have
-roles. Security policies map permissions to roles. Classes protect
-methods with permissions. As a developer you main job is to protect
-your classes by associating methods with permissions. Of course there
-are many other details such as protecting modules and functions,
-creating security user interfaces, and initializing security
-settings.

Deleted: zope2docs/trunk/zdgbook/source/TestingAndDebugging.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/TestingAndDebugging.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/TestingAndDebugging.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,800 +0,0 @@
-#####################
-Testing and Debugging
-#####################
-
-As you develop Zope applications you may run into problems.  This
-chapter covers debugging and testing techniques that can help you.
-The Zope debugger allow you to peek inside a running process and find
-exactly what is going wrong.  Unit testing allows you to automate the
-testing process to ensure that your code still works correctly as you
-change it.  Finally, Zope provides logging facilities which allow you
-to emit warnings and error messages.
-
-
-Debugging
-=========
-
-Zope provides debugging information through a number of sources.  It
-also allows you a couple avenues for getting information about Zope
-as it runs.
-
-The Control Panel
------------------
-
-The control panel provides a number of views that can help you debug
-Zope, especially in the area of performance.  The *Debugging
-Information* link on the control panel provides two views, *Debugging
-Info* and *Profiling*.
-
-Debugging info provides information on the number of object
-references and the status of open requests.  The object references
-list displays the name of the object and the number of references to
-that object in Zope.  Understanding how reference counts help
-debugging is a lengthy subject, but in general you can spot memory
-leaks in your application if the number of references to certain
-objects increases without bound.  The busier your site is, or the
-more content it holds, the more reference counts you will tend to
-have.
-
-Profiling uses the standard Python profiler.  This is turned on by
-setting the 'PROFILE_PUBLISHER' environment variable before executing
-Zope.
-
-When the profiler is running, the performance of your Zope system
-will suffer a lot.  Profiling should only be used for short periods
-of time, or on a separate ZEO client so that your normal users to not
-experience this significant penalty.
-
-Profiling provides you with information about which methods in your
-Zope system are taking the most time to execute.  It builds a
-*profile*, which lists the busiest methods on your system, sorted by
-increasing resource usage.  For details on the meaning of the
-profiler's output, read the `standard Python documentation
-<http://www.python.org/doc/current/lib/profile.html>`_
-
-Product Refresh Settings
-------------------------
-
-As of Zope 2.4 there is a *Refresh* view on all Control Panel
-Products.  Refresh allows you to reload your product's modules as you
-change them, rather than having to restart Zope to see your changes.
-The *Refresh* view provides the same debugging functionality
-previously provided by Shane Hathaway's Refresh Product.
-
-To turn on product refresh capabilities place a 'refresh.txt' file in
-your product's directory.  Then visit the *Refresh* view of your
-product in the management interface.  Here you can manually reload
-your product's modules with the *Refresh this product* button.  This
-allows you to immediately see the effect of your changes, without
-restarting Zope.  You can also turn on automatic refreshing which
-causes Zope to frequently check for changes to your modules and
-refresh your product when it detects that your files have changed.
-Since automatic refresh causes Zope to run more slowly, it is a good
-idea to only turn it on for a few products at a time.
-
-Debug Mode
-----------
-
-Setting the 'Z_DEBUG_MODE=1' environment puts Zope into debug mode.
-This mode reduces the performance of Zope a little bit.  Debug model
-has a number of wide ranging effects:
-
-- Tracebacks are shown on the browser when errors are raised.
-
-- External Methods and DTMLFile objects are checked to see if they
-  have been modified every time they are called.  If modified, they
-  are reloaded.
-
-- Zope will not fork into the background in debug mode, instead, it
-  will remain attached to the terminal that started it and the main
-  logging information will be redirected to that terminal.
-
-Normally, debug mode is set using the '-D' switch when starting Zope,
-though you can set the environment variable directly if you wish.
-
-By using debug mode and product refresh together you will have little
-reason to restart Zope while developing.
-
-The Python Debugger
--------------------
-
-Zope is integrated with the Python debugger (pdb).  The Python
-debugger is pretty simple as command line debuggers go, and anyone
-familiar with other popular command line debuggers (like gdb) will
-feel right at home in pdb.
-
-For an introduction to pdb see the standard `pdb documentation
-<http://www.python.org/doc/current/lib/module-pdb.html>`_ .
-
-There are a number of ways to debug a Zope process:
-
-  o You can shut down the Zope server and simulate a request on the
-    command line.
-
-  o You can run a special ZEO client that debugs a running server.
-
-  o You can run Zope in debug model and enter the debugger
-    through Zope's terminal session.
-
-The first method is an easy way to debug Zope if you are not running
-ZEO.  First, you must first shut down the Zope process.  It is not
-possible to debug Zope in this way and run it at the same time.
-Starting up the debugger this way will by default start Zope in
-single threaded mode.
-
-For most Zope developer's purposes, the debugger is needed to debug
-some sort of application level programming error.  A common scenario
-is when developing a new product for Zope.  Products extend Zope's
-functionality but they also present the same kind of debugging
-problems that are commonly found in any programming environment.  It
-is useful to have an existing debugging infrastructure to help you
-jump immediately to your new object and debug it and play with it
-directly in pdb.  The Zope debugger lets you do this.
-
-In reality, the "Zope" part of the Zope debugger is actually just a
-handy way to start up Zope with some pre-configured break points and
-to tell the Python debugger where in Zope you want to start
-debugging.
-
-Simulating HTTP Requests
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Now for an example. Remember, for this example to work, you *must*
-shut down Zope.  Go to your Zope's 'lib/python' directory and fire up
-Python and import 'Zope' and 'ZPublisher'::
-
-  $ cd lib/python
-  $ python
-  Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32
-  Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
-  >>> import Zope, ZPublisher
-  >>>
-
-Here you have run the Python interpreter (which is where using the
-debugger takes place) and imported two modules, 'Zope' and
-'ZPublisher'.  If Python complains about an 'ImportError' and not
-being able to find either module, then you are probably in the wrong
-directory, or you have not compiled Zope properly.  If you get this
-message::
-
-  ZODB.POSException.StorageSystemError: Could not lock the database
-  file.  There must be another process that has opened the file.
-
-This tells you that Zope is currently running.  Shutdown Zope and try
-again.
-
-The 'Zope' module is the main Zope application module.  When you
-import 'Zope' it sets up Zope.  'ZPublisher' is the Zope ORB.  See
-Chapter 2 for more information about 'ZPublisher'.
-
-You can use the 'ZPublisher.Zope' function to simulate an HTTP
-request.  Pass the function a URL relative the your root Zope object.
-Here is an example of how to simulate an HTTP request from the
-debugger::
-
-  >>> ZPublisher.Zope('')
-  Status: 200 OK
-  X-Powered-By: Zope (www.zope.org), Python (www.python.org)
-  Content-Length: 1238
-  Content-Type: text/html
-
-  <HTML><HEAD><TITLE>Zope</TITLE>
-
-    ... blah blah...
-
-  </BODY></HTML>
-  >>> 
-
-If you look closely, you will see that the content returned is
-*exactly* what is returned when you call your root level object
-through HTTP, including all the HTTP headers.
-
-Keep in mind that calling Zope this way does NOT involve a web
-server.  No ports are opened, the 'ZServer' code is not even
-imported.  In fact, this is just an interpreter front end to the same
-application code the ZServer *does* call.
-
-Interactive Debugging
-~~~~~~~~~~~~~~~~~~~~~
-
-Debugging involves publishing a request up to a point where you think
-it's failing, and then inspecting the state of your variables and
-objects.  The easy part is the actual inspection, the hard part is
-getting your program to stop at the right point.
-
-So, for the sake our example, let's say that you have a 'News' object
-which is defined in a Zope Product called 'ZopeNews', and is located
-in the 'lib/python/Products/ZopeNews' directory.  The class that
-defines the 'News' instance is also called 'News', and is defined in
-the 'News.py' module in your product.
-
-Therefore, from Zope's perspective the fully qualified name of your
-class is 'Products.ZopeNews.News.News'.  All Zope objects have this
-kind of fully qualified name.  For example, the 'ZCatalog' class can
-be found in 'Products.ZCatalog.ZCatalog.ZCatalog' (The redundancy is
-because the product, module, and class are all named 'ZCatalog').
-
-Now let's create an example method to debug.  You want your news
-object to have a 'postnews' method, that posts news::
-
-  class News(...):
-
-      ...
-
-      def postnews(self, news, author="Anonymous"):
-          self.news = news
-
-      def quote(self):
-          return '%s said, "%s"' % (self.author, self.news)
-
-You may notice that there's something wrong with the 'postnews'
-method.  The method assigns 'news' to an instance variable, but it
-does nothing with 'author'.  If the 'quote' method is called, it will
-raise an 'AttributeError' when it tries to look up the name
-'self.author'.  Although this is a pretty obvious goof, we'll use it
-to illustrate using the debugger to fix it.
-
-Running the debugger is done in a very similar way to how you called
-Zope through the python interpreter before, except that you introduce
-one new argument to the call to 'Zope'::
-
-  >>> ZPublisher.Zope('/News/postnews?new=blah', d=1)
-  * Type "s<cr>c<cr>" to jump to beginning of real publishing process.
-  * Then type c<cr> to jump to the beginning of the URL traversal
-    algorithm.
-  * Then type c<cr> to jump to published object call.
-  > <string>(0)?()
-  pdb> 
-
-Here, you call Zope from the interpreter, just like before, but there
-are two differences.  First, you call the 'postnews' method with an
-argument using the URL, '/News/postnews?new=blah'.  Second, you
-provided a new argument to the Zope call, 'd=1'.  The 'd' argument,
-when true, causes Zope to fire up in the Python debugger, pdb.
-Notice how the Python prompt changed from '>>>' to 'pdb>'.  This
-indicates that you are in the debugger.
-
-When you first fire up the debugger, Zope gives you a helpful message
-that tells you how to get to your object.  To understand this
-message, it's useful to know how you have set Zope up to be debugged.
-When Zope fires up in debugger mode, there are three breakpoints set
-for you automatically (if you don't know what a breakpoint is, you
-need to read the python `debugger documentation
-<http://www.python.org/doc/current/lib/module-pdb.html>`_).
-
-The first breakpoint stops the program at the point that ZPublisher
-(the Zope ORB) tries to publish the application module (in this case,
-the application module is 'Zope').  The second breakpoint stops the
-program right before ZPublisher tries to traverse down the provided
-URL path (in this case, '/News/postnews').  The third breakpoint will
-stop the program right before ZPublisher calls the object it finds
-that matches the URL path (in this case, the 'News' object).
-
-So, the little blurb that comes up and tells you some keys to press
-is telling you these things in a terse way.  Hitting 's' will *step*
-you into the debugger, and hitting 'c' will *continue* the execution
-of the program until it hits a breakpoint.
-
-Note however that none of these breakpoints will stop the program at
-'postnews'.  To stop the debugger right there, you need to tell the
-debugger to set a new breakpoint.  Why a new breakpoint?  Because
-Zope will stop you before it traverse your objects path, it will stop
-you before it calls the object, but if you want to stop it *exactly*
-at some point in your code, then you have to be explicit.  Sometimes
-the first three breakpoints are convienent, but often you need to set
-your own special break point to get you exactly where you want to go.
-
-Setting a breakpoint is easy (and see the next section for an even
-easier method).  For example::
-
-  pdb> import Products
-  pdb> b Products.ZopeNews.News.News.postnews
-  Breakpoint 5 at C:\Program Files\WebSite\lib\python\Products\ZopeNews\News.py:42
-  pdb> 
-
-First, you import 'Products'.  Since your module is a Zope product,
-it can be found in the 'Products' package.  Next, you set a new
-breakpoint with the *break* debugger command (pdb allows you to use
-single letter commands, but you could have also used the entire word
-'break').  The breakpoint you set is
-'Products.ZopeNews.News.News.postnews'.  After setting this
-breakpoint, the debugger will respond that it found the method in
-question in a certain file, on a certain line (in this case, the
-fictitious line 42) and return you to the debugger.
-
-Now, you want to get to your 'postnews' method so you can start
-debugging it.  But along the way, you must first *continue* through
-the various breakpoints that Zope has set for you.  Although this may
-seem like a bit of a burden, it's actually quite good to get a feel
-for how Zope works internally by getting down the rhythm that Zope
-uses to publish your object.  In these next examples, my comments
-will begin with '#".  Obviously, you won't see these comments when
-you are debugging.  So let's debug::
-
-  pdb> s
-  # 's'tep into the actual debugging
-
-  > <string>(1)?()
-  # this is pdb's response to being stepped into, ignore it
-
-  pdb> c
-  # now, let's 'c'ontinue onto the next breakpoint
-
-  > C:\Program Files\WebSite\lib\python\ZPublisher\Publish.py(112)publish()
-  -> def publish(request, module_name, after_list, debug=0,
-
-  # pdb has stopped at the first breakpoint, which is the point where
-  # ZPubisher tries to publish the application module.
-
-  pdb> c
-  # continuing onto the next breakpoint you get...
-
-  > C:\Program Files\WebSite\lib\python\ZPublisher\Publish.py(101)call_object()
-  -> def call_object(object, args, request):
-
-Here, 'ZPublisher' (which is now publishing the application) has
-found your object and is about to call it.  Calling your object
-consists of applying the arguments supplied by 'ZPublisher' to the
-object.  Here, you can see how 'ZPublisher' is passing three
-arguments into this process.  The first argument is 'object' and is
-the actual object you want to call.  This can be verified by
-*printing* the object::
-
-  pdb> p object
-  <News instance at 00AFE410>
-
-Now you can inspect your object (with the *print* command) and even
-play with it a bit.  The next argument is 'args'.  This is a tuple of
-arguments that 'ZPublisher' will apply to your object call.  The
-final argument is 'request'.  This is the request object and will
-eventually be transformed in to the DTML usable object 'REQUEST'. Now
-continue, your breakpoint is next::
-
-  pdb> c    
-  > C:\Program Files\WebSite\lib\python\Products\ZopeNews\News.py(42)postnews()
-  -> def postnews(self, N)
-
-Now you are here, at your method.  To be sure, tell the debugger to
-show you where you are in the code with the 'l' command.  Now you can
-examine variable and perform all the debugging tasks that the Python
-debugger provides.  From here, with a little knowledge of the Python
-debugger, you should be able to do any kind of debugging task that is
-needed.
-
-Interactive Debugging Triggered From the Web
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you are running in debug mode you can set break points in your
-code and then jump straight to the debugger when Zope comes across
-your break points.  Here's how to set a breakpoint::
-
-  import pdb;pdb.set_trace()
-
-Now start Zope in debug mode and point your web browser at a URL that
-causes Zope to execute the method that includes a breakpoint.  When
-this code is executed, the Python debugger will come up in the
-terminal where you started Zope.  Also note that from your web
-browser it looks like Zope is frozen.  Really it's just waiting for
-you do your debugging.
-
-From the terminal you are inside the debugger as it is executing your
-request.  Be aware that you are just debugging one thread in Zope,
-and other requests may be being served by other threads.  If you go
-to the *Debugging Info* screen while in the debugger, you can see
-your debugging request and how long it has been open.
-
-It is often more convenient to use this method to enter the debugger
-than it is to call 'ZPublisher.Zope' as detailed in the last section.
-
-Post-Mortem Debugging
-~~~~~~~~~~~~~~~~~~~~~
-
-Often, you need to use the debugger to chase down obscure problems in
-your code, but sometimes, the problem is obvious, because an
-exception gets raised.  For example, consider the following method on
-your 'News' class::
-
-  def quote(self):
-      return '%s said, "%s"' % (self.Author, self.news)
-
-Here, you can see that the method tries to substitute 'self.Author'
-in a string, but earlier we saw that this should really be
-'self.author'.  If you tried to run this method from the command
-line, an exception would be raised::
-
-  >>> ZPublisher.Zope('/News/quote')
-  Traceback (most recent call last):
-    File "<stdin>", line 1, in ?
-    File "./News.py", line 4, in test
-      test2()
-    File "./News.py", line 3, in test2
-      return '%s said, "%s"' % (self.Author, self.news)
-  NameError: Author
-  >>>
-
-Using Zope's normal debugging methods, you would typically need to
-start from the "beginning" and step your way down through the
-debugger to find this error (in this case, the error is pretty
-obvious, but more often than not errors can be pretty obscure!).
-
-Post-mortem debugging allows you to jump *directly* to the spot in
-your code that raised the exception, so you do not need to go through
-the possibly tedious task of stepping your way through a sea of
-Python code.  In the case of our example, you can just pass
-'ZPublisher.Zope' call a 'pm' argument that is set to 1::
-
-          >>> ZPublisher.Zope('/News/quote', pm=1)
-          Traceback (most recent call last):
-            File "<stdin>", line 1, in ?
-            File "./News.py", line 4, in test
-              test2()
-            File "./News.py", line 3, in test2
-              return '%s said, "%s"' % (self.Author, self.news)
-          NameError: Author
-          (pdb)
-
-Here, you can see that instead of taking you back to a python prompt,
-the post mortem debugging flag has caused you to go right into the
-debugging, *exactly* at the point in your code where the exception is
-raised.  This can be verified with the debugger's (l)ist
-command. Post mortem debugging offers you a handy way to jump right
-to the section of your code that is failing in some obvious way by
-raising an exception.
-
-Debugging With ZEO
-~~~~~~~~~~~~~~~~~~
-
-ZEO presents some interesting debugging abilities.  ZEO lets you
-debug one ZEO client when other clients continue to server requests
-for your site.  In the above examples, you have to shut down Zope to
-run in the debugger, but with ZEO, you can debug a production site
-while other clients continue to serve requests. Using ZEO is beyond
-the scope of this chapter. However, once you have ZEO running, you
-can debug a client process exactly as you debug a single-process
-Zope.
-
-
-Unit Testing
-============
-
-Unit testing allows you to automatically test your classes to make
-sure they are working correctly. By using unit tests you can make
-sure as you develop and change your classes that you are not breaking
-them. Zope comes with Pyunit. You can find out more information on
-Pyunit at `the Pyunit home page <http://pyunit.sourceforge.net/>`_
-. Pyunit is also part of the Python `standard library
-<http://www.python.org/doc/lib/module-unittest.html>`_ as of Python
-2.1.
-
-
-What Are Unit Tests
--------------------
-
-A "unit" may be defined as a piece of code with a single intended
-purpose.  A "unit test" is defined as a piece of code which exists
-to codify the intended behavior of a unit and to compare its
-intended behavior against its actual behavior.
-
-Unit tests are a way for developers and quality assurance engineers
-to quickly ascertain whether independent units of code are working as
-expected.  Unit tests are generally written at the same time as the
-code they are intended to test.  A unit testing framework allows a
-collection of unit tests to be run without human intervention,
-producing a minimum of output if all the tests in the collection are
-successful.
-
-It's a good idea to have a sense of the limits of unit testing.  From
-the `Extreme Programming Enthusiast website
-<http://c2.com/cgi/wiki?UnitTestsDefined>`_ here is a list of things
-that unit tests are *not*:
-
-- Manually operated.
-
-- Automated screen-driver tests that simulate user input (these are
-  "functional tests").
-
-- Interactive.  They run "no questions asked."
-
-- Coupled.  They run without dependencies except those native to the
-  thing being tested.
-
-- Complicated.  Unit test code is typically straightforward
-  procedural code that simulates an event.
-
-Writing Unit Tests
-------------------
-
-Here are the times when you should write unit tests:
-
-* When you write new code
-
-* When you change and enhance existing code
-
-* When you fix bugs
-
-It's much better to write tests when you're working on code than to
-wait until you're all done and then write tests.
-
-You should write tests that exercise discrete "units" of
-functionality.  In other words, write simple, specific tests that
-test one capability.  A good place to start is with interfaces and
-classes.  Classes and especially interfaces already define units of
-work which you may wish to test.
-
-Since you can't possibly write tests for every single capability and
-special case, you should focus on testing the riskiest parts of your
-code.  The riskiest parts are those that would be the most disastrous
-if they failed.  You may also want to test particularly tricky or
-frequently changed things.
-
-Here's an example test script that tests the 'News' class defined
-earlier in this chapter::
-
-  import unittest
-  import News
-
-  class NewsTest(unittest.TestCase):
-
-      def testPost(self):
-          n=News()
-          s='example news'
-          n.postnews(s)
-          assert n.news==s
-
-      def testQuote(self):
-          n=News()
-          s='example news'
-          n.postnews(s)
-          assert n.quote()=='Anonymous said: "%s"' % s
-          a='Author'
-          n.postnews(s, a)
-          assert n.quote()=='%s said: "%s"' % (a, s)
-
-  def test_suite():
-     return unittest.makeSuite(NewsTest, 'news test')
-
-  def main():
-     unittest.TextTestRunner().run(test_suite())
-
-  if __name__=="__main__":
-      main()
-
-You should save tests inside a 'tests' sub-directory in your
-product's directory. Test scripts file names should start with test,
-for example 'testNews.py'. You may accumulate many test scripts in
-your product's 'tests' directory.  You can run test your product by
-running the test scripts.
-
-We cannot cover all there is to say about unit testing here. Take a
-look at the Pyunit `documentation
-<http://pyunit.sourceforge.net/pyunit.html>`_ for more background on
-unit testing.
-
-Zope Test Fixtures
-------------------
-
-One issue that you'll run into when unit testing is that you may need
-to set up a Zope environment in order to test your products.  You can
-solve this problem in two ways.  First, you can structure your
-product so that much of it can be tested without Zope (as you did in
-the last section).  Second, you can create a test fixture that sets
-up a Zope environment for testing.
-
-To create a test fixture for Zope you'll need to:
-
-1. Add Zope's 'lib/python' directory to the Python path.
-
-2. Import 'Zope' and any other needed Zope modules and packages.
-
-3. Get a Zope application object.
-
-4. Do your test using the application object.
-
-5. Clean up the test by aborting or committing the transaction and
-   closing the Zope database connection.
-
-Here's an example Zope test fixture that demonstrates how to do each
-of these steps::
-
-  import os, os.path, sys, string
-  try:
-      import unittest
-  except ImportError:
-      fix_path()
-      import unittest
-
-  class MyTest(unittest.TestCase):
-
-      def setUp(self):
-          # Get the Zope application object and store it in an
-          # instance variable for use by test methods
-          import Zope
-          self.app=Zope.app()
-
-      def tearDown(self):
-          # Abort the transaction and shut down the Zope database
-          # connection.
-          get_transaction().abort()
-          self.app._p_jar.close()
-
-      # At this point your test methods can perform tests using
-      # self.app which refers to the Zope application object.
-
-      ...
-
-  def fix_path():
-      # Add Zope's lib/python directory to the Python path
-      file=os.path.join(os.getcwd(), sys.argv[0])
-      dir=os.path.join('lib', 'python')
-      i=string.find(file, dir)
-      sys.path.insert(0, file[:i+len(dir)])
-
-  def test_suite():
-     return unittest.makeSuite(MyTest, 'my test')
-
-  def main():
-     unittest.TextTestRunner().run(test_suite())
-
-  if __name__=="__main__":
-      fix_path()
-      main()
-
-This example shows a fairly complete Zope test fixture.  If your Zope
-tests only needs to import Zope modules and packages you can skip
-getting a Zope application object and closing the database
-transaction.
-
-Some times you may run into trouble if your test assuming that there
-is a current Zope request.  There are two ways to deal with this.
-One is to use the 'makerequest' utility module to create a fake
-request.  For example::
-
-  class MyTest(unittest.TestCase):
-      ...
-
-      def setup(self):
-          import Zope
-          from Testing import makerequest
-          self.app=makerequest.makerequest(Zope.app())
-
-This will create a Zope application object that is wrapped in a
-request.  This will enable code that expects to acquire a 'REQUEST'
-attribute work correctly.
-
-Another solution to testing methods that expect a request is to use
-the 'ZPublisher.Zope' function described earlier.  Using this
-approach you can simulate HTTP requests in your unit tests.  For
-example::
-
-  import ZPublisher
-
-  class MyTest(unittest.TestCase):
-      ...
-
-      def testWebRequest(self):
-          ZPublisher.Zope('/a/url/representing/a/method?with=a&couple=arguments',
-                          u='username:password', 
-                          s=1, 
-                          e={'some':'environment', 'variable':'settings'})
-
-If the 's' argument is passed to 'ZPublisher.Zope' then no output
-will be sent to 'sys.stdout'.  If you want to capture the output of
-the publishing request and compare it to an expected value you'll
-need to do something like this::
-
-  f=StringIO()
-  temp=sys.stdout
-  sys.stdout=f
-  ZPublisher.Zope('/myobject/mymethod')
-  sys.stdout=temp
-  assert f.getvalue() == expected_output
-
-Here's a final note on unit testing with a Zope test fixture: you may
-find Zope helpful.  ZEO allows you to test an application while it
-continues to serve other users.  It also speeds Zope start up time
-which can be a big relief if you start and stop Zope frequently while
-testing.
-
-Despite all the attention we've paid to Zope testing fixtures, you
-should probably concentrate on unit tests that don't require a Zope
-test fixture.  If you can't test much without Zope there is a good
-chance that your product would benefit from some refactoring to make
-it simpler and less dependent on the Zope framework.
-
-Logging
-=======
-
-Zope provides a framework for logging information to Zope's
-application log.  You can configure Zope to write the application log
-to a file, syslog, or other back-end.
-
-The logging API defined in the 'zLOG' module.  This module provides
-the 'LOG' function which takes the following required arguments:
-
-- subsystem -- The subsystem generating the message (e.g. "ZODB")
-
-- severity -- The "severity" of the event.  This may be an integer or
-  a floating point number.  Logging back ends may consider the int()
-  of this value to be significant.  For example, a back-end may
-  consider any severity whose integer value is WARNING to be a
-  warning.
-
-- summary -- A short summary of the event
-
-These arguments to the 'LOG' function are optional:
-
-- detail -- A detailed description
-
-- error -- A three-element tuple consisting of an error type, value,
-  and traceback.  If provided, then a summary of the error is added
-  to the detail.
-
-- reraise -- If provided with a true value, then the error given by
-  error is reraised.
-
-You can use the 'LOG' function to send warning and errors to the Zope
-application log.
-
-Here's an example of how to use the 'LOG' function to write debugging
-messages::
-
-  from zLOG import LOG, DEBUG
-  LOG('my app', DEBUG, 'a debugging message')
-
-You can use 'LOG' in much the same way as you would use print
-statements to log debugging information while Zope is running.  You
-should remember that Zope can be configured to ignore log messages
-below certain levels of severity.  If you are not seeing your logging
-messages, make sure that Zope is configured to write them to the
-application log.
-
-In general the debugger is a much more powerful way to locate
-problems than using the logger.  However, for simple debugging tasks
-and for issuing warnings the logger works just fine.
-
-Other Testing and Debugging Facilities
-======================================
-
-There is a few other testing and debugging techniques and tools not
-commonly used to test Zope.  In this section we'll mention several of
-them.
-
-Debug Logging
--------------
-
-Zope provides an analysis tool for debugging log output.  This output
-allows may give you hints as to where your application may be
-performing poorly, or not responding at all.  For example, since
-writing Zope products lets your write unrestricted Python code, it's
-very possibly to get yourself in a situation where you "hang" a Zope
-request, possibly by getting into a infinite loop.
-
-To try and detect at which point your application hangs, use the
-*requestprofiler.py* script in the *utilities* directory of your Zope
-installation.  To use this script, you must run Zope with the '-M'
-command line option.  This will turn on "detailed debug logging" that
-is necessary for the *requestprofiler.py* script to run.  The
-*requestprofiler.py* script has quite a few options which you can
-learn about with the '--help' switch.
-
-In general debug log analysis should be a last resort.  Use it when
-Zope is hanging and normal debugging and profiling is not helping you
-solve your problem.
-
-HTTP Benchmarking
------------------
-
-HTTP load testing is notoriously inaccurate.  However, it is useful
-to have a sense of how many requests your server can support.  Zope
-does not come with any HTTP load testing tools, but there are many
-available.  Apache's 'ab' program is a widely used free tool that can
-load your server with HTTP requests.
-
-Summary
-=======
-
-Zope provides a number of different debugging and testing facilities.
-The debugger allows you to interactively test your applications.
-Unit tests allow help you make sure that your application is develops
-correctly.  The logger allows you to do simple debugging and issue
-warnings.

Deleted: zope2docs/trunk/zdgbook/source/ZODBPersistentComponents.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/ZODBPersistentComponents.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/ZODBPersistentComponents.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,596 +0,0 @@
-##########################
-ZODB Persistent Components
-##########################
-
-Most Zope components live in the Zope Object DataBase (ZODB).
-Components that are stored in ZODB are said to be *persistent*.
-Creating persistent components is, for the most part, a trivial
-exercise, but ZODB does impose a few rules that persistent components
-must obey in order to work properly.  This chapter describes the
-persistence model and the interfaces that persistent objects can use
-to live inside the ZODB.
-
-Persistent Objects
-==================
-
-Persistent objects are Python objects that live for a long time. Most
-objects are created when a program is run and die when the program
-finishes. Persistent objects are not destroyed when the program ends,
-they are saved in a database.
-
-A great benefit of persistent objects is their transparency.  As a
-developer, you do not need to think about loading and unloading the
-state of the object from memory.  Zope's persistent machinery handles
-all of that for you.
-
-This is also a great benefit for application designers; you do not
-need to create your own kind of "data format" that gets saved to a
-file and reloaded again when your program stops and starts.  Zope's
-persistence machinery works with *any* kind of Python objects (within
-the bounds of a few simple rules) and as your types of objects grow,
-your database simply grows transparently with it.
-
-Persistence Example
--------------------
-
-Here is a simple example of using ZODB outside of Zope.  If all you
-plan on doing is using persistent objects with Zope, you can skip
-this section if you wish.
-
-The first thing you need to do to start working with ZODB is to
-create a "root object".  This process involves first opening a
-"storage" , which is the actual backend storage location for your
-data.
-
-ZODB supports many pluggable storage back-ends, but for the purposes
-of this article we're going to show you how to use the 'FileStorage'
-back-end storage, which stores your object data in a file.  Other
-storages include storing objects in relational databases, Berkeley
-databases, and a client to server storage that stores objects on a
-remote storage server.
-
-
-To set up a ZODB, you must first install it.  ZODB comes with Zope,
-so the easiest way to install ZODB is to install Zope and use the
-ZODB that comes with your Zope installation.  For those of you who
-don't want all of Zope, but just ZODB, see the instructions for
-downloading ZODB from the `ZODB web page
-<http://wiki.zope.org/ZODB>`_.
-
-After installing ZODB, you can start to experiment with it right from
-the Python command line interpreter.  If you've installed Zope,
-before running this set of commands, shut down your Zope server, and
-"cd" to the "lib/python" directory of your Zope instance.  If you're
-using a "standalone" version of ZODB, you likely don't need to do
-this, and you'll be able to use ZODB by importing it from a standard
-Python package directory.  In either case, try the following set of
-commands::
-
-  chrism at saints:/opt/zope/lib/python$ python
-  Python 2.1.1 (#1, Aug  8 2001, 21:17:50) 
-  [GCC 2.95.2 20000220 (Debian GNU/Linux)] on linux2
-  Type "copyright", "credits" or "license" for more information. 
-  >>> from ZODB import FileStorage, DB
-  >>> storage = FileStorage.FileStorage('mydatabase.fs')
-  >>> db = DB( storage )
-  >>> connection = db.open()
-  >>> root = connection.root()
-
-Here, you create storage and use the 'mydatabse.fs' file to store the
-object information.  Then, you create a database that uses that
-storage.
-
-
-Next, the database needs to be "opened" by calling the 'open()'
-method.  This will return a connection object to the database.  The
-connection object then gives you access to the 'root' of the database
-with the 'root()' method.
-
-The 'root' object is the dictionary that holds all of your persistent
-objects.  For example, you can store a simple list of strings in the
-root object::
-
-      root['employees'] = ['Bob', 'Mary', 'Jo']
-
-Now, you have changed the persistent database by adding a new object,
-but this change is so far only temporary.  In order to make the
-change permanent, you must commit the current transaction::
-
-      get_transaction().commit()
-
-Transactions are ways to make a lot of changes in one atomic
-operation.  In a later article, we'll show you how this is a very
-powerful feature.  For now, you can think of committing transactions
-as "checkpoints" where you save the changes you've made to your
-objects so far.  Later on, we'll show you how to abort those changes,
-and how to undo them after they are committed.
-
-If you had used a relational database, you would have had to issue a
-SQL query to save even a simple python list like the above example.
-You would have also needed some code to convert a SQL query back into
-the list when you wanted to use it again.  You don't have to do any
-of this work when using ZODB.  Using ZODB is almost completely
-transparent, in fact, ZODB based programs often look suspiciously
-simple!
-
-Working with simple python types is useful, but the real power of
-ZODB comes out when you store your own kinds of objects in the
-database.  For example, consider a class that represents a employee::
-
-  from Persistence import Persistent
-
-  class Employee(Persistent):
-
-      def setName(self, name):
-          self.name = name
-
-
-Calling 'setName' will set a name for the employee.  Now, you can put
-Employee objects in your database::
-
-  for name in ['Bob', 'Mary', 'Joe']:
-      employee = Employee()
-      employee.setName(name)
-      root['employees'].append(employee)
-
-  get_transaction().commit()
-
-Don't forget to call 'commit()', so that the changes you have made so
-far are committed to the database, and a new transaction is begun.
-
-Persistent Rules
-================
-
-There are a few rules that must be followed when your objects are
-persistent.
-
-- Your objects, and their attributes, must be "pickleable".
-
-- Your object cannot have any attributes that begin with '_p_'.
-
-- Attributes of your object that begin with '_v_' are "volatile" and
-  are not saved to the database (see next section).
-
-- You must explicitly signal any changes made to mutable attributes
-  (such as instances, lists, and dictionaries) or use persistent
-  versions of mutable objects, like 'ZODB.PersistentMapping' (see
-  below for more information on 'PersistentMapping'.)
-
-In this section, we'll look at each of these special rules one by
-one.
-
-The first rules says that your objects must be pickleable.  This
-means that they can be serialized into a data format with the
-"pickle" module.  Most python data types (numbers, lists,
-dictionaries) can be pickled.  Code objects (method, functions,
-classes) and file objects (files, sockets) *cannot* be pickled.
-Instances can be persistent objects if:
-
-- They subclass 'Persistence.Persistent'
-
-- All of their attributes are pickleable
-
-The second rule is that none of your objects attributes can begin
-with '_p_'.  For example, '_p_b_and_j' would be an illegal object
-attribute.  This is because the persistence machinery reserves all of
-these names for its own purposes.
-
-The third rule is that all object attributes that begin with '_v_'
-are "volatile" and are not saved to the database.  This means that as
-long as the persistent object is in Zope memory cache, volatile
-attributes can be used.  When the object is deactivated (removed from
-memory) volatile attributes are thrown away.
-
-Volatile attributes are useful for data that is good to cache for a
-while but can often be thrown away and easily recreated.  File
-connections, cached calculations, rendered templates, all of these
-kinds of things are useful applications of volatile attributes. You
-must exercise care when using volatile attributes.  Since you have
-little control over when your objects are moved in and out of memory,
-you never know when your volatile attributes may disappear.
-
-The fourth rule is that you must signal changes to mutable types.
-This is because persistent objects can't detect when mutable types
-change, and therefore, doesn't know whether or not to save the
-persistent object or not.
-
-For example, say you had a list of names as an attribute of your
-object called 'departments' that you changed in a method called
-'addDepartment'::
-
-  class DepartmentManager(Persistent):
-
-      def __init__(self):
-          self.departments = []
-
-      def addDepartment(self, department):
-          self.departments.append(department)
-
-When you call the 'addDepartment' method you change a mutable type,
-'departments' but your persistent object will not save that change.
-
-There are two solutions to this problem.  First, you can assign a
-special flag, '_p_changed'::
-
-  def addDepartment(self, department):
-      self.department.append(department)
-      self._p_changed = 1
-
-Remember, '_p_' attributes do something special to the persistence
-machinery and are reserved names. Assigning 1 to '_p_changed' tells
-the persistence machinery that you changed the object, and that it
-should be saved.
-
-Another technique is to use the mutable attribute as though it were
-immutable. In other words, after you make changes to a mutable
-object, reassign it::
-
-  def addDepartment(self, department):
-      departments = self.departments
-      departments.append(department)
-      self.department = departments
-
-Here, the 'self.departments' attribute was re-assigned at the end of
-the function to the "working copy" object 'departments'.  This
-technique is cleaner because it doesn't have any explicit
-'_p_changed' settings in it, but this implicit triggering of the
-persistence machinery should always be understood, otherwise use the
-explicit syntax.
-
-A final option is to use persistence-aware mutable attributes such as
-'PersistentMapping', and 'IOBTree'. 'PersistentMapping' is a mapping
-class that notifies ZODB when you change the mapping. You can use
-instances of 'PersistentMapping' in place of standard Python
-dictionaries and not worry about signaling change by reassigning the
-attribute or using '_p_changed'. Zope's Btree classes are also
-persistent-aware mutable containers. This solution can be cleaner
-than using mutable objects immutably, or signaling change manually
-assuming that there is a persistence-aware class available that meets
-your needs.
-
-Transactions and Persistent Objects
-===================================
-
-When changes are saved to ZODB, they are saved in a *transaction*.
-This means that either all changes are saved, or none are saved.  The
-reason for this is data consistency.  Imagine the following scenario:
-
-1. A user makes a credit card purchase at the sandwich.com website.
-
-2. The bank debits their account.
-
-3. An electronic payment is made to sandwich.com.
-
-Now imagine that an error happens during the last step of this
-process, sending the payment to sandwich.com.  Without transactions,
-this means that the account was debited, but the payment never went
-to sandwich.com!  Obviously this is a bad situation.  A better
-solution is to make all changes in a transaction:
-
-1. A user makes a credit card purchase at the sandwich.com website.
-
-2. The transaction begins
-
-3. The bank debits their account.
-
-4. An electronic payment is made to sandwich.com.
-
-5. The transaction commits
-
-Now, if an error is raised anywhere between steps 2 and 5, *all*
-changes made are thrown away, so if the payment fails to go to
-sandwich.com, the account won't be debited, and if debiting the
-account raises an error, the payment won't be made to sandwich.com,
-so your data is always consistent.
-
-When using your persistent objects with Zope, Zope will automatically
-*begin* a transaction when a web request is made, and *commit* the
-transaction when the request is finished.  If an error occurs at any
-time during that request, then the transaction is *aborted*, meaning
-all the changes made are thrown away.
-
-If you want to *intentionally* abort a transaction in the middle of a
-request, then just raise an error at any time.  For example, this
-snippet of Python will raise an error and cause the transaction to
-abort::
-
-  raise SandwichError('Not enough peanut butter.')
-
-A more likely scenario is that your code will raise an exception when
-a problem arises. The great thing about transactions is that you
-don't have to include cleanup code to catch exceptions and undo
-everything you've done up to that point. Since the transaction is
-aborted the changes made in the transaction will not be saved.
-
-Because Zope does transaction management for you, most of the time
-you do not need to explicitly begin, commit or abort your own
-transactions.  For more information on doing transaction management
-manually, see the links at the end of this chapter that lead to more
-detailed tutorials of doing your own ZODB programming.
-
-
-Subtransactions
----------------
-
-Zope waits until the transaction is committed to save all the changes
-to your objects.  This means that the changes are saved in memory.
-If you try to change more objects than you have memory in your
-computer, your computer will begin to swap and thrash, and maybe even
-run you out of memory completely.  This is bad. The easiest solution
-to this problem is to not change huge quantities of data in one
-transaction.
-
-If you need to spread a transaction out of lots of data, however, you
-can use subtransactions.  Subtransactions allow you to manage Zope's
-memory usage yourself, so as to avoid swapping during large
-transactions.
-
-Subtransactions allow you to make huge transactions. Rather than
-being limited by available memory, you are limited by available disk
-space.  Each subtransaction commit writes the current changes out to
-disk and frees memory to make room for more changes.
-
-To commit a subtransaction, you first need to get a hold of a
-transaction object.  Zope adds a function to get the transaction
-objects in your global namespace, 'get_transaction', and then call
-'commit(1)' on the transaction::
-
-  get_transaction().commit(1)
-
-You must balance speed, memory, and temporary storage concerns when
-deciding how frequently to commit subtransactions. The more
-subtransactions, the less memory used, the slower the operation, and
-the more temporary space used. Here's and example of how you might
-use subtransactions in your Zope code::
-
-  tasks_per_subtransaction = 10
-  i = 0
-  for task in tasks:
-      process(task)
-      i = i + 1
-      if i % tasks_per_subtransaction == 0:
-          get_transaction().commit(1)
-
-This example shows how to commit a subtransaction at regular
-intervals while processing a number of tasks.
-
-Threads and Conflict Errors
----------------------------
-
-Zope is a multi-threaded server.  This means that many different
-clients may be executing your Python code in different threads.  For
-most cases, this is not an issue and you don't need to worry about
-it, but there are a few cases you should look out for.
-
-The first case involves threads making lots of changes to objects and
-writing to the database.  The way ZODB and threading works is that
-each thread that uses the database gets its own *connection* to the
-database.  Each connection gets its own *copy* of your object.  All
-of the threads can read and change any of the objects.  ZODB keeps
-all of these objects synchronized between the threads. The upshot is
-that you don't have to do any locking or thread synchronization
-yourself. Your code can act as though it is single threaded.
-
-However, synchronization problems can occur when objects are changed
-by two different threads at the same time.
-
-Imagine that thread 1 gets its own copy of object A, as does thread
-2.  If thread 1 changes its copy of A, then thread 2 will not see
-those changes until thread 1 commits them.  In cases where lots of
-objects are changing, this can cause thread 1 and 2 to try and commit
-changes to object 1 at the same time.
-
-When this happens, ZODB lets one transaction do the commit (it
-"wins") and raises a 'ConflictError' in the other thread (which
-"looses"). The looser can elect to try again, but this may raise yet
-another 'ConflictError' if many threads are trying to change object
-A. Zope does all of its own transaction management and will retry a
-losing transaction three times before giving up and raising the
-'ConflictError' all the way up to the user.
-
-
-Resolving Conflicts
--------------------
-
-If a conflict happens, you have two choices. The first choice is that
-you live with the error and you try again. Statistically, conflicts
-are going to happen, but only in situations where objects are
-"hot-spots".  Most problems like this can be "designed away"; if you
-can redesign your application so that the changes get spread around
-to many different objects then you can usually get rid of the hot
-spot.
-
-
-Your second choice is to try and *resolve* the conflict. In many
-situations, this can be done. For example, consider the following
-persistent object::
-
-  class Counter(Persistent):
-
-      self.count = 0
-
-      def hit(self):
-          self.count = self.count + 1
-
-This is a simple counter.  If you hit this counter with a lot of
-requests though, it will cause conflict errors as different threads
-try to change the count attribute simultaneously.
-
-But resolving the conflict between conflicting threads in this case
-is easy.  Both threads want to increment the self.count attribute by
-a value, so the resolution is to increment the attribute by the sum
-of the two values and make both commits happy; no 'ConflictError' is
-raised.
-
-
-To resolve a conflict, a class should define an '_p_resolveConflict'
-method. This method takes three arguments.
-
-'oldState' -- The state of the object that the changes made by the
-current transaction were based on. The method is permitted to modify
-this value.
-
-'savedState' -- The state of the object that is currently stored in
-the database. This state was written after 'oldState' and reflects
-changes made by a transaction that committed before the current
-transaction. The method is permitted to modify this value.
-
-'newState' -- The state after changes made by the current
-transaction.  The method is *not* permitted to modify this
-value. This method should compute a new state by merging changes
-reflected in 'savedState' and 'newState', relative to 'oldState'.
-
-The method should return the state of the object after resolving the
-differences.
-
-Here is an example of a '_p_resolveConflict' in the 'Counter' class::
-
-  class Counter(Persistent):
-
-      self.count = 0
-
-      def hit(self):
-          self.count = self.count + 1
-
-      def _p_resolveConflict(self, oldState, savedState, newState):
-
-          # Figure out how each state is different:
-          savedDiff= savedState['count'] - oldState['count']
-          newDiff= newState['count']- oldState['count']
-
-          # Apply both sets of changes to old state:
-          oldState['count'] = oldState['count'] + savedDiff + newDiff
-
-          return oldState
-
-In the above example, '_p_resolveConflict' resolves the difference
-between the two conflicting transactions.
-
-Threadsafety of Non-Persistent Objects
-======================================
-
-ZODB takes care of threadsafety for persistent objects. However, you
-must handle threadsafey yourself for non-persistent objects which are
-shared between threads.
-
-Mutable Default Arguments
--------------------------
-
-One tricky type of non-persistent, shared objects are mutable default
-arguments to functions, and methods.  Default arguments are useful
-because they are cached for speed, and do not need to be recreated
-every time the method is called.  But if these cached default
-arguments are mutable, one thread may change (mutate) the object when
-another thread is using it, and that can be bad.  So, code like::
-
-        def foo(bar=[]):
-            bar.append('something')
-
-
-Could get in trouble if two threads execute this code because lists
-are mutable.  There are two solutions to this problem:
-
-- Don't use mutable default arguments. (Good)
-
-- If you use them, you cannot change them.  If you want to change
-  them, you will need to implement your own locking. (Bad)
-
-We recommend the first solution because mutable default arguments are
-confusing, generally a bad idea in the first place.
-
-Shared Module Data
-------------------
-
-Objects stored in modules but not in the ZODB are not persistent and
-not-thread safe. In general it's not a good idea to store data (as
-opposed to functions, and class definitions) in modules when using
-ZODB.
-
-
-If you decide to use module data which can change you'll need to
-protect it with a lock to ensure that only one thread at a time can
-make changes.
-
-
-For example::
-
-  from threading import Lock
-  queue=[]
-  l=Lock()
-
-  def put(obj):
-      l.acquire()
-      try:
-          queue.append(obj)
-      finally:
-          l.release()
-
-  def get():
-      l.acquire()
-      try:
-          return queue.pop()
-      finally:
-          l.release()
-
-Note, in most cases where you are tempted to use shared module data,
-you can likely achieve the same result with a single persistent
-object. For example, the above queue could be replaced with a single
-instance of this class::
-
-  class Queue(Persistent):
-
-      def __init__(self):
-          self.list=[]
-
-      def put(self, obj):
-          self.list=self.list + [obj]
-
-      def get(self):
-          obj=self.list[-1]
-          self.list=self.list[0:-1]
-          return obj
-
-Notice how this class uses the mutable object 'self.list'
-immutably. If this class used 'self.list.pop' and 'self.list.append',
-then the persistence machinary would not notice that 'self.list' had
-changed.
-
-Shared External Resources
-=========================
-
-A final category of data for which you'll need to handle
-thread-safety is external resources such as files in the filesystem,
-and other processes. In practice, these concerns rarely come up.
-
-Other ZODB Resources
-====================
-
-This chapter has only covered the most important features of ZODB
-from a Zope developer's perspective. Check out some of these sources
-for more in depth information:
-
-- Andrew Kuchling's `ZODB pages <http://www.kuchling.com/zodb/>`_
-  include lots of information included a programmer's guide and links
-  to ZODB mailing lists.
-
-- `ZODB Wiki <http://wiki.zope.org/ZODB>`_ has information about
-  current ZODB projects.
-
-- `ZODB UML
-  Model <http://www.zope.org/Documentation/Developer/Models/ZODB>`_ has
-  the nitty gritty details on ZODB.
-
-- Paper `Introduction to the Zope Object Database
-  <http://www.python.org/workshops/2000-01/proceedings/papers/fulton/zodb3.html>`_
-  by Jim Fulton, presented at the 8th Python Conference.
-
-Summary
-=======
-
-The ZODB is a complex and powerful system. However using persistent
-objects is almost completely painless. Seldom do you need to concern
-yourself with thread safety, transactions, conflicts, memory
-management, and database replication. ZODB takes care of these things
-for you. By following a few simple rules you can create persistent
-objects that just work.
-

Deleted: zope2docs/trunk/zdgbook/source/conf.py
===================================================================
--- zope2docs/trunk/zdgbook/source/conf.py	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/conf.py	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,190 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Zope Developer's Guide documentation build configuration file, created by
-# sphinx-quickstart on Mon Feb 16 22:23:29 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"Zope Developer's Guide"
-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 = 'ZopeDevelopersGuidedoc'
-
-
-# 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', 'ZopeDevelopersGuide.tex', ur"Zope Developer's Guide",
-   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/trunk/zdgbook/source/index.rst
===================================================================
--- zope2docs/trunk/zdgbook/source/index.rst	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zdgbook/source/index.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -1,17 +0,0 @@
-Zope Developer's Guide
-======================
-
-.. toctree::
-   :numbered:
-   :maxdepth: 2
-
-   Introduction.rst
-   GettingStarted.rst
-   ComponentsAndInterfaces.rst
-   ObjectPublishing.rst
-   Products.rst
-   ZODBPersistentComponents.rst
-   Acquisition.rst
-   Security.rst
-   TestingAndDebugging.rst
-   AppendixA.rst

Copied: zope2docs/trunk/zope2book/Acquisition.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/Acquisition.rst)
===================================================================
--- zope2docs/trunk/zope2book/Acquisition.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/Acquisition.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/AdvDTML.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/AdvDTML.rst)
===================================================================
--- zope2docs/trunk/zope2book/AdvDTML.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/AdvDTML.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/AdvZPT.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/AdvZPT.rst)
===================================================================
--- zope2docs/trunk/zope2book/AdvZPT.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/AdvZPT.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/AppendixA.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/AppendixA.rst)
===================================================================
--- zope2docs/trunk/zope2book/AppendixA.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/AppendixA.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/AppendixB.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/AppendixB.rst)
===================================================================
--- zope2docs/trunk/zope2book/AppendixB.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/AppendixB.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/AppendixC.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/AppendixC.rst)
===================================================================
--- zope2docs/trunk/zope2book/AppendixC.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/AppendixC.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/AppendixD.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/AppendixD.rst)
===================================================================
--- zope2docs/trunk/zope2book/AppendixD.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/AppendixD.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/AppendixE.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/AppendixE.rst)
===================================================================
--- zope2docs/trunk/zope2book/AppendixE.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/AppendixE.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/BasicObject.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/BasicObject.rst)
===================================================================
--- zope2docs/trunk/zope2book/BasicObject.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/BasicObject.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/BasicScripting.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/BasicScripting.rst)
===================================================================
--- zope2docs/trunk/zope2book/BasicScripting.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/BasicScripting.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/Contributions.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/Contributions.rst)
===================================================================
--- zope2docs/trunk/zope2book/Contributions.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/Contributions.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/DTML.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/DTML.rst)
===================================================================
--- zope2docs/trunk/zope2book/DTML.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/DTML.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/ExternalTools.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/ExternalTools.rst)
===================================================================
--- zope2docs/trunk/zope2book/ExternalTools.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/ExternalTools.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/InstallingZope.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/InstallingZope.rst)
===================================================================
--- zope2docs/trunk/zope2book/InstallingZope.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/InstallingZope.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/IntroducingZope.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/IntroducingZope.rst)
===================================================================
--- zope2docs/trunk/zope2book/IntroducingZope.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/IntroducingZope.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/MaintainingZope.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/MaintainingZope.rst)
===================================================================
--- zope2docs/trunk/zope2book/MaintainingZope.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/MaintainingZope.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/Makefile
===================================================================
--- zope2docs/trunk/zope2book/Makefile	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zope2book/Makefile	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/ObjectOrientation.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/ObjectOrientation.rst)
===================================================================
--- zope2docs/trunk/zope2book/ObjectOrientation.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/ObjectOrientation.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/Preface.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/Preface.rst)
===================================================================
--- zope2docs/trunk/zope2book/Preface.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/Preface.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/RelationalDatabases.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/RelationalDatabases.rst)
===================================================================
--- zope2docs/trunk/zope2book/RelationalDatabases.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/RelationalDatabases.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/ScriptingZope.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/ScriptingZope.rst)
===================================================================
--- zope2docs/trunk/zope2book/ScriptingZope.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/ScriptingZope.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/SearchingZCatalog.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/SearchingZCatalog.rst)
===================================================================
--- zope2docs/trunk/zope2book/SearchingZCatalog.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/SearchingZCatalog.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/Security.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/Security.rst)
===================================================================
--- zope2docs/trunk/zope2book/Security.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/Security.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/Sessions.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/Sessions.rst)
===================================================================
--- zope2docs/trunk/zope2book/Sessions.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/Sessions.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/SimpleExamples.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/SimpleExamples.rst)
===================================================================
--- zope2docs/trunk/zope2book/SimpleExamples.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/SimpleExamples.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/UsingZope.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/UsingZope.rst)
===================================================================
--- zope2docs/trunk/zope2book/UsingZope.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/UsingZope.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/VirtualHosting.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/VirtualHosting.rst)
===================================================================
--- zope2docs/trunk/zope2book/VirtualHosting.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/VirtualHosting.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/ZEO.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/ZEO.rst)
===================================================================
--- zope2docs/trunk/zope2book/ZEO.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/ZEO.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/ZPT.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/ZPT.rst)
===================================================================
--- zope2docs/trunk/zope2book/ZPT.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/ZPT.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/ZopeArchitecture.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/ZopeArchitecture.rst)
===================================================================
--- zope2docs/trunk/zope2book/ZopeArchitecture.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/ZopeArchitecture.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/ZopeServices.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/ZopeServices.rst)
===================================================================
--- zope2docs/trunk/zope2book/ZopeServices.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/ZopeServices.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/bootstrap.py
===================================================================
--- zope2docs/trunk/zope2book/bootstrap.py	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zope2book/bootstrap.py	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/buildout.cfg
===================================================================
--- zope2docs/trunk/zope2book/buildout.cfg	2009-10-10 06:13:52 UTC (rev 104987)
+++ zope2docs/trunk/zope2book/buildout.cfg	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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/trunk/zope2book/index.rst (from rev 104987, zope2docs/branches/baijum-reorganize/zope2book/index.rst)
===================================================================
--- zope2docs/trunk/zope2book/index.rst	                        (rev 0)
+++ zope2docs/trunk/zope2book/index.rst	2009-10-10 06:20:10 UTC (rev 104988)
@@ -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
+



More information about the checkins mailing list