diff --git a/reporter/README.txt b/reporter/README.txt
new file mode 100644
index 0000000..6dac6cb
--- /dev/null
+++ b/reporter/README.txt
@@ -0,0 +1,37 @@
+Quickstart Instructions
+=======================
+
+ ($Id$)
+
+ >>> from zope.app import zapi
+ >>> from zope.app.testing import ztapi
+ >>> from zope.interface import directlyProvides
+
+A Basic API for Reports and Listings
+====================================
+
+ >>> from cybertools.reporter.data import DataSource
+ >>> from cybertools.reporter.interfaces import IResultSet
+
+Let's start with the Person class from the example package - we will
+then provide a listing of persons...
+
+ >>> from cybertools.reporter.example.contact import Person, Contacts
+ >>> from cybertools.reporter.example.interfaces import IContactsDataSource
+
+ >>> import time
+ >>> format = '%Y-%m-%d'
+ >>> pdata = ((u'John', u'Smith', '1956-08-01'),
+ ... (u'David', u'Waters', '1972-12-24'),
+ ... (u'Carla', u'Myers', '1981-10-11'))
+ >>> persons = DataSource([Person(f, s, time.strptime(b, format))
+ ... for f, s, b in pdata])
+ >>> directlyProvides(persons, IContactsDataSource)
+
+ >>> ztapi.provideAdapter(IContactsDataSource, IResultSet, Contacts)
+ >>> rset = IResultSet(persons)
+
+For the browser presentation we can also use a browser view providing
+the result set with extended attributes:
+
+ >>> #rsView = zapi.getMultiAdapter((context, TestRequest()), IBrowserView)
diff --git a/reporter/__init__.py b/reporter/__init__.py
new file mode 100644
index 0000000..4bc90fb
--- /dev/null
+++ b/reporter/__init__.py
@@ -0,0 +1,4 @@
+"""
+$Id$
+"""
+
diff --git a/reporter/browser/__init__.py b/reporter/browser/__init__.py
new file mode 100644
index 0000000..4bc90fb
--- /dev/null
+++ b/reporter/browser/__init__.py
@@ -0,0 +1,4 @@
+"""
+$Id$
+"""
+
diff --git a/reporter/configure.zcml b/reporter/configure.zcml
new file mode 100644
index 0000000..db5642b
--- /dev/null
+++ b/reporter/configure.zcml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/reporter/cybertools.reporter-configure.zcml b/reporter/cybertools.reporter-configure.zcml
new file mode 100644
index 0000000..568a018
--- /dev/null
+++ b/reporter/cybertools.reporter-configure.zcml
@@ -0,0 +1 @@
+
diff --git a/reporter/data.py b/reporter/data.py
new file mode 100644
index 0000000..8add6d5
--- /dev/null
+++ b/reporter/data.py
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+"""
+Basic data / data source implementations.
+
+$Id$
+"""
+
+from zope.interface import implements
+from cybertools.reporter.interfaces import IDataSource
+
+
+class DataSource(object):
+
+ implements(IDataSource)
+
+ def __init__(self, iterable):
+ self.data = iterable
+
+ def __iter__(self):
+ return iter(self.data)
diff --git a/reporter/example/__init__.py b/reporter/example/__init__.py
new file mode 100644
index 0000000..4bc90fb
--- /dev/null
+++ b/reporter/example/__init__.py
@@ -0,0 +1,4 @@
+"""
+$Id$
+"""
+
diff --git a/reporter/example/contact.py b/reporter/example/contact.py
new file mode 100644
index 0000000..f535c75
--- /dev/null
+++ b/reporter/example/contact.py
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+"""
+A set of simple application classes for contact management to be used
+as an example for the cybertools.reporter package.
+
+$Id$
+"""
+
+from zope.component import adapts
+from zope.interface import implements
+from cybertools.reporter.interfaces import IResultSet
+from cybertools.reporter.example.interfaces import IContactsDataSource
+
+
+class Person(object):
+
+ def __init__(self, firstName, lastName, birthDate):
+ self.firstName = firstName
+ self.lastName = lastName
+ self.birthDate = birthDate
+
+
+class Contacts(object):
+
+ implements(IResultSet)
+ adapts(IContactsDataSource)
+
+ def __init__(self, context):
+ self.context = context
+
+
\ No newline at end of file
diff --git a/reporter/example/interfaces.py b/reporter/example/interfaces.py
new file mode 100644
index 0000000..8439afb
--- /dev/null
+++ b/reporter/example/interfaces.py
@@ -0,0 +1,31 @@
+#
+# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+"""
+Interfaces for a simple contact management framework to be used
+as an example for the cybertools.reporter package.
+
+$Id$
+"""
+
+from zope.interface import Interface
+
+class IContactsDataSource(Interface):
+ """ A data source marker interface for contacts.
+ """
+
diff --git a/reporter/interfaces.py b/reporter/interfaces.py
new file mode 100644
index 0000000..a16bd20
--- /dev/null
+++ b/reporter/interfaces.py
@@ -0,0 +1,86 @@
+#
+# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+"""
+interface definitions for the reporter package.
+
+$Id$
+"""
+
+import zope
+from zope.interface import Interface, Attribute
+
+
+# result set
+
+class IResultSet(Interface):
+ """A sequence of rows provided by a data source, report or
+ similar object, together with a schema that describes the columns
+ (fields, cells).
+ """
+
+ schema = zope.schema.Iterable(title=u'Schema',
+ description=u'Collection of field specifications based '
+ 'on the interfaces defined by zope.schema.')
+ rows = zope.schema.Iterable(title=u'Rows',
+ description=u'Sequence of row objects')
+
+
+class IRow(Interface):
+ """ A sequence of cells containing the real data objects.
+ """
+
+ cells = zope.schema.Dict(zope.schema.ASCIILine(),
+ title=u'Cells',
+ description=u'Mapping of data elements addressed by a name '
+ 'that is the key to the mapping.')
+
+ resultSet = Attribute('The result set this row belongs to.')
+
+
+class ICell(Interface):
+ """ A single cell of a listing or table.
+ """
+
+ text = zope.schema.Text(title=u'Text',
+ description=u'Text to be displayed')
+ value = zope.schema.Object(Interface,
+ title=u'Value',
+ description=u'The real object, often identical to text.')
+ token = zope.schema.ASCIILine(title=u'Token',
+ description=u'May be used to identify a cell within'
+ 'the result set, e.g. in forms')
+
+ row = Attribute('The row this cell belongs to.')
+
+ def sortKey():
+ """ Returns a value (typically a string or a sequence) that will
+ be used for comparing cells in order to sort rows.
+ """
+
+
+# data source
+
+class IDataSource(Interface):
+ """ An iterable that may be used as a data source.
+ """
+
+ def __iter__():
+ """ Return an iterable that provides the data to be evaluated.
+ """
+
diff --git a/reporter/tests.py b/reporter/tests.py
new file mode 100755
index 0000000..77abd1f
--- /dev/null
+++ b/reporter/tests.py
@@ -0,0 +1,27 @@
+# $Id$
+
+import unittest
+from zope.testing.doctestunit import DocFileSuite
+from zope.app.testing import ztapi
+from zope.interface.verify import verifyClass
+from zope.interface import implements
+from zope.app import zapi
+
+from cybertools.reporter.interfaces import IResultSet, IRow, ICell
+
+
+class TestReporter(unittest.TestCase):
+ "Basic tests for the reporter package."
+
+ def testInterfaces(self):
+ pass
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(TestReporter),
+ DocFileSuite('README.txt'),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')