[Python-checkins] r52625 - in tracker/vendor/roundup/current: .cvsignore BUILD.txt CHANGES.txt COPYING.txt ChangeLog MANIFEST.in README.txt cgi-bin cgi-bin/roundup.cgi demo.py detectors detectors/creator_resolution.py detectors/emailauditor.py detectors/newissuecopy.py doc doc/.cvsignore doc/FAQ.txt doc/Makefile doc/ZPL.txt doc/admin_guide.txt doc/announcement.txt doc/customizing.txt doc/debugging.txt doc/default.css doc/design.txt doc/developers.txt doc/features.txt doc/glossary.txt doc/images doc/images/edit.png doc/images/hyperdb.png doc/images/logo-acl-medium.png doc/images/logo-codesourcery-medium.png doc/images/logo-software-carpentry-standard.png doc/images/roundup-1.png doc/images/roundup.png doc/implementation.txt doc/index.txt doc/installation.txt doc/mysql.txt doc/original_overview.html doc/overview.txt doc/postgresql.txt doc/roundup-admin.1 doc/roundup-demo.1 doc/roundup-favicon.ico doc/roundup-mailgw.1 doc/roundup-server.1 doc/roundup-server.ini.example doc/spec.html doc/tracker_templates.txt doc/upgrading.txt doc/user_guide.txt doc/whatsnew-0.7.txt doc/whatsnew-0.8.txt frontends frontends/README.txt frontends/ZRoundup frontends/ZRoundup/.cvsignore frontends/ZRoundup/ZRoundup.py frontends/ZRoundup/__init__.py frontends/ZRoundup/dtml frontends/ZRoundup/dtml/manage_addZRoundupForm.dtml frontends/ZRoundup/icons frontends/ZRoundup/icons/tick_symbol.gif frontends/ZRoundup/refresh.txt locale locale/.cvsignore locale/GNUmakefile locale/de.po locale/en.po locale/es_AR.po locale/fr.po locale/lt.po locale/roundup.pot locale/ru.po locale/zh_CN.po locale/zh_TW.po patches patches/20020205.alternate_auth roundup roundup/.cvsignore roundup/__init__.py roundup/admin.py roundup/backends roundup/backends/.cvsignore roundup/backends/__init__.py roundup/backends/back_anydbm.py roundup/backends/back_metakit.py roundup/backends/back_mysql.py roundup/backends/back_postgresql.py roundup/backends/back_sqlite.py roundup/backends/back_tsearch2.py roundup/backends/blobfiles.py roundup/backends/indexer_common.py roundup/backends/indexer_dbm.py roundup/backends/indexer_rdbms.py roundup/backends/indexer_xapian.py roundup/backends/locking.py roundup/backends/portalocker.py roundup/backends/rdbms_common.py roundup/backends/sessions_dbm.py roundup/backends/sessions_rdbms.py roundup/backends/tsearch2_setup.py roundup/cgi roundup/cgi/.cvsignore roundup/cgi/MultiMapping.py roundup/cgi/PageTemplates roundup/cgi/PageTemplates/.cvsignore roundup/cgi/PageTemplates/Expressions.py roundup/cgi/PageTemplates/GlobalTranslationService.py roundup/cgi/PageTemplates/MultiMapping.py roundup/cgi/PageTemplates/PageTemplate.py roundup/cgi/PageTemplates/PathIterator.py roundup/cgi/PageTemplates/PythonExpr.py roundup/cgi/PageTemplates/README.txt roundup/cgi/PageTemplates/TALES.py roundup/cgi/PageTemplates/__init__.py roundup/cgi/TAL roundup/cgi/TAL/.cvsignore roundup/cgi/TAL/DummyEngine.py roundup/cgi/TAL/HTMLParser.py roundup/cgi/TAL/HTMLTALParser.py roundup/cgi/TAL/README.txt roundup/cgi/TAL/TALDefs.py roundup/cgi/TAL/TALGenerator.py roundup/cgi/TAL/TALInterpreter.py roundup/cgi/TAL/TALParser.py roundup/cgi/TAL/TranslationContext.py roundup/cgi/TAL/XMLParser.py roundup/cgi/TAL/__init__.py roundup/cgi/TAL/markupbase.py roundup/cgi/TAL/talgettext.py roundup/cgi/TranslationService.py roundup/cgi/ZTUtils roundup/cgi/ZTUtils/.cvsignore roundup/cgi/ZTUtils/Batch.py roundup/cgi/ZTUtils/Iterator.py roundup/cgi/ZTUtils/__init__.py roundup/cgi/__init__.py roundup/cgi/accept_language.py roundup/cgi/actions.py roundup/cgi/apache.py roundup/cgi/cgitb.py roundup/cgi/client.py roundup/cgi/exceptions.py roundup/cgi/form_parser.py roundup/cgi/templating.py roundup/cgi/zLOG.py roundup/configuration.py roundup/date.py roundup/exceptions.py roundup/hyperdb.py roundup/i18n.py roundup/init.py roundup/install_util.py roundup/instance.py roundup/mailer.py roundup/mailgw.py roundup/msgfmt.py roundup/password.py roundup/rfc2822.py roundup/roundupdb.py roundup/scripts roundup/scripts/.cvsignore roundup/scripts/__init__.py roundup/scripts/roundup_admin.py roundup/scripts/roundup_demo.py roundup/scripts/roundup_gettext.py roundup/scripts/roundup_mailgw.py roundup/scripts/roundup_server.py roundup/security.py roundup/support.py roundup/token.py roundup/version_check.py run_tests.py scripts scripts/README.txt scripts/add-issue scripts/copy-user.py scripts/hyperdb_example.py scripts/imapServer.py scripts/import_sf.py scripts/roundup-reminder scripts/roundup.rc-debian scripts/schema_diagram.py scripts/server-ctl setup.py templates templates/classic templates/classic/.cvsignore templates/classic/TEMPLATE-INFO.txt templates/classic/detectors templates/classic/detectors/.cvsignore templates/classic/detectors/messagesummary.py templates/classic/detectors/nosyreaction.py templates/classic/detectors/statusauditor.py templates/classic/detectors/userauditor.py templates/classic/extensions templates/classic/extensions/README.txt templates/classic/html templates/classic/html/_generic.calendar.html templates/classic/html/_generic.collision.html templates/classic/html/_generic.help.html templates/classic/html/_generic.index.html templates/classic/html/_generic.item.html templates/classic/html/file.index.html templates/classic/html/file.item.html templates/classic/html/help_controls.js templates/classic/html/home.classlist.html templates/classic/html/home.html templates/classic/html/issue.index.html templates/classic/html/issue.item.html templates/classic/html/issue.search.html templates/classic/html/keyword.item.html templates/classic/html/msg.index.html templates/classic/html/msg.item.html templates/classic/html/page.html templates/classic/html/query.edit.html templates/classic/html/query.item.html templates/classic/html/style.css templates/classic/html/user.forgotten.html templates/classic/html/user.index.html templates/classic/html/user.item.html templates/classic/html/user.register.html templates/classic/html/user.rego_progress.html templates/classic/initial_data.py templates/classic/schema.py templates/minimal templates/minimal/.cvsignore templates/minimal/TEMPLATE-INFO.txt templates/minimal/detectors templates/minimal/detectors/.cvsignore templates/minimal/detectors/userauditor.py templates/minimal/extensions templates/minimal/extensions/README.txt templates/minimal/html templates/minimal/html/_generic.calendar.html templates/minimal/html/_generic.collision.html templates/minimal/html/_generic.help.html templates/minimal/html/_generic.index.html templates/minimal/html/_generic.item.html templates/minimal/html/help_controls.js templates/minimal/html/home.classlist.html templates/minimal/html/home.html templates/minimal/html/page.html templates/minimal/html/style.css templates/minimal/html/user.index.html templates/minimal/html/user.item.html templates/minimal/html/user.register.html templates/minimal/html/user.rego_progress.html templates/minimal/initial_data.py templates/minimal/schema.py test test/.cvsignore test/README.txt test/__init__.py test/benchmark.py test/db_test_base.py test/mocknull.py test/session_common.py test/test_actions.py test/test_anydbm.py test/test_cgi.py test/test_dates.py test/test_hyperdbvals.py test/test_indexer.py test/test_locking.py test/test_mailgw.py test/test_mailsplit.py test/test_metakit.py test/test_multipart.py test/test_mysql.py test/test_postgresql.py test/test_rfc2822.py test/test_schema.py test/test_security.py test/test_sqlite.py test/test_templating.py test/test_token.py test/test_tsearch2.py tools tools/.cvsignore tools/base64 tools/fixroles.py tools/load_tracker.py tools/migrate-queries.py tools/pygettext.py

erik.forsberg python-checkins at python.org
Sun Nov 5 21:30:53 CET 2006


Author: erik.forsberg
Date: Sun Nov  5 21:30:25 2006
New Revision: 52625

Added:
   tracker/vendor/roundup/current/.cvsignore
   tracker/vendor/roundup/current/BUILD.txt
   tracker/vendor/roundup/current/CHANGES.txt
   tracker/vendor/roundup/current/COPYING.txt
   tracker/vendor/roundup/current/ChangeLog
   tracker/vendor/roundup/current/MANIFEST.in
   tracker/vendor/roundup/current/README.txt
   tracker/vendor/roundup/current/cgi-bin/
   tracker/vendor/roundup/current/cgi-bin/roundup.cgi   (contents, props changed)
   tracker/vendor/roundup/current/demo.py
   tracker/vendor/roundup/current/detectors/
   tracker/vendor/roundup/current/detectors/creator_resolution.py
   tracker/vendor/roundup/current/detectors/emailauditor.py
   tracker/vendor/roundup/current/detectors/newissuecopy.py
   tracker/vendor/roundup/current/doc/
   tracker/vendor/roundup/current/doc/.cvsignore
   tracker/vendor/roundup/current/doc/FAQ.txt
   tracker/vendor/roundup/current/doc/Makefile
   tracker/vendor/roundup/current/doc/ZPL.txt
   tracker/vendor/roundup/current/doc/admin_guide.txt
   tracker/vendor/roundup/current/doc/announcement.txt
   tracker/vendor/roundup/current/doc/customizing.txt
   tracker/vendor/roundup/current/doc/debugging.txt
   tracker/vendor/roundup/current/doc/default.css
   tracker/vendor/roundup/current/doc/design.txt
   tracker/vendor/roundup/current/doc/developers.txt
   tracker/vendor/roundup/current/doc/features.txt
   tracker/vendor/roundup/current/doc/glossary.txt
   tracker/vendor/roundup/current/doc/images/
   tracker/vendor/roundup/current/doc/images/edit.png   (contents, props changed)
   tracker/vendor/roundup/current/doc/images/hyperdb.png   (contents, props changed)
   tracker/vendor/roundup/current/doc/images/logo-acl-medium.png   (contents, props changed)
   tracker/vendor/roundup/current/doc/images/logo-codesourcery-medium.png   (contents, props changed)
   tracker/vendor/roundup/current/doc/images/logo-software-carpentry-standard.png   (contents, props changed)
   tracker/vendor/roundup/current/doc/images/roundup-1.png   (contents, props changed)
   tracker/vendor/roundup/current/doc/images/roundup.png   (contents, props changed)
   tracker/vendor/roundup/current/doc/implementation.txt
   tracker/vendor/roundup/current/doc/index.txt
   tracker/vendor/roundup/current/doc/installation.txt
   tracker/vendor/roundup/current/doc/mysql.txt
   tracker/vendor/roundup/current/doc/original_overview.html
   tracker/vendor/roundup/current/doc/overview.txt
   tracker/vendor/roundup/current/doc/postgresql.txt
   tracker/vendor/roundup/current/doc/roundup-admin.1
   tracker/vendor/roundup/current/doc/roundup-demo.1
   tracker/vendor/roundup/current/doc/roundup-favicon.ico   (contents, props changed)
   tracker/vendor/roundup/current/doc/roundup-mailgw.1
   tracker/vendor/roundup/current/doc/roundup-server.1
   tracker/vendor/roundup/current/doc/roundup-server.ini.example
   tracker/vendor/roundup/current/doc/spec.html
   tracker/vendor/roundup/current/doc/tracker_templates.txt
   tracker/vendor/roundup/current/doc/upgrading.txt
   tracker/vendor/roundup/current/doc/user_guide.txt
   tracker/vendor/roundup/current/doc/whatsnew-0.7.txt
   tracker/vendor/roundup/current/doc/whatsnew-0.8.txt
   tracker/vendor/roundup/current/frontends/
   tracker/vendor/roundup/current/frontends/README.txt
   tracker/vendor/roundup/current/frontends/ZRoundup/
   tracker/vendor/roundup/current/frontends/ZRoundup/.cvsignore
   tracker/vendor/roundup/current/frontends/ZRoundup/ZRoundup.py
   tracker/vendor/roundup/current/frontends/ZRoundup/__init__.py
   tracker/vendor/roundup/current/frontends/ZRoundup/dtml/
   tracker/vendor/roundup/current/frontends/ZRoundup/dtml/manage_addZRoundupForm.dtml
   tracker/vendor/roundup/current/frontends/ZRoundup/icons/
   tracker/vendor/roundup/current/frontends/ZRoundup/icons/tick_symbol.gif   (contents, props changed)
   tracker/vendor/roundup/current/frontends/ZRoundup/refresh.txt
   tracker/vendor/roundup/current/locale/
   tracker/vendor/roundup/current/locale/.cvsignore
   tracker/vendor/roundup/current/locale/GNUmakefile
   tracker/vendor/roundup/current/locale/de.po
   tracker/vendor/roundup/current/locale/en.po
   tracker/vendor/roundup/current/locale/es_AR.po   (contents, props changed)
   tracker/vendor/roundup/current/locale/fr.po
   tracker/vendor/roundup/current/locale/lt.po   (contents, props changed)
   tracker/vendor/roundup/current/locale/roundup.pot
   tracker/vendor/roundup/current/locale/ru.po
   tracker/vendor/roundup/current/locale/zh_CN.po
   tracker/vendor/roundup/current/locale/zh_TW.po   (contents, props changed)
   tracker/vendor/roundup/current/patches/
   tracker/vendor/roundup/current/patches/20020205.alternate_auth
   tracker/vendor/roundup/current/roundup/
   tracker/vendor/roundup/current/roundup/.cvsignore
   tracker/vendor/roundup/current/roundup/__init__.py
   tracker/vendor/roundup/current/roundup/admin.py
   tracker/vendor/roundup/current/roundup/backends/
   tracker/vendor/roundup/current/roundup/backends/.cvsignore
   tracker/vendor/roundup/current/roundup/backends/__init__.py
   tracker/vendor/roundup/current/roundup/backends/back_anydbm.py
   tracker/vendor/roundup/current/roundup/backends/back_metakit.py   (contents, props changed)
   tracker/vendor/roundup/current/roundup/backends/back_mysql.py
   tracker/vendor/roundup/current/roundup/backends/back_postgresql.py
   tracker/vendor/roundup/current/roundup/backends/back_sqlite.py
   tracker/vendor/roundup/current/roundup/backends/back_tsearch2.py
   tracker/vendor/roundup/current/roundup/backends/blobfiles.py
   tracker/vendor/roundup/current/roundup/backends/indexer_common.py
   tracker/vendor/roundup/current/roundup/backends/indexer_dbm.py
   tracker/vendor/roundup/current/roundup/backends/indexer_rdbms.py
   tracker/vendor/roundup/current/roundup/backends/indexer_xapian.py
   tracker/vendor/roundup/current/roundup/backends/locking.py
   tracker/vendor/roundup/current/roundup/backends/portalocker.py
   tracker/vendor/roundup/current/roundup/backends/rdbms_common.py
   tracker/vendor/roundup/current/roundup/backends/sessions_dbm.py
   tracker/vendor/roundup/current/roundup/backends/sessions_rdbms.py
   tracker/vendor/roundup/current/roundup/backends/tsearch2_setup.py
   tracker/vendor/roundup/current/roundup/cgi/
   tracker/vendor/roundup/current/roundup/cgi/.cvsignore
   tracker/vendor/roundup/current/roundup/cgi/MultiMapping.py
   tracker/vendor/roundup/current/roundup/cgi/PageTemplates/
   tracker/vendor/roundup/current/roundup/cgi/PageTemplates/.cvsignore
   tracker/vendor/roundup/current/roundup/cgi/PageTemplates/Expressions.py
   tracker/vendor/roundup/current/roundup/cgi/PageTemplates/GlobalTranslationService.py
   tracker/vendor/roundup/current/roundup/cgi/PageTemplates/MultiMapping.py
   tracker/vendor/roundup/current/roundup/cgi/PageTemplates/PageTemplate.py   (contents, props changed)
   tracker/vendor/roundup/current/roundup/cgi/PageTemplates/PathIterator.py
   tracker/vendor/roundup/current/roundup/cgi/PageTemplates/PythonExpr.py
   tracker/vendor/roundup/current/roundup/cgi/PageTemplates/README.txt
   tracker/vendor/roundup/current/roundup/cgi/PageTemplates/TALES.py
   tracker/vendor/roundup/current/roundup/cgi/PageTemplates/__init__.py
   tracker/vendor/roundup/current/roundup/cgi/TAL/
   tracker/vendor/roundup/current/roundup/cgi/TAL/.cvsignore
   tracker/vendor/roundup/current/roundup/cgi/TAL/DummyEngine.py
   tracker/vendor/roundup/current/roundup/cgi/TAL/HTMLParser.py
   tracker/vendor/roundup/current/roundup/cgi/TAL/HTMLTALParser.py
   tracker/vendor/roundup/current/roundup/cgi/TAL/README.txt
   tracker/vendor/roundup/current/roundup/cgi/TAL/TALDefs.py
   tracker/vendor/roundup/current/roundup/cgi/TAL/TALGenerator.py
   tracker/vendor/roundup/current/roundup/cgi/TAL/TALInterpreter.py
   tracker/vendor/roundup/current/roundup/cgi/TAL/TALParser.py
   tracker/vendor/roundup/current/roundup/cgi/TAL/TranslationContext.py
   tracker/vendor/roundup/current/roundup/cgi/TAL/XMLParser.py
   tracker/vendor/roundup/current/roundup/cgi/TAL/__init__.py
   tracker/vendor/roundup/current/roundup/cgi/TAL/markupbase.py
   tracker/vendor/roundup/current/roundup/cgi/TAL/talgettext.py
   tracker/vendor/roundup/current/roundup/cgi/TranslationService.py
   tracker/vendor/roundup/current/roundup/cgi/ZTUtils/
   tracker/vendor/roundup/current/roundup/cgi/ZTUtils/.cvsignore
   tracker/vendor/roundup/current/roundup/cgi/ZTUtils/Batch.py
   tracker/vendor/roundup/current/roundup/cgi/ZTUtils/Iterator.py
   tracker/vendor/roundup/current/roundup/cgi/ZTUtils/__init__.py
   tracker/vendor/roundup/current/roundup/cgi/__init__.py
   tracker/vendor/roundup/current/roundup/cgi/accept_language.py   (contents, props changed)
   tracker/vendor/roundup/current/roundup/cgi/actions.py   (contents, props changed)
   tracker/vendor/roundup/current/roundup/cgi/apache.py
   tracker/vendor/roundup/current/roundup/cgi/cgitb.py
   tracker/vendor/roundup/current/roundup/cgi/client.py
   tracker/vendor/roundup/current/roundup/cgi/exceptions.py   (contents, props changed)
   tracker/vendor/roundup/current/roundup/cgi/form_parser.py   (contents, props changed)
   tracker/vendor/roundup/current/roundup/cgi/templating.py
   tracker/vendor/roundup/current/roundup/cgi/zLOG.py
   tracker/vendor/roundup/current/roundup/configuration.py
   tracker/vendor/roundup/current/roundup/date.py
   tracker/vendor/roundup/current/roundup/exceptions.py
   tracker/vendor/roundup/current/roundup/hyperdb.py
   tracker/vendor/roundup/current/roundup/i18n.py
   tracker/vendor/roundup/current/roundup/init.py
   tracker/vendor/roundup/current/roundup/install_util.py
   tracker/vendor/roundup/current/roundup/instance.py
   tracker/vendor/roundup/current/roundup/mailer.py
   tracker/vendor/roundup/current/roundup/mailgw.py
   tracker/vendor/roundup/current/roundup/msgfmt.py
   tracker/vendor/roundup/current/roundup/password.py
   tracker/vendor/roundup/current/roundup/rfc2822.py
   tracker/vendor/roundup/current/roundup/roundupdb.py
   tracker/vendor/roundup/current/roundup/scripts/
   tracker/vendor/roundup/current/roundup/scripts/.cvsignore
   tracker/vendor/roundup/current/roundup/scripts/__init__.py
   tracker/vendor/roundup/current/roundup/scripts/roundup_admin.py
   tracker/vendor/roundup/current/roundup/scripts/roundup_demo.py
   tracker/vendor/roundup/current/roundup/scripts/roundup_gettext.py
   tracker/vendor/roundup/current/roundup/scripts/roundup_mailgw.py
   tracker/vendor/roundup/current/roundup/scripts/roundup_server.py
   tracker/vendor/roundup/current/roundup/security.py
   tracker/vendor/roundup/current/roundup/support.py
   tracker/vendor/roundup/current/roundup/token.py
   tracker/vendor/roundup/current/roundup/version_check.py
   tracker/vendor/roundup/current/run_tests.py
   tracker/vendor/roundup/current/scripts/
   tracker/vendor/roundup/current/scripts/README.txt
   tracker/vendor/roundup/current/scripts/add-issue   (contents, props changed)
   tracker/vendor/roundup/current/scripts/copy-user.py   (contents, props changed)
   tracker/vendor/roundup/current/scripts/hyperdb_example.py
   tracker/vendor/roundup/current/scripts/imapServer.py
   tracker/vendor/roundup/current/scripts/import_sf.py
   tracker/vendor/roundup/current/scripts/roundup-reminder   (contents, props changed)
   tracker/vendor/roundup/current/scripts/roundup.rc-debian
   tracker/vendor/roundup/current/scripts/schema_diagram.py
   tracker/vendor/roundup/current/scripts/server-ctl   (contents, props changed)
   tracker/vendor/roundup/current/setup.py
   tracker/vendor/roundup/current/templates/
   tracker/vendor/roundup/current/templates/classic/
   tracker/vendor/roundup/current/templates/classic/.cvsignore
   tracker/vendor/roundup/current/templates/classic/TEMPLATE-INFO.txt
   tracker/vendor/roundup/current/templates/classic/detectors/
   tracker/vendor/roundup/current/templates/classic/detectors/.cvsignore
   tracker/vendor/roundup/current/templates/classic/detectors/messagesummary.py
   tracker/vendor/roundup/current/templates/classic/detectors/nosyreaction.py
   tracker/vendor/roundup/current/templates/classic/detectors/statusauditor.py
   tracker/vendor/roundup/current/templates/classic/detectors/userauditor.py
   tracker/vendor/roundup/current/templates/classic/extensions/
   tracker/vendor/roundup/current/templates/classic/extensions/README.txt
   tracker/vendor/roundup/current/templates/classic/html/
   tracker/vendor/roundup/current/templates/classic/html/_generic.calendar.html
   tracker/vendor/roundup/current/templates/classic/html/_generic.collision.html
   tracker/vendor/roundup/current/templates/classic/html/_generic.help.html
   tracker/vendor/roundup/current/templates/classic/html/_generic.index.html
   tracker/vendor/roundup/current/templates/classic/html/_generic.item.html
   tracker/vendor/roundup/current/templates/classic/html/file.index.html
   tracker/vendor/roundup/current/templates/classic/html/file.item.html
   tracker/vendor/roundup/current/templates/classic/html/help_controls.js
   tracker/vendor/roundup/current/templates/classic/html/home.classlist.html
   tracker/vendor/roundup/current/templates/classic/html/home.html
   tracker/vendor/roundup/current/templates/classic/html/issue.index.html
   tracker/vendor/roundup/current/templates/classic/html/issue.item.html
   tracker/vendor/roundup/current/templates/classic/html/issue.search.html
   tracker/vendor/roundup/current/templates/classic/html/keyword.item.html
   tracker/vendor/roundup/current/templates/classic/html/msg.index.html
   tracker/vendor/roundup/current/templates/classic/html/msg.item.html
   tracker/vendor/roundup/current/templates/classic/html/page.html
   tracker/vendor/roundup/current/templates/classic/html/query.edit.html
   tracker/vendor/roundup/current/templates/classic/html/query.item.html
   tracker/vendor/roundup/current/templates/classic/html/style.css
   tracker/vendor/roundup/current/templates/classic/html/user.forgotten.html
   tracker/vendor/roundup/current/templates/classic/html/user.index.html
   tracker/vendor/roundup/current/templates/classic/html/user.item.html
   tracker/vendor/roundup/current/templates/classic/html/user.register.html
   tracker/vendor/roundup/current/templates/classic/html/user.rego_progress.html
   tracker/vendor/roundup/current/templates/classic/initial_data.py
   tracker/vendor/roundup/current/templates/classic/schema.py
   tracker/vendor/roundup/current/templates/minimal/
   tracker/vendor/roundup/current/templates/minimal/.cvsignore
   tracker/vendor/roundup/current/templates/minimal/TEMPLATE-INFO.txt
   tracker/vendor/roundup/current/templates/minimal/detectors/
   tracker/vendor/roundup/current/templates/minimal/detectors/.cvsignore
   tracker/vendor/roundup/current/templates/minimal/detectors/userauditor.py
   tracker/vendor/roundup/current/templates/minimal/extensions/
   tracker/vendor/roundup/current/templates/minimal/extensions/README.txt
   tracker/vendor/roundup/current/templates/minimal/html/
   tracker/vendor/roundup/current/templates/minimal/html/_generic.calendar.html
   tracker/vendor/roundup/current/templates/minimal/html/_generic.collision.html
   tracker/vendor/roundup/current/templates/minimal/html/_generic.help.html
   tracker/vendor/roundup/current/templates/minimal/html/_generic.index.html
   tracker/vendor/roundup/current/templates/minimal/html/_generic.item.html
   tracker/vendor/roundup/current/templates/minimal/html/help_controls.js
   tracker/vendor/roundup/current/templates/minimal/html/home.classlist.html
   tracker/vendor/roundup/current/templates/minimal/html/home.html
   tracker/vendor/roundup/current/templates/minimal/html/page.html
   tracker/vendor/roundup/current/templates/minimal/html/style.css
   tracker/vendor/roundup/current/templates/minimal/html/user.index.html
   tracker/vendor/roundup/current/templates/minimal/html/user.item.html
   tracker/vendor/roundup/current/templates/minimal/html/user.register.html
   tracker/vendor/roundup/current/templates/minimal/html/user.rego_progress.html
   tracker/vendor/roundup/current/templates/minimal/initial_data.py
   tracker/vendor/roundup/current/templates/minimal/schema.py
   tracker/vendor/roundup/current/test/
   tracker/vendor/roundup/current/test/.cvsignore
   tracker/vendor/roundup/current/test/README.txt
   tracker/vendor/roundup/current/test/__init__.py
   tracker/vendor/roundup/current/test/benchmark.py
   tracker/vendor/roundup/current/test/db_test_base.py
   tracker/vendor/roundup/current/test/mocknull.py
   tracker/vendor/roundup/current/test/session_common.py
   tracker/vendor/roundup/current/test/test_actions.py   (contents, props changed)
   tracker/vendor/roundup/current/test/test_anydbm.py
   tracker/vendor/roundup/current/test/test_cgi.py
   tracker/vendor/roundup/current/test/test_dates.py
   tracker/vendor/roundup/current/test/test_hyperdbvals.py
   tracker/vendor/roundup/current/test/test_indexer.py
   tracker/vendor/roundup/current/test/test_locking.py
   tracker/vendor/roundup/current/test/test_mailgw.py
   tracker/vendor/roundup/current/test/test_mailsplit.py
   tracker/vendor/roundup/current/test/test_metakit.py
   tracker/vendor/roundup/current/test/test_multipart.py
   tracker/vendor/roundup/current/test/test_mysql.py
   tracker/vendor/roundup/current/test/test_postgresql.py
   tracker/vendor/roundup/current/test/test_rfc2822.py
   tracker/vendor/roundup/current/test/test_schema.py
   tracker/vendor/roundup/current/test/test_security.py
   tracker/vendor/roundup/current/test/test_sqlite.py
   tracker/vendor/roundup/current/test/test_templating.py
   tracker/vendor/roundup/current/test/test_token.py
   tracker/vendor/roundup/current/test/test_tsearch2.py
   tracker/vendor/roundup/current/tools/
   tracker/vendor/roundup/current/tools/.cvsignore
   tracker/vendor/roundup/current/tools/base64   (contents, props changed)
   tracker/vendor/roundup/current/tools/fixroles.py
   tracker/vendor/roundup/current/tools/load_tracker.py   (contents, props changed)
   tracker/vendor/roundup/current/tools/migrate-queries.py
   tracker/vendor/roundup/current/tools/pygettext.py
Log:

Importing roundup 1.1.2.


Added: tracker/vendor/roundup/current/.cvsignore
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/.cvsignore	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,9 @@
+*.pyc
+*.pyo
+localconfig.py
+build
+demo
+dist
+MANIFEST
+_test_*
+*.cover

Added: tracker/vendor/roundup/current/BUILD.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/BUILD.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,51 @@
+Building Releases
+=================
+
+Roundup is currently a source-only release - it has no binary components. I
+want it to stay that way, too. This document describes how to build a
+source release. Users of Roundup should read the doc/installation.txt file
+to find out how to install this software.
+
+Building and distributing a release of Roundup is done by running:
+
+1.  Make sure the unit tests run! "./run_tests.py"
+2.  Tag the CVS for the release, eg. "cvs tag -R release-0-6-3"
+3.  Edit roundup/__init__.py and doc/announcement.txt to reflect the new
+    version and appropriate announcements. Add truncated announcement to
+    setup.py description field.
+4.  Clean out all *.orig, *.rej, .#* files from the source.
+5.  python setup.py clean --all
+6.  Edit setup.py to ensure that all information therein (version, contact
+    information etc) is correct.
+7.  python setup.py sdist --manifest-only
+8.  Check the MANIFEST to make sure that any new files are included. If
+    they are not, edit MANIFEST.in to include them. "Documentation" for
+    MANIFEST.in may be found in disutils.filelist._parse_template_line.
+9.  python setup.py sdist
+    (if you find sdist a little verbose, add "--quiet" to the end of the
+     command)
+10. Unpack the new dist file in /tmp then a) run_test.py and b) demo.py
+    with all available Python versions.
+11. Generate gpg signature with "gpg -a --detach-sign"
+12. python setup.py bdist_rpm
+13. python setup.py bdist_wininst
+14. Send doc/announcement.txt to python-announce at python.org
+15. Notify any other news services as appropriate...
+
+      http://freshmeat.net/projects/roundup/
+
+
+So, those commands in a nice, cut'n'pasteable form::
+
+ find . -name '*.orig' -exec rm {} \;
+ find . -name '*.rej' -exec rm {} \;
+ find . -name '.#*' -exec rm {} \;
+ python setup.py clean --all
+ python setup.py sdist --manifest-only
+ python setup.py sdist --quiet
+ python setup.py bdist_rpm
+ python setup.py bdist_wininst
+ python setup.py register
+ python2.5 setup.py sdist upload --sign
+
+

Added: tracker/vendor/roundup/current/CHANGES.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/CHANGES.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,1873 @@
+This file contains the changes to the Roundup system over time. The entries
+are given with the most recent entry first.
+
+2006-04-27 1.1.2
+Feature:
+- server-ctl script uses server configuration file (sf bug 1443805)
+
+Fixed:
+- progress display in roundup-admin reindex
+- bug in menu() permission filter (sf bug 1444440)
+- indexing may be turned off for FileClass "content" now
+  ("content" and "type" properties are now automatically included in the
+  FileClass schema where previously the "content" property was faked and
+  "type" was optional)
+- verbose output during import is optional now (sf bug 1475624)
+- escape *all* uses of "schema" in mysql backend (sf bug 1472120)
+- responses to user rego email (sf bug 1470254)
+- dangling connections in session handling (sf bug 1463359)
+- reduced frequency of session timestamp update
+- classhelp popup pagination forgot about "type" (sf bug 1465836)
+- umask is now configurable (with the same 0002 default)
+- sorting of entries in classhelp popup (sf bug 1449000)
+- allow single digit seconds in date spec (sf bug 1447141)
+- prevent generation of new single-digit seconds dates (sf bug 1429390)
+- implement close() on all indexers (sf bug 1242477)
+
+
+2006-03-03 1.1.1
+Fixed:
+- failure with browsers not sending "Accept-Language" header
+  (sf bugs 1429646 and 1435335)
+- translate class name in "required property not supplied" error message
+  (sf bug 1429669)
+- error in link property lookups with numeric-alike key values (sf bug 1424550)
+- ignore UTF-8 BOM in .po files
+- add permission filter to menu() implementations (sf bug 1431188)
+- lithuanian translation updated by Nerijus Baliunas (sf patch 1411175)
+- incompatibility with python2.3 in the mailer module (sf bug 1432602)
+- typo in SMTP TLS option name: "MAIL_TLS_CERFILE" (sf bug 1435452)
+- email obfuscation code in html templating is more robust
+- blank-title subject line handling (sf bug 1442121)
+- "All users may only view and edit issues, files and messages they
+  create" example in docs (sf bug 1439086)
+- saving of queries (sf bug 1436169)
+- "Adding a new constrained field to the classic schema" example in docs
+  (sf bug 1433118)
+- security check in mailgw (sf bug 1442145)
+- "clear this message" (sf bug 1429367)
+- escape all uses of "schema" in mysql backend (sf bug 1397569)
+- date spec wasn't allowing week intervals
+
+
+2006-02-10 1.1.0
+Feature:
+- trackers may configure custom stop-words for the full-text indexer
+- login may now be for a single session (and this is the default)
+- trackers may hide exceptions from web users (they will be mailed to the
+  tracker admin) (hiding is the default)
+- include "clear this message" link in the "ok" message bar
+
+Fixed:
+- fixes in scripts/import_sf.py
+- fix some unicode bugs in roundup-admin import
+- Xapian indexer wasn't actually being used and its reindexing of existing
+  data was busted to boot
+- roundup-admin import wasn't indexing message content
+- allow dispname to be passed to renderWith (sf bug 1424587)
+- rename dispname to @dispname to avoid name clashes in the future
+- fixed schema migration problem when Class keys were removed
+
+
+2006-02-03 1.0.1
+Feature:
+- scripts/import_sf.py will import a tracker from Sourceforge.NET
+- added hasRole() to HTMLUser
+
+Fixed:
+- SQL generation for sort/group by separate Link properties (sf bug
+  1417565)
+- fix timezone offsetting in email Date: header
+- fix security check for hasPermission('Permission', None)
+
+
+2006-01-27 1.0
+Feature:
+- Lithuanian translation by Aiste Kesminaite
+- Web User Interface language selection by form variable @language,
+  browser cookie or HTTP header Accept-Language (sf patch 1360321)
+- initial values for configuration options may be passed on
+  'roundup-admin install' command line (based on sf patch 1237110)
+- favicon.ico image may be changed with server config option (sf patch 1355661)
+- Password objects initialized from plaintext remember plaintext value
+  (sf rfe 1379447)
+- Roundup installation document includes configuration example
+  for Exim Internet Mailer (sf bug 1393860)
+- enable registration confirmation by web only (sf bug 1381675)
+- allow preselection of values in templating menu()s (sf patch 1396085)
+- display the query name in the header (sf feature 1298535 / patch 1349387)
+- classhelp works with Link properties now (sf bug 1410290)
+- added setorderprop() and setlabelprop() to Class (sf features 1379534,
+  1379490)
+- CSV encoding support (sf bug 1240848)
+- fields rendered with StructuredText are hyperlinked by default
+- additional attributes for input element may be passed to the 'field'
+  method of a property wrapper
+- added "copy_url" method to generate a URL for copying an item
+
+Fixed:
+- MySQL now creates String columns using the TEXT column type
+- password.crypt won't work with md5 passwords (sf bug 1372253)
+- use quoted printable encoding for nosy attachments that have MIME
+  type 'text/plain' but contain 8-bit characters (sf bug 1381559)
+- login name and email address fields in the classic template
+  are highlighted as required fields (sf bug 1392364)
+- french translation updated by Patrick Decat (sf patch 1397059)
+- HTTP authorization takes precedence over session cookie (sf bug 1396134)
+- enforce correct encoding of PostgreSQL backend (sf bug 1374235)
+- grouping/sorting on link to same class fixed (sf bug 1404930)
+- all backends implement the retired check in getnodeids (sf bug 1290560)
+- fix detection of "missing" existing values in CGI form parser (sf bug
+  1414149)
+- ZRoundup works again (sf bug 1263842)
+- default user template does not display password fields and submit button
+  when editing is not allowed
+- fix StructuredText import in cgi.templating
+- have "System Messages" be marked as such again (sf bug 1281907)
+- enable editing of public queries (sf bug 966144)
+
+
+2005-10-07 0.9.0b1
+Feature:
+- added "imapServer.py" script (sf patch 934567)
+- added date selection popup windows (thanks Marcus Priesch)
+- added Xapian indexer; replaces standard indexers if Xapian is available
+- mailgw subject parsing has configurable levels of strictness
+- nosy messages may be sent individually to all recipients
+- remember where we came from when logging in (sf patch 1312889)
+
+
+2006-??-?? 0.8.6
+Fixed:
+- french translation updated by Patrick Decat (sf patch 1397059)
+- tighten up Date parsing to not allow 'M/D/YY' (or 'D/M/YY) (sf bug
+  1290550)
+- handle "schema" being reserved word in MySQL 5+ (sf bug 1397569)
+- fixed documentation of filter() in the case of multiple values in a
+  String search (sf bug 1373396)
+- fix comma-separated ID filter spec in web requests (sf bug 1396278)
+- fix Date: header generation to be LOCALE-agnostic (sf bug 1352624)
+- fix admin doc description of roundup-server config file
+- fix redirect after instant registration (sf bug 1381676)
+- fix permission checks in cgi interface (sf bug 1289557)
+- fix permission check on RetireAction (sf bug 1407342)
+- timezone now applied to date for pretty-format (sf bug 1406861)
+- fix mangling of "_" in mail Subject class name (sf bug 1413852)
+- catch bad classname in URL (related to sf bug 1240541)
+- clean up digested_file_types (sf bug 1268303)
+- fix permission checks in mailgw (sf bug 1263655)
+- fix encoding of subject in generated error message (sf bug 1414465)
+
+
+2005-10-07 0.8.5
+Feature:
+- Argentinian Spanish translation by Ramiro Morales
+
+Fixed:
+- Display of Multilinks where linked Class labelprop values are None
+- Fix references to the old * Registration Permissions
+- Fix missing merge of fix to sf bug 1177057
+- Fix RDBMS indexer indexing UTF-8 words that encode to > 30 chars
+- Handle invalidly-specified charsets in incoming email
+
+
+2005-07-18 0.8.4
+Fixed:
+- extra CRs in CSV export files on Windows platform (sf bug 1195742)
+- activity RDBMS columns were being reported in changes
+- fix name collision in roundup.cgi script (sf bug 1203795)
+- fix handling of invalid interval input
+- search locale files relative ro roundup installation path (sf bug 1219689)
+- use translation for boolean property rendering (sf bug 1225152)
+- enabled disabling of REMOTE_USER for when it's not a valid username (sf
+  bug 1190187)
+- fix invocation of hasPermission from templating code (sf bug 1224172)
+- have 'roundup-admin security' display property restrictions (sf bug
+  1222135)
+- fixed templating menu() sort_on handling (sf bug 1221936)
+- allow specification of pagesize, sorting and filtering in "classhelp"
+  popups (sf bug 1211800)
+- handle dropped properies in rdbms/metakit journal export (sf bug 1203569)
+- handle missing Subject lines better (sf bug 1198729)
+- sort/group by missing values correctly (sf bugs 1198623, 1176897)
+- discard, don't bounce messages to the mailgw when the messages's sender
+  is invalid (ie. when we try to bounce, we get a 550 "unknown user
+  account" response from the SMTP server) (sf bug 1190906)
+- removed debugging code from cgi/actions.py
+- refactored hyperdb.rawToHyperdb, allowing a number of improvements
+  (thanks Ralf Schlatterbeck)
+- don't try to set a timeout for IMAPS (thanks Paul Jimenez)
+- present Reject exception messages to web users (sf bug 1237685)
+
+
+2005-05-02 0.8.3
+Feature:
+- chinese translation by limodou
+
+Fixed:
+- fix reference to The Zope Book in Roundup FAQ
+- disabled file logging in Roundup test suite (sf bug 1155649)
+- return original string if message issue xref isn't valid
+- fix nosyreaction.py to stop it setting the nosy list unnecessarily
+  (see doc/upgrading.txt for how to fix in your trackers)
+- after logout, always display tracker home page
+- web forms don't create new items if no item properties are set from UI
+- item creation failed if multilink fields had invalid entries (sf bug
+  1177602)
+- fix bdist_rpm (sf bug 1164328)
+- fix checking of "Email Access" for Anonymous email registration (sf bug
+  1177057)
+- disable "Email Access" for Anonymous by default to stop spam regsitering
+  users on public trackers
+- send errors in the web interface to a logfile by default. Use the
+  "debug" multiprocess mode (roundup-server) or the DEBUG_TO_CLIENT var
+  (roundup.cgi) to have the errors appear in your browser
+- fix setgid typo (sf bug 1171346)
+- fix faulty find_template filename facility (sf bug 1163629)
+- fix roundup-admin "export" so it creates the target dir if needed
+- "fix" roundup-admin "import" to not use "universal newline support" since
+  the csv module appears to have its own ideas about such things (sf bug
+  1163890)
+- fix installation docs referring to old-style configuration variables
+- fix roundup-admin "find" for searching Multilinks (sf bug 1189465)
+
+
+2005-03-03 0.8.2
+Feature:
+- roundup-server automatically redirects from trackers list
+  to the tracker page if there is only one tracker
+
+Fixed:
+- added content to ZRoundup refresh.txt file (sf bug 1147622)
+- fix invalid reference to csv.colon_separated
+- correct URL to What's New in setup.py meta-data
+- change AUTOCOMMIT=OFF to AUTOCOMMIT=0 for MySQL (sf bug 1143707)
+- compile message objects in 'setup.py build'
+- use backend datatype for journal timestamps in RDBMSes
+- fixes to the "Using an external password validation source"
+  customisation example (sf bugs 1153640 and 1155108)
+
+
+2005-02-17 0.8.1
+Fixed:
+- replaced MutlilinkIterator with multilinkGenerator (thanks Bob Ippolito)
+- fixed broken csv import in roundup.admin module
+- fixed braino in HTMLClass.filter() (sf bug 1124213)
+- change ZTUtils Iterator to always iter() its sequence argument
+
+
+2005-01-16 0.8.0
+Fixed:
+- fix roundup-server log and PID file paths to be absolute
+- fix initialisation of roundup-server in daemon mode so initialisation
+  errors are visible
+- fix: 'Logout' link was enabled on issue index page only
+- have Permissions only test the check function if itemid is suppled
+- modify cgi templating system to check item-level permissions in listings
+- enable batching in message and file listings
+- more documentation of security mechanisms (incl. sf patches 1117932,
+  1117860)
+- better unit tests for security mechanisms
+- code cleanup (sf patch 1115329 and additional)
+- issue search page allows setting of no sorting / grouping (sf bug
+  1119475)
+- better edit conflict handling (sf bug 1118790)
+- consistent text searching behaviour (AND everywhere) (sf bug 1101036)
+- fix handling of invalid date input (sf bug 1102165)
+- retain Boolean selections in edit error handling (sf bug 1101492)
+- fix initialisation of logging module from config file (sf bug 1108577)
+- removed rlog module (py 2.3 is minimum version now)
+- fixed class "help" listing paging (sf bug 1106329)
+- nicer error looking up values of None (response to sf bug 1108697)
+- fallback for (list) popups if javascript disabled (sf patch 1101626)
+
+
+2005-01-13 0.8.0b2
+Fixed:
+- note about how to run roundup demo in Windows (sf bug 1082090)
+- fix API for templating utils extensions - remove "utils" arg (sf bug 1081981)
+- back_sqlite.py is missing "import time" (sf bug 1081959)
+- fix (list) popup (sf bug 1083570)
+- fix some security assertions (sf bug 1085481)
+- 'roundup-server -S' always writes [trackers] section heading (sf bug 1088878)
+- fix port number as int in mysql connection info (sf bug 1082530)
+- fix setup.py to work with <Python2.3 (sf bug 1082801)
+- fix permissions checks in cgi templating (sf bug 1082755)
+- fix "Users may only edit their issues" example in docs
+- handle ~/.my.cnf files for MySQL defaults (sf bug 1096031)
+
+
+2004-12-08 0.8.0b1
+Feature:
+- added MD5 scheme for password hiding
+- added support for HTTP charset selection
+- implement __nonzero__ for HTMLProperty
+- remove "manual" locking of sqlite database
+- create a new RDBMS cursor after committing
+- added basic logging, and configuration of it and python's logging module
+- roundup-mailgw now logs fatal exceptions rather than mailing them to admin
+- add a default argument to the DateHTMLProperty.field method, and an
+  optional Interval (string or object) to the DateHTMLProperty.now (patch
+  from Vickenty Fesunov)
+- hide "(list)" popup links when issue is only viewable
+- roundup-server options -g and -u accept both ids and names (sf bug 983769)
+- roundup-server now has a configuration file (-C option)
+- added mod_python interface (see installation.txt)
+- reorganised tracker configuration, using ConfigParser config, cleaned-up
+  schema definition and implementing easier extension writing (sf rfe 661301)
+- Permissions may now be defined on a per-property basis
+- added "Create" Permission. Replaces the "Web"- and "Email Registration"
+  Permissions.
+- added option to turn off registration confirmation via email
+  ("instant_registration" in config) (sf rfe 922209)
+- roundup-admin reindex command may now work on single items or classes
+- multiple selection Link/Multilink search field (thanks Marlon van den Berg)
+- relaxed hyperlinking in web interface (accept "issue123" or "Issue 123")
+- record journaltag lookup ("fixes" sf bug 998140)
+- allow listing popup to be used in query forms (thanks Marcus Priesch)
+- roundup windows service may be installed with command line options
+  recognized by roundup-server (but not tracker specification arguments).
+  Use this to specify server configuration file for the service.
+- added experimental multi-thread server
+- don't try to import all backends in backends.__init__ unless we *want* to
+- unless in debug mode, keep a single persistent connection through a
+  single web or mailgw request.
+- HTTP Basic Authentication (sf patch 1067690)
+- extended security.addPermissionToRole to allow skipping the separate
+  getPermission call
+
+Fixed:
+- postgres backend open doesn't hide corruption in schema (sf bug 956375)
+- *dbm-style backends nuke() method now clear id counters
+- removed safeget() from the API (sf bug 994750)
+- demo tracker is always set up on localhost (sf bug 1049101)
+- relaxed URL designator syntax to allow issue[0]*1 (sf bug 1054523)
+
+
+2005-05-02 0.7.12
+Fixed:
+- handle capitalisation of class names in text hyperlinking (sf bug
+  1101043)
+- quote full-text search text in URL generation
+- fixed problem migrating mysql databases
+- fix search_checkboxes macro (sf patch 1113828)
+- fix bug in date editing in Metakit
+- allow suppression of search_text in indexargs_form (sf bug 1101548)
+- hack to fix some anydbm export problems (sf bug 1081454)
+- ignore AutoReply messages (sf patch 1085051)
+- fix ZRoundup syntax error (sf bug 1122335)
+- fix RDBMS clear() so it resets all class itemid counters
+
+
+2005-01-06 0.7.11
+Fixed:
+- index args URL generation broken in .10 (sf bug 1096027)
+- handle NotModified for non-static files (sf patch 1095790)
+- fix permission lookup in query editing
+
+
+2005-01-04 0.7.10
+Fixed:
+- reset ID counters if the database is cleared (thanks William)
+- apply IE caching "fix" to automatically serve up all pages expired
+- fix typo (sf patch 1076629)
+- fix hyperlinking of items (sf bug 1080251)
+- fix roundup-admin find command handling of Multilinks
+- fix some security assertions (sf bug 1085481)
+- don't set the title to nothing from incoming mail (thanks Bruce Guenter)
+- fix py2.4 strftime() API change bug (sf bug 1087746)
+- fix indexer searching with no valid words (sf bug 1086787)
+- updated searching / indexing docs
+- fix "(list)" popup when list is one item long (sf bug 1064716)
+- have RDBMS full-text indexer do AND searching (sf bug 1055435)
+- handle spaces in String index params in batching (sf bug 1054224)
+
+
+2004-10-26 0.7.9
+Feature:
+- DateHTMLProperty.field() accepts format string (thanks Wil Cooley)
+
+Fixed:
+- popup listing uses filter args (thanks Marlon van den Berg)
+- fixed editing of message contents
+- loosened the detection of issue cross-references in messages
+- open CSV files in "universal newline" mode
+- s/Modifed/Modified (thanks donfu)
+- applied patch fixing some form handling issues in ZRoundup (sf bug 995565)
+- enforce View Permission when serving file content (sf bug 1050470)
+- don't index common words (sf bug 1046612)
+- don't wrap query.item.html in a <span> (thanks Roch'e Compaan)
+- TAL expressions like 'request/show/whatever' return True
+  if the request does not contain explicit @columns list
+- NumberHTMLProperty should return '' not "None" if not set (thanks
+  William)
+- ensure multilink ordering in RDBMS backends (thanks Marcus Priesch, sf
+  bug 950963)
+- always honor indexme property on Strings (sf patch 1063711)
+- make hyperdb value parsing errors readable in mailgw errors
+- make anydbm journal export handle removed properties
+- allow use of XML templates again
+
+
+2004-10-15 0.7.8
+Fixed:
+- Clean out sessions / otks tables when migrating
+
+
+2004-10-11 0.7.7
+Fixed:
+- ZRoundup's search interface works now (sf bug 994957)
+- fixed history display when "ascending"
+- removed references to py2.3+ boolean values (sf bug 995682)
+- fix static file path normalisation in security check (thanks David Linke)
+- less specific messages for login failures (thanks Chris Withers)
+- Reject raised against email messages should result in email rejection, not
+  discarding of the message
+- mailgw can override the MAIL_DEFAULT_CLASS
+- handle Py2.3+ datetime objects as Date specs (sf bug 971300)
+- use row locking in MySQL newid() (sf bug 1034211)
+- add sanity check for sort and group on same property (sf bug 1033477)
+- extend OTK and session table value cols to TEXT (sf bug 1031271)
+- fix lookup of REMOTE_USER (sf bug 1002923)
+- new Interval props weren't created properly in rdbms
+- date.Interval() now accepts an Interval as a spec (sf bug 1041266)
+- handle deleted properties in RDBMS history
+- apply timezone in correct direction in user input (sf bug 1013097)
+- more efficient find() in RDBMS (sf bug 1012781)
+
+
+2004-07-21 0.7.6
+Fixed:
+- rdbms backend full text search failure after import (sf bug 980314)
+- rdbms backends not filtering correctly on link=None
+- fix anydbm journal import (sf bug 983166)
+- handle postgresql bug in SQL generation (sf bug 984591)
+- fix dates-from-Dates (sf bug 984604)
+- fix messageid generated when msgid is None for send_message (sf bug 987933)
+- make user permissions check more sane (fix search page for anonymous)
+- fixed RDBMS filter() for no matches from full-text search (sf bug 990778)
+- fixed DateHTMLProperty for invalid date entry (sf bug 986538)
+- fixed external password source example (sf bug 986601)
+- document the STATIC_FILES config var
+- implement the HTTP HEAD command (sf bug 992544)
+- fix journal export of files to remove content from CSV files
+- API clarification. Previously, the anydbm/bsddb/metakit filter() methods
+  had required exact matches to Multilink argument lists. The RDBMS
+  backends treated Multilink matches like all other data types - matching
+  any of the Multilink argument list is good enough. The latter behaviour
+  is implemented across the board now.
+- fix metakit handling of filter on Link==None
+
+
+2004-06-24 0.7.5
+Fixed:
+- force lookup of journal props in anydbm filtering
+- fixed lookup of "missing" Link values for new props in anydbm backend
+- allow list of values for id, Number and Boolean filtering in anydbm
+  backend
+- fixed some more mysql 0.6->0.7 upgrade bugs (sf bug 950410)
+- fixed Boolean values in postgresql (sf bugs 972546 and 972600)
+- fixed -g arg to roundup-server (sf bug 973946)
+- better roundup-server usage string (sf bug 973352)
+- include "context" always, as documented (sf bug 965447)
+- fixed REMOTE_USER (external HTTP Basic auth) (sf bug 977309)
+- fixed roundup-admin "find" to use better value parsing
+- fixed RDBMS Class.find() to handle None value in multiple find
+- export now stores file "content" in separate files in export directory
+
+
+2004-06-10 0.7.4
+Fixed:
+- re-acquire the OTK manager when we re-open the database
+- mailgw handler can close the database on us
+- fixed grouping by a NULL Link value
+- fixed anydbm import/export (sf bugs 965216, 964457, 964450)
+- fix python 2.3.3 strftime deprecation warning (sf patch 968398)
+- fix some column datatypes in postgresql and mysql (sf bugs 962611,
+  959177 and 964231)
+- fixed RDBMS journal packing (sf bug 959177)
+- fixed filtering by floats in anydbm (sf bug 963584)
+
+
+2004-05-28 0.7.3
+Fixed:
+- add "checked" to truth values for Boolean input
+- fixed import in metakit backend
+- fix SearchAction use of Class.filter(), and clarify API docs for same
+- ensure static files may only be served out of the tracker's "static
+  files" directory
+
+
+2004-05-17 0.7.2
+Fixed:
+- anydbm sorting with None values (sf bug 952853)
+- roundup-server -g option not recognised (sf bug 952310)
+- HTML templating isset() inverted (sf bug 951779)
+- otks manager missing (sf bug 952931)
+- mention DEFAULT_TIMEZONE requirement in upgrading doc (sf bug 952932)
+- fix DateHTMLProperty so local() can override user timezone (sf bug
+  953678)
+- fix anydbm sort/group direction handling, and make RDBMS sort/group use
+  Link'ed "order" properties (sf bug 953148)
+- fix Interval editing (sf bug 954891)
+
+
+2004-05-10 0.7.1
+Fixed:
+- several temp files made it into the source distribution (sf bug 949243)
+- typo in roundup/instance.py
+- missing CRLF var in rfc822.py (sf patch 949471)
+- fix user creation page
+- have roundup server pass though the cause of a "403 Forbidden" response
+- fix schema mutation in sqlite backends (thanks Tamer Fahmy)
+- make popup Javascript IE 5.0 friendly (thanks Marlon van den Berg)
+- fix RDBMS import (thanks Tamer Fahmy)
+
+
+2004-05-06 0.7.0
+Fixed:
+- sqlite migration drops some journal information (thanks David Linke)
+- user editing Role entry help text always appears
+- disable forking server when os.fork() not available (sf bug 938586)
+- removed Boolean from source to make py <2.3 happy (sf bug 938790)
+- fix nested scope bug in rdbms multilink sorting
+- re-seed the random number generator for each request
+- postgresql backend altered to not use popen (thanks Georges Martin)
+- fixed journal marshalling in RDBMS backends (sf bug 943627)
+- fixed handling of key values starting with numbers (sf bug 941363)
+- fixed journal "param" column size in RDBMS backends
+- fixed static file serving
+- fixed rego from email address (sf bug 947414)
+- fixed sqlite journal ordering issue
+- fixed mysql date range filtering
+
+
+2004-04-18 0.7.0b3
+Feature:
+- added a favicon
+- added url_quote and html_quote methods to the utils object
+- added isset method to HTMLProperty
+- database export now exports full journals too
+- tracker name at end of page title (sf rfe 926840)
+- roundup-server now uses the ForkingMixin
+- added another sample detector "creator_resolution"
+- added search_checkboxes as an option for the search form
+- added IMAP support to mail gateway (sf rfe 934000)
+- check MANIFEST against the files actually unpacked
+- roundupdb nosymessage() takes an optional bcc list
+
+Fixed:
+- mysql and postgresql schema mutation now handle added Multilinks
+- web CSV export was busted (as was any action returning a result)
+- MultiMapping deviated from the Zope C implementation in a number of
+  places (thanks Toby Sargeant)
+- MySQL and Postgresql use BOOL/BOOLEAN for Boolean types
+- OTK generation was busted (thanks Stuart D. Gathman)
+- export and import now include journals (incompatible with export < 0.7)
+- added "download_url" method to generate a correctly quoted URL for file
+  download links (sf bug 927745)
+- all uses of TRACKER_WEB now ensure it ends with a '/'
+- roundup-admin install checks for existing tracker in target home
+- grouping (and sorting) by multilink in RDBMS backends (sf bug 655702)
+- roundup scripts may now be asked for their version (sf rfe 798657)
+- sqlite backend had stopped using the global lock
+- better check for anonymous viewing of user items (sf bug 933510)
+- stop Interval from displaying an empty string (sf bug 934022)
+- fixed storage of some datatypes in some RDBMS backends
+
+
+2004-03-27 0.7.0b2
+Feature:
+- added CSV export to index pages
+- added emailauditor.py which works around a bug in IE. See
+  "detectors/emailauditor.py" for more info.
+- added dispatcher functionality - see upgrading.txt for more info
+- added Reject exception which may be raised by auditors. This is trapped
+  by mailgw and may be used to veto creation of file attachments or
+  messages. (sf bug 700265)
+- queries on a per-user basis, and public queries (sf "bug" 891798 :)
+- added DEFAULT_TIMEZONE (sf rfe 895139)
+- added HTML page template to the templating context as "template"
+- added is_retired to HTMLItems in templating
+
+Fixed:
+- Boolean, Date and Link HTML templating was broken
+- fix reporting of test inclusion in postgresql test
+- EditAction was confused about who "self" was
+- edit collision detection was broken for index-page edits
+- sqlite backend wasn't migrating multilink tables correctly
+- use SimpleCookie instead of Cookie (is an alias for the evil SmartCookie)
+- handle older sessions in session dbm
+- make presetunread more resilient to status Class changes
+- HTMLDatabase classes() was broken
+
+
+2004-03-24 0.7.0b1
+Major new features:
+- added postgresql backend (originally from sf patch 761740, many changes
+  since)
+- added new "actor" automatic property (indicates user who cause the last
+  "activity")
+- RDBMS backends implement their session and one-time-key stores and
+  full-text indexers; thus they are now performing their own locking
+  internally
+- all RDBMS backends now have indexes on several columns
+- support confirming registration by replying to the email (sf bug 763668)
+- all HTML templating methods now automatically check for permissions
+  (either view or edit as appropriate), greatly simplifying templates
+
+Other new features:
+- simple support for collision detection (sf rfe 648763)
+- support setgid and running on port < 1024 (sf patch 777528)
+- using Zope3's test runner now, allowing GC checks, nicer controls and
+  coverage analysis
+- change nosymessage and send_message to accept msgid=None (RFE #707235)
+- handle Resent-From: headers (sf bug 841151)
+- always sort MultilinkHTMLProperty in the correct order, usually
+  alphabetically (sf feature 790512)
+- added script for copying user(s) ("scripts/copy-user.py") from tracker
+  to tracker (sf patch 828963)
+- ignore incoming email with "Precedence: bulk" (sf patch 843489)
+- use HTTP 'Content-Length' header (modified sf patch 844577)
+- HTML generated is now HTML4 (or optionally XHTML) compliant (sf feature
+  814314 and sf patch 834620)
+- default stylesheet turns off sidebar when printing
+- allow direct supply of filter() arguments in templating (thanks Godefroid
+  Chapelle)
+- improved body_title slot in HTML templating (sf patch 873502)
+- HTMLLinkProperty field() method renders as a field now (thanks darryl)
+- cgi Action handlers may now return the actual content to be sent back to
+  the user (rather than using some template)
+- date.Date now handles fractional seconds
+
+Fixed:
+- mysql documentation fixed to note requirement of 4.0+ and InnoDB
+- added testing of schema mutation, fixed rdbms backends handling of a
+  couple of cases
+- HTML 4.01 validation on the 'classic' backend
+- messages to the mailgw can be about classes other than issues now.
+- signature matching is more precise (sf bug 827775).
+- anonymous user can no longer edit or view itself (sf bug 828901).
+- corrected typo in installation.html (sf bug 822967).
+- clarified listTemplates docstring.
+- print a nicer error message when the address is already in use 
+  (sf bug 798659).
+- remove empty lines before sending strings off to the csv parser 
+  (sf bug 821364).
+- centralised conversion of user-input data to hyperdb values (sf bug
+  802405, sf bug 817217, sf rfe 816994)
+- recalculate SHA on template files when installed tracker used as
+  template (sf bug 827510)
+- fixed ZRoundup (sf bug 624380)
+- the mail gateway now searches recursively for the text/plain and the
+  attachments of a message (sf bug 841241).
+- fixed display of feedback messages in some situations (sf bug 739545)
+- fixed ability to edit "content" property (sf bug 914062)
+
+Cleanup:
+- replace curuserid attribute on Database with the extended getuid() method
+- extract a new 'mailer' module for sending mail
+- extract a '_send_mail' method for testing mail sending
+- simplify backend importing
+- use roundup_server in demo.py
+- implement newItemAction using editItemAction
+- use FormError in client.py, moving the handling up to inner_main()
+- implemented semantic comparison of Message objects in test_mailgw
+- tidied up forms in default stylesheet
+- force textareas to use monospace fonts, lessening surprise on the user
+- moved out parts of client.py to new modules:
+  * actions.py - the xxxAction and xxxPermission functions refactored into 
+    Action classes
+  * exceptions.py - all exceptions
+  * form_parser.py - parsePropsFromForm & extractFormList in a FormParser
+    class
+
+
+2004-05-17 0.6.10
+Fixed:
+- mysql backend wasn't locking tracker
+- ensure static files may only be served out of the tracker's "static
+  files" directory
+
+
+2004-04-18 0.6.9
+Fixed:
+- paging in classhelp popup was broken
+- socket timeout error logging can fail
+- hyperlink designators in message display (sf bug 931828)
+- don't match retired items in RDBMS stringFind
+
+
+2004-04-01 0.6.8
+Fixed:
+- existing trackers (ie. live ones) may be used as templates for new
+  trackers - the TEMPLATE-INFO.txt name entry has the tracker's dir name
+  appended (so the demo tracker's template name is "classic-demo")
+- handle bad multilink input at item creation time better (sf bug 917834)
+- make sure email signature starts on a newline (sf bug 919759)
+- add line to rego email to help URL detection (sf bug 906247)
+- look harder for text/plain in email
+- fixed fallback excel writer in rcsv so it has a delimiter
+- fixed setup.py's use of listTemplates (!)
+- make rdbms serialise() less trusting
+- handle Boolean values in history HTML display
+
+
+2004-03-01 0.6.7
+Fixed:
+- be more backward-compatible when asking for EMAIL_CHARSET
+- made error on create consistent with edit when user enters invalid data
+  for Multilink and Link form fields (sf bug 904072)
+- made errors from bad input in the quick "Show issue:" form more
+  user-friendly (sf bug 904064)
+- don't add a query to a user's list if it's already there
+- nicer invalid property error in HTML templating
+- use EMAIL_CHARSET for message body too (still sf bug 900046)
+
+
+2004-02-25 0.6.6
+Fixed:
+- don't insert spaces into designators, it just confuses users (sf bug
+  898087)
+- Eudora can't handle utf-8 headers. We love Eudora. (sf bug 900046)
+- fixed bug in args to new DateHTMLProperty in the local() method (sf bug
+  901444)
+- fixed registration (sf bug 903283)
+- also changed rego to not use a 302 during confirmation, as this seems to
+  confuse some email clients or browsers.
+
+
+2004-02-16 0.6.5
+Fixed:
+- mailgw handling of subject-line errors
+- allow serving of FileClass file content when the class isn't called
+  "file" (eg. messages and other FileClasses)
+- allowed negative ids (ie. new item markers) in HTMLClass.getItem,
+  allowing "db/file_with_status/-1/status/menu" to generate a useful
+  widget
+- fixed content-type when templates are serving up xml (thanks Godefroid
+  Chapelle)
+- fixed IE double-submit when it shouldn't (sf bug 842254)
+- fixed check for JS pop()/push() to make more general (sf bug 877504)
+- fix re-enabling queries (sf bug 861940)
+- use supplied content-type on file uploads before trying filename)
+- fixed roundup-reminder script to use default schema (thanks Klamer Schutte)
+- fixed edit action / parsePropsFromForm to handle index-page edits better
+- safer logging from HTTP server (sf bug 896917)
+
+
+2003-12-17 0.6.4
+Fixed:
+- fixed date arithmetic to not allow day-of-month == 0 (sf bug 853306)
+- fixed date arithmetic to limit hours-per-day to 24, not 60
+- hard-coded python2.3-ism (socket.timeout) fixed
+- fixed activity displaying as future because of Date arithmetic fix in 0.6.3
+  (sf bug 842027).
+- fix Windows service mode for roundup-server (sf bug 819890)
+- fixed #white in cgitb (thanks Henrik Levkowetz)
+
+
+2003-11-14 0.6.3
+Fixed:
+- fixed detectors fix incorrectly fixed in bugfix release 0.6.2
+- added note to upgrading doc for detectors fix in 0.6.2
+- added script to help migrating queries from pre-0.6 trackers
+- fixed "documentation" of getnodeids in roundup.hyperdb
+- added flush() to DevNull (sf bug 835365)
+- fixed javascript for help window for only one checkbox case
+- date arithmetic was utterly broken, and has been for a long time.
+  Date +/- Interval now works, and Date - Date also works (produces
+  an Interval.
+- handle socket timeout exception (thanks Marcus Priesch)
+- fixed retirement of items in rdbms imports (sf bug 841355)
+- fixed bug in looking up journal of newly-created items in *dbm backends
+
+
+2003-09-29 0.6.2
+Fixed:
+- cleaned up, clarified internal caching API in *dbm backends
+- stopped pyc writing to current directory! yay! (patch 800718 with changes)
+- fixed file leak in detector initialisation (patch 800715)
+- commented out example tracker homes (patch 800720)
+- added note about hidden :template var in user.item (bug 799842)
+- fixed Apply Error that was raised, when property was deleted from class and
+  we are trying to edit an instance
+
+
+2003-08-31 0.6.1
+Fixed:
+- Add note about installing cgi-bin with a different interpreter
+- Importing wasn't setting None values explicitly when it should have been
+- Fixed import warning regarding 0xffff0000 literal, finally, really this
+  time. Checked on win2k. (sf bug 786711)
+- fix CGI editCSV action to handle metakit's integer itemids
+- apply fix for "remove" links from Klamer Schutte
+- added permission check on "remove" link while I was there..
+- applied CSV fix for python2.3 (sf bug 790363)
+- fixed form padding in LHS menu (sf bug 790502)
+- fixed upgrading docs for timezones (sf bug 790498)
+- set the content type on page templates (can have XML templates now)
+- various cosmetic fixes (thanks James Kew for being persistent :)
+- applied patch 739314 (sorry John!)
+
+
+2003-08-08 0.6.0
+- Fixed editing attributes on FileClass nodes.
+- Query editing now works correctly (sf bug 621248)
+- roundup-server now logs IP addresses by default (sf bug 778795)
+- logfile must be specified if pidfile is (sf bug 772820)
+- timelog editing via csv interface crashes (sf bug 699837)
+- sort multilinks a little better for grouping (sf bug 772935)
+- batch the (list) listings at 500 entries per page (sf bug 759906)
+- don't have RDBMS backends list retired nodes (sf bug 767319)
+- fix file downloading
+- add action attribute to issue.item form tag
+
+
+2003-07-29 0.6.0b4
+- plugged cross-site-scripting hole (thanks Jeff Epler)
+- handle deprecation of FCNTL in python2.2+ (sf bug 756756)
+- handle missing Subject: line (sf bug 755331)
+- fix New User creation (sf bug 754510)
+- fix hackish message escaping (sf bug 757128)
+- fix :required ordering problem (sf bug 740214)
+- audit some user properties for valid values (roles, address) (sf bugs
+  742968 and 739653)
+- fix HTML file detection (hence history xref linking) (sf bug 741478)
+- session database caches it's type, rather than calling whichdb each time 
+  around.
+- changed rdbms_common to fix sql backends for new Boolean types under Py2.3
+
+
+2003-06-10 0.6.0b3
+Fixed:
+- cgi client was broken during b2 fixing
+
+
+2003-06-09 0.6.0b2
+Feature:
+- added the start/stop/restart/condstart/status roundup-server control
+  script
+
+Fixed:
+- handle non-existant demo dir (thanks Ollie Rutherfurd)
+- strip whitespace from Role names so "User, Admin" will work
+- fixed template searching on Windows (thanks J Vickroy)
+
+
+2003-05-09 0.6.0b1
+Removed:
+- having served its purpose as a template for other relational database
+  implementations, the gadfly backend has now been removed from the Roundup
+  distribution.
+
+Feature:
+- new instant-gratification Demo Mode
+- support setting of properties on message and file through web and
+  email interface (thanks John Rouillard)
+- allow additional control over the roundupdb email sending (explicit
+  cc addresses, different from address and different nosy list property)
+  (thanks John Rouillard)
+- applied patch for nicer history display (sf feature 638280)
+- cleaning old unused sessions only once per hour, not on every cgi 
+  request. It is greatly improves web interface performance, especially
+  on trackers under high load
+- added mysql backend (see doc/mysql.txt for details)
+- switch metakit to use "compressed" multilink journal change representation
+- metakit now handles "unset" for most types (not Number and Boolean)
+- fixed bug in metakit search-by-ID
+- added ability to display localized dates in web interface. User input is
+  convered to GMT (see doc/upgrading.txt).
+- added a form to show a specific issue
+- more proper sorting/grouping on mulitilink properties. Sorting is performed
+  not only by number of links, but also by links itself. This makes usable
+  grouping e.g. by topic multilink
+- add "ago" to intervals in the past (sf bug 679232)
+- included UN*X manual pages from Bastian Kleineidam
+- implemented extension to form parsing to allow editing of multiple items
+  and creation of multiple items (but only one per class)
+- the colon ":" special form variable designator may now be any of : + @
+- trackers' templates directory can contain subdirectories with static files
+  (e.g. images). They are accessible naturally: _file/images/img.gif
+- altered Class.create() and FileClass.create() methods to make "content"
+  property available in auditors
+- can now configure CC to author only for messages creating issues (sf
+  feature 625808)
+- registration is now a two-step process, with confirmation from the email
+  address supplied in the registration form
+- added password reset feature for forgotten password / login
+- added support for last-modified and if-modified-since headers for static
+  file serving
+- added Node.get() method
+- nicer page titles (sf feature 65197)
+- relaxed CVS importing (sf feature 693277)
+- added support for searching on ranges of dates and intervals (see
+  doc/user_guide.txt in chapter "Searching Page" for details) (closes sf
+  feature 700178)
+- role names made case insensitive
+- added ability to restore retired nodes
+- more lenient date input and addition Interval input support (sf bug 677764)
+- roundup mailgw now handles apop
+- implemented ability to search for multilink properties with no value
+- Class.find() may now find unset Links (sf bug 700620)
+- more flexibility in classhelp link labelling (sf feature 608204)
+- added command-line functionality for roundup-admin (sf feature 687664)
+- added nicer popup windows for topic, nosy, etc (has add/remove buttons)
+  thanks Gus Gollings
+- HTML templating files now have a .html extension
+- Roundup templates are now distributed much more sanely, allowing for
+  3rd-party templates.
+- extended date syntax to make range searches even more useful
+- SMTP login and TLS support added (sf bug 710853 with extras ;)
+  Note: requires python 2.2+
+- added Windows Service mode for roundup-server when daemonification is
+  attempted on Windows.
+- sort HTMLClass.properties results by name (sf feature 724738)
+- nicer index navigation (sf feature 676866)
+
+Fixed:
+- applied unicode patch. All data is stored in utf-8. Incoming messages
+  converted from any encoding to utf-8, outgoing messages are encoded 
+  according to rfc2822 (sf bug 568873)
+- fixed layout issues with forms in sidebar
+- fixed timelog example so it handles new issues (sf bug 678908)
+- handle missing os.fork() (sf bug 681046)
+- added warning filter for "FutureWarning: hex/oct constants > sys.maxint will
+  return positive values..." (literal 0xffff0000 in portalocker.py)
+- fixed ZPT code generating SyntaxWarning for assignment to None
+- open static files using binary mode (sf bug 693208)
+- fixed deja-vu bug 692910
+- don't display "Editing" on read-only pages (sf bug 651967)
+- re-worked detectors initialisation - woohoo, no more cross-importing!
+- fixed export/import of retired nodes (sf bug 685273)
+- remember the display template specified during edit (sf bug 701815)
+- added example HTML tempating for vacation flag (sf bug 701722)
+- finally, tables autosize columns (sf bug 609070)
+- added creation to index columns (sf bug 708247)
+- fixed missing (pre-commit) journal entries in *dbm backends (sf bug 679217)
+- URL cited in roundup email confusing dumb Email clients (sf bug 716585)
+- set title on issues even when the email body is empty (sf bug 727430)
+- under the heading of "questionable whether it's a fix or not"
+  (sf "bug" 621226 for the users of the "standards compliant" browser IE)
+
+
+2003-05-08 0.5.7
+- fixed Interval maths (sf bug 665357)
+- fixed sqlite rollback/caching bug (sf bug 689383)
+- fixed rdbms table update detection logic (sf bug 703297)
+- fixed detection of bad date specs (sf bug 691439)
+- required String properties not being flagged (thanks Ajit George)
+- only look for CSV files when importing (thanks Dan Grassi)
+- can now unset values in CSV editing (sf bug 704788)
+- fixed rdbms email address lookup (case insensitivity)
+- email file attachments added to issue files list (sf bug 711501)
+- added socket timeout to attempt to prevent stuck processes (sf bug 665487)
+- email registered users shouldn't be able to log in (sf bug 714673)
+- handle missing addresses on users (sf bug 724537)
+
+
+2003-02-27 0.5.6
+- fixed templating filter function arguments (sf bug 678911)
+- fixed multiselect in searching (sf bug 676874)
+- fixed parsing of content-disposition filenames (sf bug 675116)
+- added 'h' to roundup-server optarg list (sf bug 674070)
+- fixed doc for db.history in anydbm and rdbms_common (sf bug 679221)
+- fixed roundup-reminder (sf bug 681042)
+- fixed int assumptions about Number values (sf bug 677762)
+- clarified licensing
+- another attempt to fix cookie misbehaviour - customise cookie name using
+  tracker name
+- fixed error in indexargs_url (thanks Patrick Ohly)
+- fixed getnode (sf bug 684531)
+- fixed args to some date templating methods (sf bug 689670)
+- fixed database corruption in rdbms property mutation
+
+
+2003-01-24 0.5.5
+- fixed rdbms searching by ID (sf bug 666615)
+- fixed metakit searching by ID
+- detect corrupted index and raise semi-useful exception (sf bug 666767)
+- open server logfile unbuffered
+- revert StringHTMLProperty to not hyperlink text by default
+- fixes to CGI form handling
+- fix unlink bug in metakit backend
+- fixed hyperlinking ambiguity (sf bug 669777)
+- fixed cookie path to use TRACKER_WEB (sf bug 667020) (thanks Nathaniel Smith
+  for helping chase it down and Luke Opperman for confirming fix)
+
+
+2003-01-10 0.5.4
+- key the templates cache off full path, not filename
+- implemented whole-database locking
+- hyperlinking of special text (url, email, item designator) in messages
+- fixed time default in date.py
+- fixed error in cgi/templates.py (sf bug 652089)
+- fixed handling of missing password (sf bug 655632)
+- applied patches for handling Outlook quirks (thanks Andrey Lebedev)
+  (multipart/alternative, "fw" and content-type "name")
+- fire auditors and reactors in rdbms retire (thanks Sheila King)
+- better match for mailgw help "command" text
+- handle :add: better in cgi form parsing (sf bug 663235)
+- handle all-whitespace multilink values in forms (sf bug 663855)
+- fixed searching on date / interval fields (sf bug 658157)
+- fixed form elements names in search form to allow grouping and sorting 
+  on "creation" field
+- display of saved queries is now performed correctly
+
+
+2002-12-11 0.5.3
+- added mention of how to give users multiple Roles
+- mention needed trailing "/" in TRACKER_WEB
+- fixed upgrading doc to have CGI changes in the correct order
+- fixed double-close of anydbm backend (sf bug 639030)
+- removed use of string/strop from TAL/TALInterpreter
+- handle KeyboardInterrupt nicely
+- fixed Date and Interval form value handling
+- fixed Date.local()
+- email quoted text stripping is controllable again (sf bug 650742)
+- extract attachment name from content-disposition if name is missing (sf
+  bug 637278)
+- removed FILTER_POSITION from bundled configs
+- reverse message listing in issue display (reversion of recent change)
+- bad entries for multilink editing in cgi don't traceback now (sf bug 640310)
+- detect and break email loops (sf bug 640854)
+- finished of handling of retired flag in filter() (sf bug 635260)
+- allow StringHTMLProperty in MultilinkHTMLProperty test to work
+- don't set explicit None Link properties in web create
+- fixed nasty sorting bug that was lowercasing properties
+- allow multiple :remove and :add elements per property being edited
+- added date header to emails (sf bug 651358)
+
+
+2002-11-07 0.5.2
+- added quotes around python interpreter in windows bat (sf bug 623963)
+- fixed link at end of installation doc (sf bug 623957)
+- handle "classname" URL path errors cleaner (generate a 404)
+- added CGI :remove:<propname> and :add:<propname> which specify item ids to
+  remove / add in <propname> multilink.
+- bugfix in boolean templating
+- remember the change note on bad submissions (sf bug 625989)
+- highlight required form fields (sf bug 625989)
+- force non-word boundary to match re: in subject (sf bug 626303)
+- handle sqlite bug (<2.7.2) (sf bug 630828)
+- handle missing props in anydbm stringFind
+- updated email package address formatting (deprecation)
+- copied email address quoting from email v2.4.3 so we're consistent with 2.2
+- email summary extraction now takes the first whole sentence or line -
+  whichever is longer
+- documented dependency on Active State (sf bug 623959)
+- ensured there's no zero-length files in source (sf bug 633622)
+- added ID to the search page (sf bug 631601)
+- fixed filtering by id in anydbm
+- show issue ID in the headings (sf bug 631598)
+- show entire messages by default in issues (sf bug 625995)
+- fixed journalling to save old values instead of new (sorry it took so long GM)
+- handle missing REQUEST_URI for cgi-bin users (sf bug 620163)
+
+
+2002-10-16 0.5.1
+- highlight rows in groups of three
+- metakit cleanups
+- nicer "navigation" style in index views
+- handle missing Link values in anydbm backend set() operation
+- fixed filter() with no sort/group (sf bug 618614)
+- fixed register with no session (sf bug 618611)
+- fixed log / pid file path handling in roundup-server (sf bug 617981)
+- fixed old gadfly compatibiltiy problem, for sure this time (sf bug 612873)
+- https URLs from config now recognised as valid (sf bug 619829)
+- nicer display of tracker list in roundup-server (sf bug 619769)
+- fixed some missed renaming instance -> tracker (sf bug 619769)
+- allow blank passwords again (sf bug 619714)
+- expose the tracker config as a variable for templating
+- homogenise newlines in CGI text submissions (sf bug 614072)
+- merged Zope Collector #372 fix from ZPT CVS trunk
+- fixed history to display username instead of userid
+- shipped templates didn't import all hyperdb types in dbinit.py
+- fixed bug in Interval serialisation
+- handle "unset" status in status auditor (sf bug 621250)
+- issues in 'done-cbb' are now also moved to 'chatting' on new messages
+- implemented the missing Interval.__add__
+- added ability to implement new templating utility methods
+- expose the Date.pretty method to templating
+- made form table cell alignment consistent (sf bug 621887)
+- include stylesheet in docs (sf bug 623183)
+- store PIPE messages so we can re-send them on errors (sf bug 623082)
+- implemented "retire" cgi action, added to user index (sf bug 618612)
+- included doc ideas from Bernhard Reiter (sf feature 621941)
+
+
+2002-10-02 0.5.0
+- fixed style for alternating rows in user lists
+- fixed query edit form so it doesn't barf
+- #617133 ] 0.5.0pr1 uses nonexistent renderTemplate
+- merged Zope Collector #539 fix from ZPT CVS trunk
+
+
+2002-09-27 0.5.0 pr1
+- handling of None for Date/Interval/Password values in export/import
+- handling of journal values in export/import
+- password edit now has a confirmation field
+- registration error punts back to register page
+- gadfly backend now handles changes to the schema - but only one property
+  at a time
+- cgi.client base URL is now obtained from the config TRACKER_WEB
+- request.url has gone away - there's too much magic in trying to figure
+  what it should be
+- cgi-bin script redirects to https now if the request was https
+- FileClass "content" property wasn't being returned by getprops() in most
+  backends
+- we now verify instance attributes on instance open and throw a useful error
+  if they're not all there
+- sf 611217 ] menu() has problems when labelprop==None
+- verify contents of tracker module when the tracker is opened
+- many performance improvements in *dbm and sql backends
+- mailgw was missing an "import sys"
+- setup now installs scripts with python -O flag, doubling performance in some
+  cases (there's a lot of __debug__ use)
+- fix :required for Link menus
+- import wasn't setting the ID to maxid+1
+- added getItem to HTMLClass so you can access arbitrary items in templates
+- index filtering form values may now be key values too
+- replaced the content() callback ickiness with Page Template macro usage
+- changed the default CSS style to be less offensive to some ;)
+- better handling of Page Template compilation errors
+- handle multiple unrelated indexed classes
+- #614188 ] Exception in mailgw.py
+- #613310 ] traceback on onexistant items
+- #613291 ] typos in nosy list
+- handle stupid mailers that QUOTE their Re; 'Re: "[issue1] bla blah"'
+- giving a user a Role that doesn't exist doesn't break stuff any more
+- revamped user guide, customisation guide, added maintenance guide
+- merge Zope Collector #538 fix from ZPT CVS trunk (path expressions with a
+  non-path final alternate no longer try to call a value returned by that
+  alternate)
+- merge Zope Collector #573 fix from ZPT CVS trunk
+- merge Zope Collector #580 fix from ZPT CVS trunk
+- added "crypt" password encoding and ability to set password with
+  already encrypted password through roundup-admin
+- fixed the mailgw so that anonymous users may still access it
+- add hook to allow external password verification, overridable in the
+  tracker interfaces module
+- fixed login attempt by user that doesn't exist
+
+
+2002-09-13 0.5.0 beta2
+-  all backends now have a .close() method, and it's used everywhere
+-  fixed bug in detectors __init__
+-  switched the default issue item display to only show issue summary
+   (added instructions to doc to make it display entire content)
+-  MANIFEST.in was missing a lot of template files
+-  added generic item editing
+-  much nicer layout of template rendering errors
+-  added context/is_edit_ok and context/is_view_ok convenience methods and
+   implemented use of them in the classic template
+
+
+2002-09-11 0.5.0 beta1
+Fixed:
+-  #576086 ] dumb copying mistake (frontends/ZRoundup.py)
+-  installation instructions now mention "python2" in "testing your python".
+-  made the unit tests run again - they were quite b0rken
+-  #571170 ] gdbm deadlock
+-  #576241 ] MultiLink problems in parsePropsFromForm
+-  fixed the date module so that Date(". - 2d") works
+-  web forms may now unset Link values (like assignedto)
+-  cleanup: moved roundup.templatebuilder to roundup.templates.builder
+-  instance __init__ no longer silently traps dbinit import errors
+
+Feature:
+-  new backend for metakit (thanks Gordon McMillan)
+-  new backend for gadfly (it's as done as it's going to get)
+-  further split the dbm backends from the core code, allowing easier
+   non-dict-like backends (eg metakit, RDB)
+-  implemented and used the new access control mechanisms (Permissions, Roles)
+   (see doc/security.txt)
+-  switched templating to use Zope's PageTemplates (yay!)
+-  switched to sessions for web authentication
+-  added Boolean and Number types
+-  fixed the journal bloat
+-  updated design document for new access controls
+-  updated customisation document, including more examples
+-  entire database export and import (incl files)
+-  better mailgw help message (feature request #558562)
+-  re-enabled link backrefs from messages (feature request #568714)
+-  the page layout is now templatable
+-  re-worked cgi interface to abstract out the explicit "issue" interface
+-  have index page handle mid-page errors better so header and footer are
+   still visible
+-  we handle "not found", access and item page render errors better
+-  fixed double-submit by having new-item-submit redirect at end
+-  daemonify roundup-server (fork, logfile, pidfile)
+-  modify cgitb to display PageTemplate errors better
+-  rename to "instance" to "tracker"
+-  have roundup.cgi pick up tracker config from the environment 
+-  revamped look and feel in web interface
+-  cleaned up stylesheet usage
+-  several bug fixes and documentation fixes
+-  added is_retired test to hyperdb.Class
+-  added capability to save queries:
+   - a query Class with name, klass (to search) and url (query string)
+     properties
+   - a Multilink to query on user called queries
+   - html templates for query, and a list of queries in user.item
+   - search form has Save button & name input
+   - saved queries put in menu in pagehead
+   - for migration, none of the above is required and old behavior preserved.
+   - showquery translates search form <-> query string
+-  cleaned up the indexer code:
+   - it splits more words out
+   - removed code we'll never use (roundup.roundup_indexer has the full
+     implementation, and replaces roundup.indexer)
+   - only index text/plain and rfc822/message (ideas for other text formats to
+     index are welcome)
+   - added simple unit test for indexer. Needs more tests for regression.
+   - all String properties may now be indexed too. Currently there's a bit of
+     "issue" specific code in the actual searching which needs to be
+     addressed. In a nutshell:
+     + pass 'indexme="yes"' as a String() property initialisation arg, eg:
+           file = FileClass(db, "file", name=String(), type=String(),
+               comment=String(indexme="yes"))
+     + the comment will then be indexed and be searchable, with the results
+       related back to the issue that the file is linked to
+   - as a result of this work, the FileClass has a default MIME type that may
+     be overridden in a subclass, or by the use of a "type" property as is
+     done in the default templates.
+   - the regeneration of the indexes (if necessary) is done once the schema is
+     set up in the dbinit.
+   - new "reindex" command in roundup-admin used to force regeneration of the 
+     index
+-  added email display function - mangles email addrs so they're not so easily
+   scraped from the web
+-  switched to using a session-based web login
+-  made mailgw handle set and modify operations on multilinks (bug #579094)
+-  fixed the journal bloat from multilink changes - we just log the add or
+   remove operations, not the whole list
+
+
+2002-06-24 0.4.2
+Fixed:
+-  Cleaned up the hyperdb unit tests.
+-  Applied patch from Andrew W. Nosenko to give nicer Unauthorised message
+   when anonymous user tries to edit. Should've been applied in 0.4.2pr1. Oops.
+-  Added more detailed note to MIGRATION regarding the detectors changes.
+
+
+2002-06-19 0.4.2pr1
+Feature:
+-  added a "detectors" directory for people to put their useful auditors and
+   reactors in. Note - the roundupdb.IssueClass.sendmessage method has been
+   split and renamed "nosymessage" specifically for things like the nosy
+   reactor, and "send_message" which just sends the message.
+-  link() htmltemplate function now has a "showid" option for links and
+   multilinks. When true, it only displays the linked node id as the anchor
+   text. The link value is displayed as a tooltip using the title anchor
+   attribute.
+   To use in eg. the superseder field, have something like this:
+   <td>
+    <display call="field('superseder', showid=1)">
+    <display call="classhelp('issue', 'id,title', label='list', width=500)">
+    <property name="superseder">
+     <br>View: <display call="link('superseder', showid=1)">
+    </property>
+   </td>
+-  stripping of the email message body can now be controlled through the
+   config variables EMAIL_KEEP_QUOTED_TEXT and EMAIL_LEAVE_BODY_UNCHANGED.
+-  all database files created are now group readable and writable.
+-  added option to automatically add the authors and recipients of messages
+   to the nosy lists with the options ADD_AUTHOR_TO_NOSY (default 'new') and
+   ADD_RECIPIENTS_TO_NOSY (default 'new'). These settings emulate the current
+   behaviour. Setting them to 'yes' will add the author/recipients to the nosy
+   on messages that create issues and followup messages.
+-  reverting to dates for intervals > 2 months sucks
+-  changed the default message list in issues to display the message body
+-  applied patch #558876 ] cgi client customization
+-  split instance initialisation into two steps, allowing config changes
+   before the database is initialised.
+-  don't create an empty message on email issue creation if the email is empty
+-  may now display additional fields in Multilink form menus
+-  #541941 ] changing multilink properties by mail
+-  #526730 ] search for messages capability
+-  #505180 ] split MailGW.handle_Message
+   - also changed cgi client since it was duplicating the functionality
+
+Fixed:
+-  stop sending blank (whitespace-only) notes
+-  cleanup of serialisation for database storage
+-  node ids are now generated from a lockable store - no more race conditions
+-  sorting was applied to all nodes of the MultiLink class instead of
+   to the nodes that are actually linked to in the "field" template
+   function.  This adds about 20+ seconds in the display of an issue if
+   your database has a 1000 or more issues in it.
+-  added missing documentation for a few of the config option values
+-  file upload broke if you didn't supply a change note
+-  fixed SCRIPT_NAME in ZRoundup for instances not at top level of Zope
+   (thanks dman)
+-  fixed some sorting issues that were breaking some unit tests under py2.2
+-  mailgw test output dir was confusing the init test (but only on 2.2 *shrug*)
+-  node caching now works, and gives a small boost in performance
+-  #449374 ] re-enable bsddb3 backend
+   bsddb3 backend now works, reinstating
+-  #551483 ] assignedto in Client.make_index_link
+-  made backends.__init__ be more specific about which ImportErrors it really
+   wants to ignore
+-  fixed the example addresses in the templates to use correct example domains
+-  cleaned out the template stylesheets, removing a bunch of junk that really
+   wasn't necessary (font specs, styles never used) and added a style for 
+   message content
+-  build htmlbase if tests are run using CVS checkout
+-  #565979 ] code error in hyperdb.Class.find
+-  #565996 ] The "Attach a File to this Issue" fails
+-  #564271 ] find() and new properties
+-  #562130 ] cookie path generated from ZRoundup was wrong in some situations
+-  remove CR characters embedded in messages (ZRoundup)
+-  properly quote the email address and "real name" in all situations using the
+    'email' module if it is available and 'rfc822' otherwise
+-  #565992 ] if ISSUE_TRACKER_WEB doesn't have the trailing '/', add it
+-  use the rfc822 module to ensure that every (oddball) email address and
+   real-name is properly quoted
+-  #558867 ] ZRoundup redirect /instance requests to /instance/ 
+-  #569415 ] {version}
+-  #569178 ] type error
+   was fixed as part of the general cleanup of reactors
+
+
+2002-03-25 - 0.4.1
+Feature:
+-  use blobfiles in back_anydbm which is used in back_bsddb.
+   change test_db as dirlist does not work for subdirectories.
+   ATTENTION: blobfiles now creates subdirectories for files.
+-  add module blobfiles in backends with file access functions.
+-  roundup db catch only IOError in getfile.
+-  roundup db catches retrieving not existing files.
+-  #503204 ] mailgw needs a default class
+   - partially done - the setting of additional properties can wait for a
+     better configuration system.
+-  Alternate email addresses are now available for users. See the MIGRATION
+   file for info on how to activate the feature.
+-  #511168 ] Web interface: Adding new products
+   Classes that don't provide template html get a default edit interface now:
+   - access using the admin "class list" interface
+   - limited to admin-only
+   - requires the csv module from object-craft (url given if it's missing)
+-  Added popup help for classes using the classhelp html template function.
+   - add <display call="classhelp('priority', 'id,name,description')">
+     to an item page, and it generates a link to a popup window which displays
+     the id, name and description for the priority class. The description
+     field won't exist in most installations, but it will be added to the
+     default templates.
+-  #517734 ] web header customisation is obscure
+-  All messages sent to the nosy list are now encoded as
+   quoted-printable before they are sent.
+-  Fixed display of mutlilink properties when using the template
+   functions, menu and plain.
+
+Fixed:
+-  Clean up mail handling, multipart handling.
+-  respect encodings in non multipart messages.
+-  makeHtmlBase: re.sub under python 2.2 did not replace '.', string.replace
+   does it.
+-  preamble in tepmlateBuilder mentioned htmldata
+-  mailgw checks encoding on first part too.
+-  #511586 ] unittest FAIL: testReldate_date
+-  Added a uniquely Roundup header to email, "X-Roundup-Name"
+-  All forms now have "double-submit" protection when Javascript is enabled
+   on the client-side.
+-  #516883 ] mail interface + ANONYMOUS_REGISTER
+-  #516854 ] "My Issues" and redisplay
+-  #517906 ] Attribute order in "View customisation"
+-  #514854 ] History: "User" is always ticket creator
+-  wasn't handling cvs parser feeding correctly
+-  fixed some problems in date calculations (calendar.py doesn't handle over-
+   and under-flow). Also, hour/minute/second intervals may now be more than
+   99 each.
+-  #527416 ] roundup-admin uses undefined value
+-  #527503 ] unfriendly init blowup when parent dir
+   (also handles UsageError correctly now in init)
+-  #524129 ] roundup-admin gets python path wrong
+
+
+2002-01-24 - 0.4.0
+Feature:
+-  much nicer history display (actualy real handling of property types etc)
+-  journal entries for link and mutlilink properties can be switched on or 
+   off
+-  properties in change note are now sorted
+-  you can now use the roundup-admin tool pack the database
+
+Fixed:
+-  the mail gateway now responds with an error message when invalid values 
+   for arguments are specified for link or mutlilink properties
+-  modified unit test to check nosy and assignedto when specified as arguments
+-  handle attachments with no name (eg tnef)
+-  fixed setting nosy as argument in subject line
+-  fixed back_bsddb so it passed the journal tests
+-  fixed status changes in mail gateway (eg. unread -> chatting)
+-  we'll actually distribute the frontends directory now, as advertised...
+-  handle stripping of "AW:" from subject line
+-  htmltemplate list() wasn't sorting...
+-  unit tests for html templating (and re-enabled the listbox field for
+   multilinks)
+-  allow abbreviation of "help" in admin tool too.
+-  run_tests testReldate_date failed if LANG is 'german'
+-  mailgw failures (unexpected ones) are forwarded to the roundup admin
+
+
+2002-01-16 - 0.4.0b2
+Fixed:
+-  #495392 ] empty nosy -patch
+-  #500574 ] messageid must have format <part1 at part2>
+-  fixed some problems with web editing and change detection
+-  mail splitting wasn't detecting responses in the same "section" as quoted
+   text
+-  missed a "from i18n import _" in date.py
+-  #501690 ] MIGRATION.txt incomplete
+-  #502342 ] pipe interface
+-  #502437 ] rogue reactor and unittest
+-  re-enabled dumbdbm when using python >2.1.1 (ie 2.1.2, 2.2)
+-  changed all config accesses so they access either the instance or the
+   config attriubute on the db. This means that all config is obtained from
+   instance_config instead of the mish-mash of classes. This will make
+   switching to a ConfigParser setup easier too, I hope.
+-  #502951 ] adding new properties to old database
+-  #502953 ] nosy-like treatment of other multilinks
+-  #503164 ] create and passwords
+-  plain rendering of links in the htmltemplate now generate a hyperlink to
+   the linked node's page.
+-  #503330 ] ANONYMOUS_REGISTER now applies to mail
+-  #503353 ] setting properties in initial email
+-  #502956 ] filtering by multilink not supported
+-  #503340 ] creating issue with [asignedto=p.ohly]
+-  #502949 ] index view for non-issues and redisplay
+-  #503793 ] changing assignedto resets nosy list
+-  lots of date/interval related changes:
+   - more relaxed date format for input
+   - handle None for date/interval properties
+
+
+2002-01-08 - 0.4.0b1
+Feature:
+-  Added INSTANCE_NAME to configuration - used in web and email to identify
+   the instance.
+-  Added EMAIL_SIGNATURE_POSITION to indicate where to place the roundup
+   signature info in e-mails.
+-  Some more flexibility in the mail gateway and more error handling.
+-  Login now takes you to the page you back to the were denied access to.
+-  Admin user now can has a user index link on their web interface.
+-  We now have basic transaction support. Information is only written to
+   the database when the commit() method is called. Only the anydbm and
+   bsddb3 backends are modified in this way - the bsddb3 backend needs a
+   lot more work anyway...
+    - the CGI and mailgw automatically commit() at the end of processing a
+      single transaction
+    - the admin tool requires an explicit "commit" - it will prompt at exit
+      if there are unsaved changes. A "rollback" removes all changes made
+      during the session (up to the last commit).
+-  Added the "display" command to the admin tool - displays a node's values
+-  Message author's name appears in From: instead of roundup instance name
+   (which still appears in the Reply-To:)
+-  Added a Zope frontend for roundup.
+-  Centralised the python version check code, bumped version to 2.1.1 (really
+   needs to be 2.1.2, but that isn't released yet :)
+-  much better attaching of erroneous messages in the mail gateway
+-  #496356 ] Use threading in messages
+   This adds the tracking of messages by message-id and allows threading
+   using in-reply-to. Most e-mail clients support threading using this
+   feature, and we hope to add support for it to the web gateway.
+
+Fixed:
+-  Lots of bugs, thanks Roché and others on the devel mailing list!
+-  login_action and newuser_action return values were being ignored
+-  Woohoo! Found that bloody re-login bug that was killing the mail
+   gateway.
+-  Fixed login/registration forwarding the user to the right page (or not,
+   on a failure)
+-  We now use weakrefs in the Classes to keep the database reference, so
+   the close() method on the database is no longer needed.
+-  #487480 ] roundup-server
+-  #487476 ] INSTALL.txt
+-  #489760 ] [issue] only subject
+-  fixed doc/index.html to include the quoting in the mail alias.
+-  fixed the backends __init__ so we can pydoc the backend modules
+-  web i/f reports "note added" if there are no changes but a note is entered
+-  we were assuming database files created by anydbm had the same name, but
+   this is not the case for dbm. We now perform a much better check _and_
+   cope with the anydbm implementation module changing too!
+-  envelope-from is now set to the roundup-admin and not roundup itself so
+   delivery reports aren't sent to roundup (thanks Patrick Ohly)
+-  #495400 ] entering blanks
+   Values with spaces are now accepted in roundup-admin - check the long help
+   for details.
+-  #496360 ] table width does not work
+-  detectors were being registered multiple times
+-  added tests for mailgw
+
+
+2001-11-23 - 0.3.0 
+Feature:
+-  #467129 ] Lossage when username=e-mail-address
+-  #473123 ] Change message generation for author
+-  MailGW now moves 'resolved' to 'chatting' on receiving e-mail for an issue.
+-  Added Structured Text rendering to htmltemplate, thanks Brad Clements.
+-  Added CGI configuration via env vars (see roundup.cgi for details)
+-  "roundup.cgi" is now installed to "<python-prefix>/share/roundup/cgi-bin"
+-  roundup-admin now accepts abbreviated commands (eg. l = li = lis = list)
+-  roundup-mailgw now supports unix mailbox and POP as sources of mail.
+-  roundup-admin now handles all hyperdb exceptions
+-  users may attach files to issues (and support in ext) through the web now
+-  incorporated patch from Roch'e Compaan implementing attachments in nosy
+   e-mail
+-  added a target version field to the extended issue schema
+-  added dummy hooks for I18N and some preliminary (test) markup of
+   translatable messages
+
+Fixed:
+-  Fixed a bug in HTMLTemplate changes.
+-  'unread' to 'chatting' automagic status change was b0rken.
+-  Anonymous user lockout wasn't working.
+-  roundup-server now works on Windows, thanks Juergen Hermann.
+-  Fixed install documentation, also thanks Juergen Hermann.
+-  Fixed some URL issues in roundup.cgi, again thanks Juergen Hermann.
+-  bug #475347 ] WindowsError still not caught (patch from Juergen Hermann)
+-  bug #474749 ] indentations lost
+-  bug #477104 ] HTML tag error in roundup-server
+-  bug #477107 ] HTTP header problem
+-  bug #477687 ] conforming html
+-  bug #474372 ] Netscape 4.77 do not render Support form
+-  bug #477685 ] base64.decodestring breaks
+-  bug #477837 ] lynx does not like the cookie
+-  bug #477892 ] Password edit doesn't fix login cookie
+-  newuser_action now presents error messages rather than tracebacks.
+-  bug #479511 ] mailgw to pop
+-  bug #479508 ] roundup-admin crash on wrong class
+-  bad error report in hyperdb
+-  roundup.mailgw now handles errors on the set() and create() at the end
+   of processing
+-  roundup.mailgw also handles messages that are passed to it that don't
+   contain a From: line - apparently some POP servers can do this. It punts
+   an error message to the roundup admin.
+-  fixed nosy reaction and author copy handling
+-  errors in nosy reaction will be propogated now (were effectively being
+   squashed)
+-  re-open the database as the author in mail handling
+-  missing "return" in filter_section (thanks Roch'e Compaan)
+
+
+2001-10-23 - 0.3.0 pre 3
+Feature:
+-  MailGW now moves 'unread' to 'chatting' on receiving e-mail for an issue.
+-  feature #473127: Filenames. I modified the file.index and htmltemplate
+   source so that the filename is used in the link and the creation
+   information is displayed.
+ Admin Tool (roundup-admin):
+ -  Interactive mode for running multiple (independant at present) commands.
+ -  Tabular display of nodes.
+ -  Import and export via colon-separated files.
+
+Changed:
+-  re-organised the html templating code. Fixed some bugs, probably
+   introduced some more.  Hopefully not too many.
+
+Fixed:
+-  Stand-alone server now has a configurable setuid user.
+-  CGI interface wasn't handling checkboxes at all.
+-  Fixed quopri usage in mailgw from bug reports on mailing list.
+-  Remove the "freshen" command from the roundup-admin tool.
+-  Catch errors in login - no username or password supplied.
+-  Fixed editing of password (Password property type) thanks Roch'e Compaan.
+-  Fixed grouping of non-str properties thanks Roch'e Compaan.
+-  bug #473121: The customisation view and filters (CGI interface view
+   customisation section may now be hidden (patch from Roch'e Compaan.)
+-  bug #473122: Issue id sorting (hyperdb sorts strings-that-look-like-numbers
+   as numbers now.
+-  bug #473124: UI inconsistency with Link fields.
+   This also prompted me to fix a fairly long-standing usability issue -
+   that of being able to turn off certain filters.
+-  bug #473125: Paragraph in e-mails
+-  bug #473126: Sender unknown
+-  bug #473130: Nosy list not set correctly
+
+
+2001-10-11 - 0.3.0 pre 2
+Fixed:
+-  Hyperdatabase was inserting empty strings instead of None for missing
+   property values. This broke a lot of things.
+
+
+2001-10-10 - 0.3.0 pre 1
+Feature:
+-  roundup-admin create now prompts for property info if none is supplied
+   on the command-line.
+-  hyperdb Class getprops() method may now return only the mutable
+   properties.
+-  CGI interfaces now generate a top-level index of their known instances.
+
+Changed:
+-  Login now uses cookies, which makes it a whole lot more flexible. We can
+   now support anonymous user access (read-only, unless there's an
+   "anonymous" user, in which case write access is permitted). Login
+   handling has been moved into cgi_client.Client.main()
+-  The "extended" schema is now the default in roundup init.
+-  The schemas have had their page headings modified to cope with the new
+   login handling. Existing installations should copy the interfaces.py
+   file from the roundup lib directory to their instance home.
+-  Passwords are now encoded by default (except exising databases which
+   will only be encoded when the passwords are changed). The scheme used
+   at the moment is SHA - but the code is flexible enough to take any
+   number of encoding systems.
+-  The roundup-admin tool always operates as the "admin" user now. Database
+   protection should be achieved using file system protections (see the
+   documentation for details.)
+
+Fixed:
+-  Incorrectly had a Bizar Software copyright on the cgitb.py module from
+   Ping - has been removed.
+-  Pretty time interval wasn't handling > 1 month properly.
+-  Generation of links to Link/Multilink in indexes. (thanks Hubert Hoegl)
+-  AssignedTo wasn't in the "classic" schema's item page.
+-  Fixed a whole bunch of places in the CGI interface where we should have
+   been returning Not Found instead of throwing an exception.
+-  Fixed a deviation from the spec: trying to modify the 'id' property of
+   an item now throws an exception.
+-  The plain() template function now html-escapes the content.
+-  Change message was stuffing up for multilinks with no key property.
+
+
+
+--------------
+
+2001-08-30 - 0.2.8
+Fixed:
+-  Wasn't handling unguessable mime types for file uploads.
+-  Missing import in mailgw.
+
+
+2001-08-29 - 0.2.7
+Feature:
+-  Text searches are now case insensitive. All forms of text search use
+   regular expressions now.
+
+Fixed:
+-  Had another 2.1-ism in the unit tests
+-  Made the mail parser a little more robust w.r.t missing Subject:
+   (both thanks Mikhail Sobolev)
+-  Missed some isFooType usages (thanks Mikhail Sobolev for spotting them)
+-  Reverted back to sending change messages to the web editor of a node so
+   that the change note message is actually genrated.
+-  CGI interface wasn't generating correct change messages.
+-  Notes entered during a change are saved to the messages list even if
+   there's no nosy list. No message is generated if there's no nosy list and
+   there's no change note (since it would just duplicates the journal).
+-  Completely removed the bsddb3 module from the tests - will be reinstated
+   when the http://bsddb.sourceforge.net/'s bugs #439959 and #456408 are
+   dealt with. One is fixed in CVS, the other pending.
+
+
+2001-08-08 - 0.2.6
+Note:
+-  Roundup is now released under the same terms as the Python License.
+
+Feature:
+-  Added tests for instance initialisation. No more releasing the software
+   with bugs in roundup.init!
+-  Now bundling unittest with the package so that python 2.0 users can use
+   the tests.
+-  Much better error handling and messages generated by the mail gateway.
+
+Fixed:
+-  Implemented correct mail splitting. Added unit tests. Also snips
+   signatures now too.
+-  Bug #447671 - typo in roundup/init.py
+-  Changed date.Date to use regular string formatting instead of strftime -
+   win32 seems to have problems with %T and no hour... or something...
+-  Bug #448484 - now catching correct exception from makedirs.
+-  Instances are now opened by a special function that generates a unique
+   module name for the instances on import time.
+
+
+2001-08-03 - 0.2.5
+Note:
+-  The bsddb3 module has a bug that renders it non-functional. Users should
+   select the anydbm or bsddb backend instead.
+
+Fixed:
+-  Python 2.0 does not contain the unittest module. The setup.py module now
+   checks for unittest before attempting to run the unit tests.
+
+
+2001-08-03 - 0.2.4
+Features:
+-  Added ability for cgi newblah forms to indicate that the new node
+   should be linked somewhere.
+-  Added time logging and file uploading to the templates.
+-  Added "My Issues" and "My Support" to extended template. Changed "Your
+   Details" to "My Details". Changed the "New Foo" links to "Add Foo".
+   Added links for unassigned support and issues. Generally reorganised and
+   cleanup the header up.
+-  Changed the order of the information in the message generated by web edits.
+-  Extended the range of intervals that are pretty-printed before actual dates
+   are displayed.
+-  Added more BUILD instructions including the "clean" command to force
+   rebuild.
+-  Web edit messages aren't sent to the person who did the edit any more. No
+   message is generated if they are the only person on the nosy list.
+-  Roundupdb now appends "mailing list" information to its messages which
+   include the e-mail address and web interface address. Templates may
+   override this in their db classes to include specific information (support
+   instructions, etc).
+
+Fixed:
+-  Argument handling for the roundup-admin find command.
+-  Handling of summary when no note supplied for newblah. Again.
+-  Detection of no form in htmltemplate Field display.
+-  Checklist html template command was setting wrong name.
+-  2.1-specific gmtime() (no arg) call in roundup.date. (thanks Paul Wright)
+-  mailgw was making naughty assumptions about the schema of the classes it
+   was creating nodes for.
+-  remove the $Foo$ from the HTML files stored in the htmlbase modules.
+-  Instance import now imports the instance using imp.load_module so that
+   we can have instance homes of "roundup" or other existing python package
+   names.
+
+
+2001-07-30 - 0.2.3
+Big change:
+-  I've split off the support class from the issue class in "extended".
+   Anyone who has any support entries, sorry. It should be possible to
+   write a scipt that moves the entries over pretty easily. If this causes
+   you pain, I'll do so. You'll want to update your instance with the new
+   code in "extended" either way.
+
+Features:
+-  Added the unit tests to the start of setup.py so they're run whenever
+   we do anything distutils'y.
+-  Added nicer prompting to the roundup-admin "init" command.
+-  Actually, the roundup-admin code is totally revamped, and has command
+   help and better command-line arg handling.
+-  The cgi_client.Client base class now reflects the structure of "classic"
+   rather than "extended" since "classic" is more of a "base" template.
+-  Added more DB to test. Skips tests where imports fail.
+
+Fixed:
+-  One of the tests in test_date had the wrong expected result.
+-  Fixed IssueClass so that superseders links to its classname rather than
+   hard-coded to "issue".
+-  templatebuilder was catching IOError instead of OSError.
+-  The cgi_client newblah method wasn't detecting the __note form field
+   properly.
+-  The History command in htmltemplate didn't handle a new node (None
+   nodeid) properly.
+
+
+2001-07-29 - 0.2.2
+Features:
+-  Added implementation.txt to the doc directory. Contains implementation
+   notes specific to this implementations of Roundup.
+-  Cleaned up mailgw some (subclass Message for getPart) and added some
+   tests for multipart splitting.
+-  Better checking for html dir in templatebuilder.
+-  Base hyperdb.Class now fakes the "id" property.
+-  Made the classic roundup look more like the original prototype.
+-  Made cgi_client and templating slightly more generic.
+-  Moved some code around in cgi_client allowing for subclassing to change
+   behaviour.
+-  Added the fabricated property "id" to all hyperdb classes.
+-  Cleanup of the link label generation (new method on hyperdb.Class to do
+   it).
+
+Fixed:
+-  Everything uses errno module now to check errno values.
+-  New issue form handles lack of note better now.
+-  HTML templating uses section-bar style for index group headers now.
+-  Fixed problem in link display when Link value is None.
+-  Form handling in cgi client wasn't propogating through the previous
+   query elements.
+-  Fixed sort arguments generated for column headings so sorting can be
+   changed now.
+
+
+2001-07-28 - 0.2.1
+Features:
+-  Added docstring to roundup package so pydoc reports useful information.
+-  Added the roundup 1 software carpentry submission HTML to the doc
+   directory as "overview.html".
+
+Fixes:
+-  Fixed bug in init command - templatebuilder was assuming existence of
+   "html" directory in instance home.
+-  Fixed INSTALL.txt to reflect some changes in the installation and test
+   procedure. Whatdya know, "setup.py install" does the script install.
+   There you go...
+-  Fixed some non-string node ids in cgi_client now that the hyperdb is
+   strict about such things.
+
+2001-07-26 - 0.2.0
+Features:
+-  Major reorganisation of code to allow multiple roundup instances and a
+   single, site-packages -based installation. Also allows multiple database
+   back-ends.
+-  Moved the bin/ proggies into the top dir, so that it all works
+   out-of-the-box
+-  Added the "classic" template - a direct implementation of the Roundup
+   spec. Well, as close as we're going to get, anyway.
+-  Added an issue priority of support to "extended"
+-  Added command-line arg handling to roundup-server so it's more useful 
+   out-of-the-box.
+-  Added distutils-style installation of "lib" files.
+-  Added some unit tests.
+
+Fixes:
+-  Fixed bug in re generation in the filter
+-  Fixed handling of None String property in grouped list headings
+-  Fixed adding new issue with no change note
+-  Fixed values in text input fields which contained quotes (") are now
+   quoted.
+-  Fixed a bug in the hyperdb filter - wrong variable names in the error
+   message.
+
+2001-07-19 - 0.1.3
+-  Reldate now takes an argument "pretty" - when true, it pretty-prints the
+   interval generated up to 5 days, then pretty-prints the date of last
+   activity. The issue index and item now use the pretty format.
+-  Classes list for admin user in CGI interface.
+-  Made the view configuration more accessible, neater and more realistic.
+-  Fixed list view grouping handling grouping by a Multilink or String or Link
+   value of None or Date, ...  (mind you, sorting by Date???)
+-  Fixed bug in the plain formatter when a Link was None.
+-  Fixed ordering of list view column headings.
+-  Fixed list view column heading sort links - and limited the number of
+   columns to sort by to 2.
+-  Added searching by glob to StringType filtering -
+    ^text  - search for text at start of fields
+    text$  - search for text at end of fields
+    ^text$ - exactly match text in fields
+    te*xt  - search for text matching "te"<any characters>"xt"
+    te?xt  - search for text matching "te"<any one character>"xt"
+-  Added more fields to the issue.filter and issue.index templates
+
+
+2001-07-18 - 0.1.2
+-  Set default index to ?:group=priority&:columns=activity,status,title so
+   the priority column isn't displayed.
+-  Thanks Anthony:
+   - added notes to the README about Python prerequisites
+   - added check to roundup.py, roundup.cgi, server.py and roundup-mailgw.py
+     for python 2+ - and made the file itself parseable by 1.5.2 ;)
+   - python 2.0 didn't have the default args for the time module functions.
+   - better handling of db directory in initDB
+-  Sorting on the extra properties defined by roundupdb classes was broken
+   due to the caching used. May now sort on activity and creation
+   properties, etc.
+-  Set the default index to sort on activity
+
+
+2001-07-18 - 0.1.1
+-  Initial version release with consent of Roundup spec author, Ka-Ping Yee:
+   "Amazing!  Nice work.  I'll watch for the source code on your website."
+
+2001-07-11 - 0.1.0
+-  Needed a bug tracking system. Looked around. Tried to install many
+   Perl-based systems, to no avail. Got tired of waiting for Roundup to be
+   released. Had just finished major product project, so needed something
+   different for a while. Roundup here I come...
+
+

Added: tracker/vendor/roundup/current/COPYING.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/COPYING.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,106 @@
+Roundup Licensing
+-----------------
+
+Copyright (c) 2003 Richard Jones (richard at mechanicalcat.net)
+Copyright (c) 2002 eKit.com Inc (http://www.ekit.com/)
+Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+PageTemplates Licensing
+-----------------------
+
+Portions of this code (roundup.cgi.PageTemplates, roundup.cgi.TAL and
+roundup.cgi.ZTUtils) have been copied from Zope. They have been modified in
+the following manner:
+
+- removal of unit tests, Zope-specific code and support files from 
+  PageTemplates: PageTemplateFile.py, ZPythonExpr.py, ZRPythonExpr.py,
+  ZopePageTemplate.py, examples, help, tests, CHANGES.txt, HISTORY.txt,
+  version.txt and www. From TAL: DummyEngine.py, HISTORY.txt, CHANGES.txt,
+  benchmark, driver.py, markbench.py, ndiff.py, runtest.py, setpath.py,
+  tests and timer.py. From ZTUtils: SimpleTree.py, Zope.py, CHANGES.txt and
+  HISTORY.txt.
+- editing to remove dependencies on Zope modules (see files for change notes)
+
+The license for this code is the `Zope Public License (ZPL) Version 2.0`_,
+included below.
+
+
+Zope Public License (ZPL) Version 2.0
+-------------------------------------
+
+This software is Copyright (c) Zope Corporation (tm) and
+Contributors. All rights reserved.
+
+This license has been certified as open source. It has also
+been designated as GPL compatible by the Free Software
+Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the
+following conditions are met:
+
+1. Redistributions in source code must retain the above
+   copyright notice, this list of conditions, and the following
+   disclaimer.
+
+2. Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions, and the following
+   disclaimer in the documentation and/or other materials
+   provided with the distribution.
+
+3. The name Zope Corporation (tm) must not be used to
+   endorse or promote products derived from this software
+   without prior written permission from Zope Corporation.
+
+4. The right to distribute this software or to use it for
+   any purpose does not give you the right to use Servicemarks
+   (sm) or Trademarks (tm) of Zope Corporation. Use of them is
+   covered in a separate agreement (see
+   http://www.zope.com/Marks).
+
+5. If any files are modified, you must cause the modified
+   files to carry prominent notices stating that you changed
+   the files and the date of any change.
+
+Disclaimer
+
+  THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``AS IS''
+  AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+  NO EVENT SHALL ZOPE CORPORATION OR ITS CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+  DAMAGE.
+
+
+This software consists of contributions made by Zope
+Corporation and many individuals on behalf of Zope
+Corporation.  Specific attributions are listed in the
+accompanying credits file.
+

Added: tracker/vendor/roundup/current/ChangeLog
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/ChangeLog	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,918 @@
+2001-08-03 11:54  richard
+
+	* BUILD.txt, CHANGES.txt, README.txt, setup.py,
+	roundup/templates/classic/htmlbase.py: Started stuff off for the
+	0.2.5 release
+
+2001-08-03 11:28  richard
+
+	* roundup-admin, roundup-mailgw, roundup-server,
+	cgi-bin/roundup.cgi, roundup/init.py: Used the much nicer
+	load_package, pointed out by Steve Majewski.
+
+2001-08-03 11:19  richard
+
+	* roundup/templates/classic/: htmlbase.py, html/issue.item,
+	html/style.css: finished of colourising the classic template
+
+2001-08-03 10:59  richard
+
+	* CHANGES.txt: chnages
+
+2001-08-03 10:59  richard
+
+	* roundup-admin, roundup-mailgw, roundup-server,
+	cgi-bin/roundup.cgi, roundup/init.py: Instance import now imports
+	the instance using imp.load_module so that we can have instance
+	homes of "roundup" or other existing python package names.
+
+2001-08-02 20:26  richard
+
+	* README.txt: changes
+
+2001-08-02 16:38  richard
+
+	* roundup/: cgi_client.py, hyperdb.py, roundupdb.py,
+	templates/classic/dbinit.py, templates/classic/instance_config.py,
+	templates/extended/dbinit.py,
+	templates/extended/instance_config.py: Roundupdb now appends
+	"mailing list" information to its messages which include the e-mail
+	address and web interface address. Templates may override this in
+	their db classes to include specific information (support
+	instructions, etc).
+
+2001-08-02 16:00  richard
+
+	* CHANGES.txt: anges
+
+2001-08-02 15:55  richard
+
+	* roundup/cgi_client.py: Web edit messages aren't sent to the
+	person who did the edit any more. No message is generated if they
+	are the only person on the nosy list.
+
+2001-08-02 11:01  richard
+
+	* CHANGES.txt: changes
+
+2001-08-02 11:00  richard
+
+	* BUILD.txt: Added the 'clean' command to the instructions -
+	distutils doesn't seem to always detect when it needs to rebuild
+	when it should.
+
+2001-08-02 10:43  richard
+
+	* roundup/templates/extended/interfaces.py: Even better (more
+	useful) headings
+
+2001-08-02 10:36  richard
+
+	* roundup/templates/extended/interfaces.py: Made all the
+	user-specific link names the same (My Foo)
+
+2001-08-02 10:34  richard
+
+	* roundup/cgi_client.py: bleah syntax error
+
+2001-08-02 10:27  richard
+
+	* CHANGES.txt, roundup/templates/extended/htmlbase.py: changes
+
+2001-08-02 10:27  richard
+
+	* roundup/date.py: Extended the range of intervals that are
+	pretty-printed before actual dates are displayed.
+
+2001-08-02 10:26  richard
+
+	* roundup/cgi_client.py: Changed the order of the information in
+	the message generated by web edits.
+
+2001-08-01 15:15  richard
+
+	* CHANGES.txt: changes
+
+2001-08-01 15:15  richard
+
+	* README.txt, roundup/templates/extended/htmlbase.py,
+	roundup/templates/extended/interfaces.py,
+	roundup/templates/extended/html/issue.index,
+	roundup/templates/extended/html/support.index: Added "My Issues"
+	and "My Support" to extended template.
+
+2001-08-01 15:06  richard
+
+	* CHANGES.txt: changes
+
+2001-08-01 15:06  richard
+
+	* roundup/: templatebuilder.py, templates/classic/htmlbase.py,
+	templates/extended/htmlbase.py: htmlbase doesn't have extraneous
+	$Foo$ in it any more
+
+2001-08-01 14:24  richard
+
+	* roundup/: hyperdb.py, mailgw.py: mailgw was assuming certain
+	properties existed on the issues being created.
+
+2001-08-01 13:52  richard
+
+	* CHANGES.txt, roundup/htmltemplate.py: Checklist was using wrong
+	name.
+
+2001-08-01 13:48  richard
+
+	* README.txt: Just a new idea...
+
+2001-07-31 19:58  richard
+
+	* CHANGES.txt: changes
+
+2001-07-31 19:54  richard
+
+	* roundup/date.py: Fixed the 2.1-specific gmtime() (no arg) call in
+	roundup.date. (Paul Wright)
+
+2001-07-30 18:12  richard
+
+	* CHANGES.txt, roundup-admin, roundup/cgi_client.py,
+	roundup/htmltemplate.py, roundup/templatebuilder.py,
+	roundup/templates/classic/htmlbase.py,
+	roundup/templates/classic/html/file.newitem,
+	roundup/templates/classic/html/issue.item,
+	roundup/templates/extended/htmlbase.py,
+	roundup/templates/extended/interfaces.py: Added time logging and
+	file uploading to the templates.
+
+2001-07-30 18:04  richard
+
+	* roundup/templates/extended/html/: file.newitem, timelog.index,
+	timelog.item: oops
+
+2001-07-30 18:03  richard
+
+	* roundup/templates/extended/html/: issue.item, support.item: Fixes
+	to the uploading stuff (I forgot to put the code in the issue class
+	;)
+
+2001-07-30 17:17  richard
+
+	* setup.py: Just making sure we've got the right version in there
+	for development.
+
+2001-07-30 16:26  richard
+
+	* roundup/cgi_client.py: Added some documentation on how the
+	newblah works.
+
+2001-07-30 16:17  richard
+
+	* roundup/: cgi_client.py, htmltemplate.py: Features:  . Added
+	ability for cgi newblah forms to indicate that the new node   
+	should be linked somewhere.  Fixed:  . Fixed the agument handling
+	for the roundup-admin find command.   . Fixed handling of summary
+	when no note supplied for newblah. Again.   . Fixed detection of no
+	form in htmltemplate Field display.
+
+2001-07-30 13:53  richard
+
+	* CHANGES.txt: chanegs
+
+2001-07-30 13:52  richard
+
+	* roundup-admin: init help now lists templates and backends
+
+2001-07-30 13:52  richard
+
+	* roundup/backends/__init__.py: Checks for ability to import the
+	specific back-end module.
+
+2001-07-30 13:45  richard
+
+	* test/test_db.py: Added more DB to test_db. Can skip tests where
+	imports fail.
+
+2001-07-30 12:38  richard
+
+	* roundup/templates/: classic/htmlbase.py, extended/htmlbase.py:
+	updated htmlbases
+
+2001-07-30 12:38  richard
+
+	* roundup/: hyperdb.py, roundupdb.py: get() now has a default arg -
+	for migration only.
+
+2001-07-30 12:37  richard
+
+	* roundup/htmltemplate.py: Temporary measure until we have decent
+	schema migration.
+
+2001-07-30 12:37  richard
+
+	* roundup/cgi_client.py: Temporary measure until we have decent
+	schema migration...
+
+2001-07-30 12:37  richard
+
+	* roundup-admin: Freshen is really broken. Commented out.
+
+2001-07-30 12:36  richard
+
+	* roundup/backends/: back_bsddb.py, back_bsddb3.py: Handle
+	non-existence of db files in the other backends (code from anydbm).
+
+2001-07-30 12:35  richard
+
+	* roundup/templates/extended/html/issue.item: Should've been
+	supportcall
+
+2001-07-30 11:47  richard
+
+	* roundup/templates/extended/html/issue.item: Forgot to add the
+	support call property to the item page.
+
+2001-07-30 11:41  richard
+
+	* roundup/backends/: back_anydbm.py, back_bsddb.py, back_bsddb3.py:
+	Makes schema changes mucho easier.
+
+2001-07-30 11:32  richard
+
+	* CHANGES.txt, README.txt: noted changes
+
+2001-07-30 11:28  richard
+
+	* roundup-admin: Bugfixes
+
+2001-07-30 11:28  richard
+
+	* roundup/templates/__init__.py: Support for determining the
+	installed tempaltes
+
+2001-07-30 11:27  richard
+
+	* roundup/templates/extended/html/: support.filter, support.index,
+	support.item: Oops - these are the HTML displays for the support
+	class.
+
+2001-07-30 11:26  richard
+
+	* roundup/templates/extended/: dbinit.py, htmlbase.py,
+	interfaces.py, html/issue.filter, html/issue.index,
+	html/issue.item: Big changes:  . split off the support priority
+	into its own class  . added "new support, new user" to the page
+	head  . fixed the display options for the heading links
+
+2001-07-30 11:25  richard
+
+	* roundup/templates/classic/: htmlbase.py, interfaces.py: Changes
+	to reflect cgi_client now implementing this template by default,
+	and not "extended".
+
+2001-07-30 11:25  richard
+
+	* roundup/cgi_client.py: Default implementation is now "classic"
+	rather than "extended" as one would expect.
+
+2001-07-30 11:24  richard
+
+	* roundup/htmltemplate.py: Handles new node display now.
+
+2001-07-30 10:57  richard
+
+	* roundup-admin: Now uses getopt, much improved command-line
+	parsing. Much fuller help. Much better internal structure. It's
+	just BETTER. :)
+
+2001-07-30 10:06  richard
+
+	* roundup/templatebuilder.py: Hrm - had IOError instead of OSError.
+	Not sure why there's two. Ho hum.
+
+2001-07-30 10:05  richard
+
+	* roundup/roundupdb.py: Fixed IssueClass so that superseders links
+	to its classname rather than hard-coded to "issue".
+
+2001-07-30 10:04  richard
+
+	* roundup-admin: Made the "init" prompting more friendly.
+
+2001-07-30 09:34  richard
+
+	* CHANGES.txt, roundup/templates/classic/htmlbase.py,
+	roundup/templates/extended/htmlbase.py: changes
+
+2001-07-30 09:34  richard
+
+	* setup.py: Added unit tests so they're run whenever we
+	package/install/whatever.
+
+2001-07-30 09:32  richard
+
+	* test/test_dates.py: Fixed bug in unit test ;)
+
+2001-07-29 19:43  richard
+
+	* setup.py: Make sure that the htmlbase is up-to-date when we build
+	a source dist.
+
+2001-07-29 19:33  richard
+
+	* CHANGES.txt: changes
+
+2001-07-29 19:31  richard
+
+	* roundup/htmltemplate.py: oops
+
+2001-07-29 19:28  richard
+
+	* roundup/: htmltemplate.py, hyperdb.py: Fixed sorting by clicking
+	on column headings.
+
+2001-07-29 18:37  richard
+
+	* CHANGES.txt, README.txt, setup.py: changes
+
+2001-07-29 18:27  richard
+
+	* roundup/: cgi_client.py, htmltemplate.py, hyperdb.py: Fixed
+	handling of passed-in values in form elements (ie. during a
+	drill-down)
+
+2001-07-29 17:01  richard
+
+	* README.txt, roundup-admin, roundup-mailgw, roundup-server,
+	setup.py, cgi-bin/roundup.cgi, roundup/__init__.py,
+	roundup/cgi_client.py, roundup/cgitb.py, roundup/date.py,
+	roundup/htmltemplate.py, roundup/hyperdb.py, roundup/init.py,
+	roundup/mailgw.py, roundup/roundupdb.py,
+	roundup/templatebuilder.py, roundup/templates/classic/__init__.py,
+	roundup/templates/classic/dbinit.py,
+	roundup/templates/classic/instance_config.py,
+	roundup/templates/classic/interfaces.py,
+	roundup/templates/extended/__init__.py,
+	roundup/templates/extended/dbinit.py,
+	roundup/templates/extended/instance_config.py,
+	roundup/templates/extended/interfaces.py, test/README.txt,
+	test/__init__.py, test/test_dates.py, test/test_db.py,
+	test/test_multipart.py, test/test_schema.py: Added vim command to
+	all source so that we don't get no steenkin' tabs :)
+
+2001-07-29 16:42  richard
+
+	* test/test_dates.py: Added Interval tests.
+
+2001-07-29 15:41  richard
+
+	* CHANGES.txt: changes
+
+2001-07-29 15:36  richard
+
+	* roundup/: htmltemplate.py, hyperdb.py: Cleanup of the link label
+	generation.
+
+2001-07-29 14:11  richard
+
+	* CHANGES.txt: Reverse the entries so most recent is first.
+
+2001-07-29 14:09  richard
+
+	* test/test_db.py: Added the fabricated property "id" to all
+	hyperdb classes.
+
+2001-07-29 14:07  richard
+
+	* roundup/templates/classic/: interfaces.py, html/file.index,
+	html/issue.filter, html/issue.index, html/issue.item,
+	html/msg.index, html/msg.item, html/style.css, html/user.index,
+	html/user.item: Fixed the classic template so it's more like the
+	"advertised" Roundup template.
+
+2001-07-29 14:06  richard
+
+	* roundup/htmltemplate.py: Fixed problem in link display when Link
+	value is None.
+
+2001-07-29 14:05  richard
+
+	* roundup/: hyperdb.py, roundupdb.py: Added the fabricated property
+	"id".
+
+2001-07-29 14:04  richard
+
+	* roundup/cgi_client.py: Moved some code around allowing for
+	subclassing to change behaviour.
+
+2001-07-28 18:17  richard
+
+	* roundup/htmltemplate.py: fixed use of stylesheet
+
+2001-07-28 18:16  richard
+
+	* roundup/cgi_client.py: New issue form handles lack of note better
+	now.
+
+2001-07-28 18:02  richard
+
+	* roundup/templatebuilder.py: commented out print
+
+2001-07-28 17:59  richard
+
+	* roundup/: htmltemplate.py, init.py, templatebuilder.py: Replaced
+	errno integers with their module values.  De-tabbed
+	templatebuilder.py
+
+2001-07-28 17:35  richard
+
+	* README.txt: todo refinement ;)
+
+2001-07-28 16:44  richard
+
+	* CHANGES.txt, README.txt, doc/implementation.txt: Split off
+	implementation notes into separate file in doc directory. Added
+	some todo items to the README
+
+2001-07-28 16:43  richard
+
+	* roundup/mailgw.py, test/__init__.py, test/test_multipart.py:
+	Multipart message class has the getPart method now. Added some
+	tests for it.
+
+2001-07-28 11:56  richard
+
+	* CHANGES.txt, MANIFEST.in: changes
+
+2001-07-28 11:45  richard
+
+	* doc/: overview.html, spec.html, images/edit.gif, images/edit.png,
+	images/hyperdb.gif, images/hyperdb.png, images/logo-acl-medium.gif,
+	images/logo-acl-medium.png, images/logo-codesourcery-medium.gif,
+	images/logo-codesourcery-medium.png,
+	images/logo-software-carpentry-standard.gif,
+	images/logo-software-carpentry-standard.png, images/roundup-1.gif,
+	images/roundup-1.png, images/roundup.gif, images/roundup.png: GIF
+	-> PNG, saving about 100k
+
+2001-07-28 11:40  richard
+
+	* doc/: overview.html, images/edit.gif, images/hyperdb.gif,
+	images/roundup-1.gif, images/roundup.gif: added more documentation
+
+2001-07-28 11:39  richard
+
+	* roundup/__init__.py: Added some documentation to the roundup
+	package.
+
+2001-07-28 10:39  richard
+
+	* CHANGES.txt, setup.py: changes for the 0.2.1 distribution build.
+
+2001-07-28 10:34  richard
+
+	* CHANGES.txt: changes
+
+2001-07-28 10:34  richard
+
+	* roundup/: cgi_client.py, mailgw.py: Fixed some non-string node
+	ids.
+
+2001-07-28 10:31  richard
+
+	* INSTALL.txt, roundup/templatebuilder.py: Fixed some problems with
+	installation.
+
+2001-07-27 17:33  richard
+
+	* INSTALL.txt: more notes for installation
+
+2001-07-27 17:30  richard
+
+	* BUILD.txt: minor notes
+
+2001-07-27 17:27  richard
+
+	* BUILD.txt, README.txt: Added build instructions, changed my
+	e-mail address in the docs to the sourceforge address.
+
+2001-07-27 17:20  richard
+
+	* Makefile, setup.cfg, setup.py: Makefile is now obsolete - setup
+	does what it used to do.
+
+2001-07-27 17:18  richard
+
+	* MANIFEST.in: Added the distutils manifest template (for
+	"documentation", see distutils.filelist).  Has no facility for
+	comments, so no ID or LOG for this baby.
+
+2001-07-27 17:16  richard
+
+	* test/: README.TXT, README.txt: rename for consistency
+
+2001-07-27 17:04  richard
+
+	* INSTALL.TXT, CHANGES.txt, INSTALL.txt, README.TXT, README.txt:
+	name changes to make distutils happy
+
+2001-07-27 16:56  richard
+
+	* setup.cfg, setup.py: Added scripts to the setup and added the
+	config so the default script install dir is /usr/local/bin.
+
+2001-07-27 16:55  richard
+
+	* test/: README.TXT, __init__.py, test_dates.py, test_db.py,
+	test_schema.py: moving tests -> test
+
+2001-07-27 16:25  richard
+
+	* roundup/hyperdb.py: Fixed some of the exceptions so they're the
+	right type.  Removed the str()-ification of node ids so we don't
+	mask oopsy errors any more.
+
+2001-07-27 15:17  richard
+
+	* roundup/hyperdb.py: just some comments
+
+2001-07-26 17:14  richard
+
+	* setup.py: Made setup.py executable, added id and log.
+
+2001-07-26 16:47  richard
+
+	* INSTALL.TXT: Updated for new installation procedure
+
+2001-07-25 14:19  anthonybaxter
+
+	* setup.py: first cut at setup.py - installs the package, but not
+	the bin/cgi-bin yet
+
+2001-07-25 14:09  richard
+
+	* roundup/date.py: Fixed offset handling (shoulda read the spec a
+	little better)
+
+2001-07-25 13:40  richard
+
+	* README.TXT: added note about the spec
+
+2001-07-25 13:39  richard
+
+	* roundup/htmltemplate.py: Hrm - displaying links to classes that
+	don't specify a key property. I've got it defaulting to 'name',
+	then 'title' and then a "random" property (first one returned by
+	getprops().keys().  Needs to be moved onto the Class I think...
+
+2001-07-25 11:23  richard
+
+	* doc/spec.html, doc/images/logo-acl-medium.gif,
+	doc/images/logo-codesourcery-medium.gif,
+	doc/images/logo-software-carpentry-standard.gif,
+	roundup/backends/back_anydbm.py,
+	roundup/templates/extended/dbinit.py: Added the Roundup spec to the
+	new documentation directory.
+
+2001-07-24 21:18  anthonybaxter
+
+	* roundup/init.py: oops. left a print in
+
+2001-07-24 20:54  anthonybaxter
+
+	* roundup/: init.py, templatebuilder.py: oops. Html.
+
+2001-07-24 20:46  anthonybaxter
+
+	* roundup/: init.py, templatebuilder.py, templates/__init__.py,
+	templates/classic/__init__.py, templates/classic/dbinit.py,
+	templates/classic/htmlbase.py, templates/extended/__init__.py,
+	templates/extended/htmlbase.py: Added templatebuilder module. two
+	functions - one to pack up the html base, one to unpack it. Packed
+	up the two standard templates into htmlbases.  Modified __init__ to
+	install them.
+	
+	__init__.py magic was needed for the rather high levels of wierd
+	import magic.  Reducing level of import magic == (good, future)
+
+2001-07-24 14:26  anthonybaxter
+
+	* roundup/backends/back_bsddb3.py: bsddb3 implementation. For now,
+	it's the bsddb implementation with a "3" added in crayon.
+
+2001-07-24 11:07  richard
+
+	* roundup-server: Added command-line arg handling to roundup-server
+	so it's more useful out-of-the-box.
+
+2001-07-24 11:06  richard
+
+	* roundup/templates/classic/dbinit.py: Oops - accidentally duped
+	the keywords class
+
+2001-07-24 09:32  richard
+
+	* INSTALL.TXT: minor edit
+
+2001-07-24 09:28  richard
+
+	* roundup/templates/: README.txt, classic/__init__.py,
+	classic/dbinit.py, classic/instance_config.py,
+	classic/interfaces.py, classic/detectors/__init__.py,
+	classic/detectors/nosyreaction.py, classic/html/file.index,
+	classic/html/issue.filter, classic/html/issue.index,
+	classic/html/issue.item, classic/html/msg.index,
+	classic/html/msg.item, classic/html/style.css,
+	classic/html/user.index, classic/html/user.item: Adding the classic
+	template
+
+2001-07-24 09:20  richard
+
+	* roundup/templates/extended/dbinit.py: forgot to remove the
+	interfaces from the dbinit module ;)
+
+2001-07-24 09:16  richard
+
+	* roundup/templates/extended/: __init__.py, interfaces.py: Split
+	off the interfaces (CGI, mailgw) into a separate file from the DB
+	stuff.
+
+2001-07-23 20:31  richard
+
+	* roundup-server: disabled the reloading until it can be done
+	properly
+
+2001-07-23 18:55  richard
+
+	* CHANGES, INSTALL.TXT, README, README.TXT: renamed the text files
+	so that they're recognised as text files on windows added
+	INSTALL.TXT
+
+2001-07-23 18:53  richard
+
+	* README, roundup-server: Fixed the ROUNDUPS decl in roundup-server
+	Move the installation notes to INSTALL
+
+2001-07-23 18:45  richard
+
+	* roundup-admin, roundup/init.py,
+	roundup/templates/extended/dbinit.py: ok, so now "./roundup-admin
+	init" will ask questions in an attempt to get a workable
+	instance_home set up :) _and_ anydbm has had its first test :)
+
+2001-07-23 18:25  richard
+
+	* roundup/backends/back_bsddb.py: more handling of bad journals
+
+2001-07-23 18:20  richard
+
+	* roundup-admin, roundup/backends/back_anydbm.py,
+	roundup/backends/back_bsddb.py: Moved over to using marshal in the
+	bsddb and anydbm backends.  roundup-admin now has a "freshen"
+	command that'll load/save all nodes (not  retired - mod
+	hyperdb.Class.list() so it lists retired nodes)
+
+2001-07-23 17:56  richard
+
+	* roundup/: date.py, backends/back_bsddb.py: Storing only
+	marshallable data in the db - no nasty pickled class references.
+
+2001-07-23 17:22  richard
+
+	* roundup/backends/: __init__.py, _anydbm.py, _bsddb.py,
+	back_anydbm.py, back_bsddb.py: *sigh* some databases have _foo.so
+	as their underlying implementation.  This time for sure, Rocky.
+
+2001-07-23 17:15  richard
+
+	* roundup/backends/: _anydbm.py, _bsddb.py, bsddb.py: Moved the
+	backends into the backends package. Anydbm hasn't been tested at
+	all.
+
+2001-07-23 17:14  richard
+
+	* roundup/: roundupdb.py, backends/__init__.py,
+	templates/extended/dbinit.py: Moved the database backends off into
+	backends.
+
+2001-07-23 16:25  richard
+
+	* roundup/templates/extended/dbinit.py: relfected the move to
+	roundup/backends
+
+2001-07-23 16:24  richard
+
+	* roundup/backends/__init__.py: made backends a package
+
+2001-07-23 16:23  richard
+
+	* roundup/: hyper_bsddb.py, backends/bsddb.py: moved hyper_bsddb.py
+	to the new backends package as bsddb.py
+
+2001-07-23 14:49  anthonybaxter
+
+	* README: changed the 'snip' lines so they don't look like CVS
+	conflict markers.
+
+2001-07-23 14:47  anthonybaxter
+
+	* cgi-bin/roundup.cgi: renamed ROUNDUPS to ROUNDUP_INSTANCE_HOMES
+	sys.exit(0) if python version wrong.
+
+2001-07-23 14:33  richard
+
+	* cgi-bin/roundup.cgi: brought the CGI instance config dict in line
+	with roundup-server
+
+2001-07-23 14:33  anthonybaxter
+
+	* roundup/templates/extended/: __init__.py, dbinit.py,
+	instance_config.py: split __init__.py into 2. dbinit and
+	instance_config.
+
+2001-07-23 14:31  richard
+
+	* CHANGES, cgi-bin/roundup.cgi: Fixed the roundup CGI script for
+	updates to cgi_client.py
+
+2001-07-23 14:21  richard
+
+	* roundup/templates/extended/: html/file.index, html/issue.filter,
+	html/issue.index, html/issue.item, html/msg.index, html/msg.item,
+	html/style.css, html/user.index, html/user.item, issue.filter,
+	issue.item, msg.item, style.css, user.item: moving HTML templates
+	to their own dir
+
+2001-07-23 14:19  richard
+
+	* roundup/templates/extended/: file.index, issue.index, msg.index,
+	user.index: moving the HTML templates into their own dir
+
+2001-07-23 14:05  anthonybaxter
+
+	* roundup-server: actually quit if python version wrong
+
+2001-07-23 13:56  richard
+
+	* roundup/cgi_client.py: oops, missed a config removal
+
+2001-07-23 13:50  anthonybaxter
+
+	* roundup/templates/extended/: __init__.py, file.index,
+	issue.filter, issue.index, issue.item, msg.index, msg.item,
+	style.css, user.index, user.item, detectors/__init__.py,
+	detectors/nosyreaction.py: moved templates to proper location
+
+2001-07-23 13:46  richard
+
+	* roundup-admin, roundup-mailgw, roundup-server: moving the bin
+	files to facilitate out-of-the-boxness
+
+2001-07-22 22:09  richard
+
+	* roundup/: __init__.py, cgi_client.py, cgitb.py, date.py,
+	htmltemplate.py, hyper_bsddb.py, hyperdb.py, init.py, mailgw.py,
+	roundupdb.py: Final commit of Grande Splite
+
+2001-07-22 21:58  richard
+
+	* roundup/: __init__.py, cgi_client.py, cgitb.py, date.py,
+	htmltemplate.py, hyper_bsddb.py, hyperdb.py, init.py, mailgw.py,
+	roundupdb.py: More Grande Splite
+
+2001-07-22 21:47  richard
+
+	* cgi-bin/roundup.cgi: More Grande Splite
+
+2001-07-22 21:11  richard
+
+	* CHANGES, README, cgitb.py, config.py, date.py, hyperdb.py,
+	hyperdb_bsddb.py, roundup-mailgw.py, roundup.cgi, roundup.py,
+	roundup_cgi.py, roundupdb.py, server.py, style.css, template.py,
+	test.py: Initial commit of the Grande Splite
+
+2001-07-20 22:33  richard
+
+	* server.py: oops ;)
+
+2001-07-20 18:20  richard
+
+	* CHANGES: update for recent chagnes
+
+2001-07-20 18:20  richard
+
+	* README, hyperdb.py: Fixed a bug in the filter - wrong variable
+	names in the error message.  Recognised that the filter has an
+	outstanding bug. Hrm. we need a bug tracker for this project :)
+
+2001-07-20 17:35  richard
+
+	* CHANGES, hyperdb.py, hyperdb_bsddb.py, roundup_cgi.py,
+	roundupdb.py, test.py: largish changes as a start of splitting off
+	bits and pieces to allow more flexible installation / database
+	back-ends
+
+2001-07-20 17:34  richard
+
+	* template.py: Quote the value put in the text input value
+	attribute.
+
+2001-07-20 11:37  richard
+
+	* README: Just registering a new TODO
+
+2001-07-20 10:53  richard
+
+	* roundup_cgi.py: Default index now filters out the resolved issues
+	;)
+
+2001-07-20 10:23  richard
+
+	* CHANGES: update for latest changes
+
+2001-07-20 10:22  richard
+
+	* roundupdb.py: Priority list changes - removed the redundant TODO
+	and added support. See roundup-devel for details.
+
+2001-07-20 10:17  richard
+
+	* roundup_cgi.py: Fixed adding a new issue when there is no __note
+
+2001-07-19 20:43  anthonybaxter
+
+	* config.py, server.py: HTTP_HOST and HTTP_PORT config options.
+
+2001-07-19 16:37  anthonybaxter
+
+	* README: added more todo items
+
+2001-07-19 16:27  anthonybaxter
+
+	* cgitb.py, config.py, date.py, hyperdb.py, roundup-mailgw.py,
+	roundup.py, roundup_cgi.py, roundupdb.py, server.py, template.py:
+	fixing (manually) the (dollarsign)Log(dollarsign) entries caused by
+	my using the magic (dollarsign)Id(dollarsign) and
+	(dollarsign)Log(dollarsign) strings in a commit message. I'm a
+	twonk.
+	
+	Also broke the help string in two.
+
+2001-07-19 16:14  richard
+
+	* Makefile, README, dummy_config.py: minor changes to test the cvs
+	mailout system
+
+2001-07-19 16:08  anthonybaxter
+
+	* roundup.py: fixed typo in usage string because it was bugging me
+	each time I saw it.
+
+2001-07-19 15:52  anthonybaxter
+
+	* cgitb.py, config.py, date.py, hyperdb.py, roundup-mailgw.py,
+	roundup.py, roundup_cgi.py, roundupdb.py, server.py, template.py:
+	Added CVS keywords $Id: ChangeLog,v 1.7 2001/08/03 02:12:07 anthonybaxter Exp $ and $Log: ChangeLog,v $
+	Added CVS keywords $Id$ and Revision 1.7  2001/08/03 02:12:07  anthonybaxter
+	Added CVS keywords $Id$ and regenerated on Fri Aug  3 12:12:00 EST 2001
+	Added CVS keywords $Id$ and to all python files.
+
+2001-07-19 15:46  anthonybaxter
+
+	* config.py: modified to use localconfig.py (if it exists) and to
+	make the various options (e.g. paths) based on ROUNDUP_HOME &c.
+
+2001-07-19 15:23  richard
+
+	* CHANGES, Makefile, config.py, hyperdb.py, roundup_cgi.py,
+	roundupdb.py, template.py:  . Fixed bug in re generation in the
+	filter (I hadn't finished the code ;)
+	 . Added TODO as a priority (between bug and usability)
+	 . Fixed handling of None String property in grouped list headings
+
+2001-07-19 13:12  richard
+
+	* README: mention config.py in the install instructions, removed a
+	bug
+
+2001-07-19 13:11  richard
+
+	* Makefile, dummy_config.py: Added stuff to help with release
+	generation.   . Makefile has the release tgz builder in it   .
+	dummy_config.py is an empty config file that replaces the config.py
+	in the	   release
+
+2001-07-19 12:16  richard
+
+	* README, date.py, hyperdb.py, roundup.cgi, roundup_cgi.py,
+	roundupdb.py, CHANGES, cgitb.py, config.py, roundup-mailgw.py,
+	roundup.py, server.py, style.css, template.py: Initial revision
+
+2001-07-19 12:16  richard
+
+	* README, date.py, hyperdb.py, roundup.cgi, roundup_cgi.py,
+	roundupdb.py, CHANGES, cgitb.py, config.py, roundup-mailgw.py,
+	roundup.py, server.py, style.css, template.py: Initial import of
+	code - currently version 1.0.2 but with the 1.0.3 changes as given
+	in the CHANGES file. Is about ready for a 1.0.3 release.
+

Added: tracker/vendor/roundup/current/MANIFEST.in
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/MANIFEST.in	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,14 @@
+recursive-include roundup *.*
+recursive-include frontends *.*
+recursive-include scripts *.* *-*
+recursive-include tools *.*
+recursive-include cgi-bin *.cgi
+recursive-include test *.py *.txt
+recursive-include doc *.html *.png *.txt *.css *.1
+recursive-include detectors *.py
+recursive-include templates *.* home* page*
+global-exclude .cvsignore *.pyc *.pyo .DS_Store
+include run_tests.py *.txt demo.py MANIFEST.in MANIFEST
+exclude BUILD.txt I18N_PROGRESS.txt TODO.txt
+exclude doc/security.txt doc/templating.txt
+include locale/*.po locale/*.mo locale/roundup.pot

Added: tracker/vendor/roundup/current/README.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/README.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,39 @@
+=======================================================
+Roundup: an Issue-Tracking System for Knowledge Workers
+=======================================================
+
+Copyright (c) 2003 Richard Jones (richard at mechanicalcat.net)
+Copyright (c) 2002 eKit.com Inc (http://www.ekit.com/)
+Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
+
+
+INSTANT GRATIFICATION
+=====================
+
+The impatient may try Roundup immediately by typing at the console::
+
+   python demo.py
+
+To start anew (a fresh demo instance)::
+
+   python demo.py nuke
+
+Installation
+============
+For installation instructions, please see installation.txt in the "doc"
+directory.
+
+
+Upgrading
+=========
+For upgrading instructions, please see upgrading.txt in the "doc" directory.
+
+
+Usage and Other Information
+===========================
+See the index.txt file in the "doc" directory.
+
+
+License
+=======
+See COPYING.txt

Added: tracker/vendor/roundup/current/cgi-bin/roundup.cgi
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/cgi-bin/roundup.cgi	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,229 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
+# This module is free software, and you may redistribute it and/or modify
+# under the same terms as Python, so long as this copyright message and
+# disclaimer are retained in their original form.
+#
+# IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
+# OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
+# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
+# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+# 
+# $Id: roundup.cgi,v 1.42 2005/05/18 05:39:21 richard Exp $
+
+# python version check
+from roundup import version_check
+from roundup.i18n import _
+import sys, time
+
+#
+##  Configuration
+#
+
+# Configuration can also be provided through the OS environment (or via
+# the Apache "SetEnv" configuration directive). If the variables
+# documented below are set, they _override_ any configuation defaults
+# given in this file. 
+
+# TRACKER_HOMES is a list of trackers, in the form
+# "NAME=DIR<sep>NAME2=DIR2<sep>...", where <sep> is the directory path
+# separator (";" on Windows, ":" on Unix). 
+
+# Make sure the NAME part doesn't include any url-unsafe characters like 
+# spaces, as these confuse the cookie handling in browsers like IE.
+
+# ROUNDUP_LOG is the name of the logfile; if it's empty or does not exist,
+# logging is turned off (unless you changed the default below). 
+
+# DEBUG_TO_CLIENT specifies whether debugging goes to the HTTP server (via
+# stderr) or to the web client (via cgitb).
+DEBUG_TO_CLIENT = False
+
+# This indicates where the Roundup tracker lives
+TRACKER_HOMES = {
+#    'example': '/path/to/example',
+}
+
+# Where to log debugging information to. Use an instance of DevNull if you
+# don't want to log anywhere.
+class DevNull:
+    def write(self, info):
+        pass
+    def close(self):
+        pass
+    def flush(self):
+        pass
+#LOG = open('/var/log/roundup.cgi.log', 'a')
+LOG = DevNull()
+
+#
+##  end configuration
+#
+
+
+#
+# Set up the error handler
+# 
+try:
+    import traceback, StringIO, cgi
+    from roundup.cgi import cgitb
+except:
+    print "Content-Type: text/plain\n"
+    print _("Failed to import cgitb!\n\n")
+    s = StringIO.StringIO()
+    traceback.print_exc(None, s)
+    print s.getvalue()
+
+
+#
+# Check environment for config items
+#
+def checkconfig():
+    import os, string
+    global TRACKER_HOMES, LOG
+
+    # see if there's an environment var. ROUNDUP_INSTANCE_HOMES is the
+    # old name for it.
+    if os.environ.has_key('ROUNDUP_INSTANCE_HOMES'):
+        homes = os.environ.get('ROUNDUP_INSTANCE_HOMES')
+    else:
+        homes = os.environ.get('TRACKER_HOMES', '')
+    if homes:
+        TRACKER_HOMES = {}
+        for home in string.split(homes, os.pathsep):
+            try:
+                name, dir = string.split(home, '=', 1)
+            except ValueError:
+                # ignore invalid definitions
+                continue
+            if name and dir:
+                TRACKER_HOMES[name] = dir
+                
+    logname = os.environ.get('ROUNDUP_LOG', '')
+    if logname:
+        LOG = open(logname, 'a')
+
+    # ROUNDUP_DEBUG is checked directly in "roundup.cgi.client"
+
+
+#
+# Provide interface to CGI HTTP response handling
+#
+class RequestWrapper:
+    '''Used to make the CGI server look like a BaseHTTPRequestHandler
+    '''
+    def __init__(self, wfile):
+        self.wfile = wfile
+    def write(self, data):
+        self.wfile.write(data)
+    def send_response(self, code):
+        self.write('Status: %s\r\n'%code)
+    def send_header(self, keyword, value):
+        self.write("%s: %s\r\n" % (keyword, value))
+    def end_headers(self):
+        self.write("\r\n")
+
+#
+# Main CGI handler
+#
+def main(out, err):
+    import os, string
+    import roundup.instance
+    path = string.split(os.environ.get('PATH_INFO', '/'), '/')
+    request = RequestWrapper(out)
+    request.path = os.environ.get('PATH_INFO', '/')
+    tracker = path[1]
+    os.environ['TRACKER_NAME'] = tracker
+    os.environ['PATH_INFO'] = string.join(path[2:], '/')
+    if TRACKER_HOMES.has_key(tracker):
+        # redirect if we need a trailing '/'
+        if len(path) == 2:
+            request.send_response(301)
+            # redirect
+            if os.environ.get('HTTPS', '') == 'on':
+                protocol = 'https'
+            else:
+                protocol = 'http'
+            absolute_url = '%s://%s%s/'%(protocol, os.environ['HTTP_HOST'],
+                os.environ.get('REQUEST_URI', ''))
+            request.send_header('Location', absolute_url)
+            request.end_headers()
+            out.write('Moved Permanently')
+        else:
+            tracker_home = TRACKER_HOMES[tracker]
+            tracker = roundup.instance.open(tracker_home)
+            import roundup.cgi.client
+            if hasattr(tracker, 'Client'):
+                client = tracker.Client(tracker, request, os.environ)
+            else:
+                client = roundup.cgi.client.Client(tracker, request, os.environ)
+            try:
+                client.main()
+            except roundup.cgi.client.Unauthorised:
+                request.send_response(403)
+                request.send_header('Content-Type', 'text/html')
+                request.end_headers()
+                out.write('Unauthorised')
+            except roundup.cgi.client.NotFound:
+                request.send_response(404)
+                request.send_header('Content-Type', 'text/html')
+                request.end_headers()
+                out.write('Not found: %s'%client.path)
+
+    else:
+        import urllib
+        request.send_response(200)
+        request.send_header('Content-Type', 'text/html')
+        request.end_headers()
+        w = request.write
+        w(_('<html><head><title>Roundup trackers index</title></head>\n'))
+        w(_('<body><h1>Roundup trackers index</h1><ol>\n'))
+        homes = TRACKER_HOMES.keys()
+        homes.sort()
+        for tracker in homes:
+            w(_('<li><a href="%(tracker_url)s/index">%(tracker_name)s</a>\n')%{
+                'tracker_url': os.environ['SCRIPT_NAME']+'/'+
+                               urllib.quote(tracker),
+                'tracker_name': cgi.escape(tracker)})
+        w(_('</ol></body></html>'))
+
+#
+# Now do the actual CGI handling
+#
+out, err = sys.stdout, sys.stderr
+try:
+    # force input/output to binary (important for file up/downloads)
+    if sys.platform == "win32":
+        import os, msvcrt
+        msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
+        msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+    checkconfig()
+    sys.stdout = sys.stderr = LOG
+    main(out, err)
+except SystemExit:
+    pass
+except:
+    sys.stdout, sys.stderr = out, err
+    out.write('Content-Type: text/html\n\n')
+    if DEBUG_TO_CLIENT:
+        cgitb.handler()
+    else:
+        out.write(cgitb.breaker())
+        ts = time.ctime()
+        out.write('''<p>%s: An error occurred. Please check
+            the server log for more infomation.</p>'''%ts)
+        print >> sys.stderr, 'EXCEPTION AT', ts
+        traceback.print_exc(0, sys.stderr)
+
+sys.stdout.flush()
+sys.stdout, sys.stderr = out, err
+LOG.close()
+
+# vim: set filetype=python ts=4 sw=4 et si

Added: tracker/vendor/roundup/current/demo.py
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/demo.py	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,129 @@
+#! /usr/bin/env python
+#
+# Copyright (c) 2003 Richard Jones (richard at mechanicalcat.net)
+#
+# $Id: demo.py,v 1.24 2006/02/08 04:03:54 richard Exp $
+
+import errno
+import os
+import socket
+import sys
+import urlparse
+from glob import glob
+
+from roundup import configuration
+from roundup.scripts import roundup_server
+
+def install_demo(home, backend, template):
+    """Install a demo tracker
+
+    Parameters:
+        home:
+            tracker home directory path
+        backend:
+            database backend name
+        template:
+            full path to the tracker template directory
+
+    """
+    from roundup import init, instance, password, backends
+
+    # set up the config for this tracker
+    config = configuration.CoreConfig()
+    config['TRACKER_HOME'] = home
+    config['MAIL_DOMAIN'] = 'localhost'
+    config['DATABASE'] = 'db'
+    config['WEB_DEBUG'] = True
+    if backend in ('mysql', 'postgresql'):
+        config['RDBMS_HOST'] = 'localhost'
+        config['RDBMS_USER'] = 'rounduptest'
+        config['RDBMS_PASSWORD'] = 'rounduptest'
+        config['RDBMS_NAME'] = 'rounduptest'
+
+    # see if we have further db nuking to perform
+    module = backends.get_backend(backend)
+    if module.db_exists(config):
+        module.db_nuke(config)
+
+    init.install(home, template)
+    # don't have email flying around
+    os.remove(os.path.join(home, 'detectors', 'nosyreaction.py'))
+    try:
+        os.remove(os.path.join(home, 'detectors', 'nosyreaction.pyc'))
+    except os.error, error:
+        if error.errno != errno.ENOENT:
+            raise
+    init.write_select_db(home, backend)
+
+    # figure basic params for server
+    hostname = 'localhost'
+    # pick a fairly odd, random port
+    port = 8917
+    while 1:
+        print 'Trying to set up web server on port %d ...'%port,
+        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        try:
+            s.connect((hostname, port))
+        except socket.error, e:
+            if not hasattr(e, 'args') or e.args[0] != errno.ECONNREFUSED:
+                raise
+            print 'should be ok.'
+            break
+        else:
+            s.close()
+            print 'already in use.'
+            port += 100
+    config['TRACKER_WEB'] = 'http://%s:%s/demo/'%(hostname, port)
+
+    # write the config
+    config['INSTANT_REGISTRATION'] = 1
+    config.save(os.path.join(home, config.INI_FILE))
+
+    # open the tracker and initialise
+    tracker = instance.open(home)
+    tracker.init(password.Password('admin'))
+
+    # add the "demo" user
+    db = tracker.open('admin')
+    db.user.create(username='demo', password=password.Password('demo'),
+        realname='Demo User', roles='User')
+    db.commit()
+    db.close()
+
+def run_demo(home):
+    """Run the demo tracker installed in ``home``"""
+    cfg = configuration.CoreConfig(home)
+    url = cfg["TRACKER_WEB"]
+    hostname, port = urlparse.urlparse(url)[1].split(':')
+    port = int(port)
+    success_message = '''Server running - connect to:
+    %s
+1. Log in as "demo"/"demo" or "admin"/"admin".
+2. Hit Control-C to stop the server.
+3. Re-start the server by running "python demo.py" again.
+4. Re-initialise the server by running "python demo.py nuke".
+''' % url
+
+    # disable command line processing in roundup_server
+    sys.argv = sys.argv[:1] + ['-p', str(port), 'demo=' + home]
+    roundup_server.run(success_message=success_message)
+
+def demo_main():
+    """Run a demo server for users to play with for instant gratification.
+
+    Sets up the web service on localhost. Disables nosy lists.
+    """
+    home = os.path.abspath('demo')
+    if not os.path.exists(home) or (sys.argv[-1] == 'nuke'):
+        if len(sys.argv) > 2:
+            backend = sys.argv[-2]
+        else:
+            backend = 'anydbm'
+        install_demo(home, backend, os.path.join('templates', 'classic'))
+    run_demo(home)
+
+if __name__ == '__main__':
+    demo_main()
+
+# vim: set filetype=python sts=4 sw=4 et si :

Added: tracker/vendor/roundup/current/detectors/creator_resolution.py
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/detectors/creator_resolution.py	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,43 @@
+# This detector was written by richard at mechanicalcat.net and it's been
+# placed in the Public Domain. Copy and modify to your heart's content.
+
+#$Id: creator_resolution.py,v 1.2 2004/04/07 06:32:54 richard Exp $
+
+from roundup.exceptions import Reject
+
+def creator_resolution(db, cl, nodeid, newvalues):
+    '''Catch attempts to set the status to "resolved" - if the assignedto
+    user isn't the creator, then set the status to "in-progress" (try
+    "confirm-done" first though, but "classic" Roundup doesn't have that
+    status)
+    '''
+    if not newvalues.has_key('status'):
+        return
+
+    # get the resolved state ID
+    resolved_id = db.status.lookup('resolved')
+
+    if newvalues['status'] != resolved_id:
+        return
+
+    # check the assignedto
+    assignedto = newvalues.get('assignedto', cl.get(nodeid, 'assignedto'))
+    creator = cl.get(nodeid, 'creator')
+    if assignedto == creator:
+        if db.getuid() != creator:
+            name = db.user.get(creator, 'username')
+            raise Reject, 'Only the creator (%s) may close this issue'%name
+        return
+
+    # set the assignedto and status
+    newvalues['assignedto'] = creator
+    try:
+        status = db.status.lookup('confirm-done')
+    except KeyError:
+        status = db.status.lookup('in-progress')
+    newvalues['status'] = status
+
+def init(db):
+    db.issue.audit('set', creator_resolution)
+
+# vim: set filetype=python ts=4 sw=4 et si

Added: tracker/vendor/roundup/current/detectors/emailauditor.py
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/detectors/emailauditor.py	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,42 @@
+
+def eml_to_mht(db, cl, nodeid, newvalues):
+    '''This auditor fires whenever a new file entity is created.
+
+    If the file is of type message/rfc822, we tack onthe extension .eml.
+
+    The reason for this is that Microsoft Internet Explorer will not open
+    things with a .eml attachment, as they deem it 'unsafe'. Worse yet,
+    they'll just give you an incomprehensible error message. For more 
+    information, please see: 
+
+    http://support.microsoft.com/default.aspx?scid=kb;EN-US;825803
+
+    Their suggested work around is (excerpt):
+
+     WORKAROUND
+
+     To work around this behavior, rename the .EML file that the URL
+     links to so that it has a .MHT file name extension, and then update
+     the URL to reflect the change to the file name. To do this:
+
+     1. In Windows Explorer, locate and then select the .EML file that
+        the URL links.
+     2. Right-click the .EML file, and then click Rename.
+     3. Change the file name so that the .EML file uses a .MHT file name
+        extension, and then press ENTER.
+     4. Updated the URL that links to the file to reflect the new file
+        name extension.
+
+    So... we do that. :)'''
+    if newvalues.get('type', '').lower() == "message/rfc822":
+        if not newvalues.has_key('name'):
+            newvalues['name'] = 'email.mht'
+            return
+        name = newvalues['name']
+        if name.endswith('.eml'):
+            name = name[:-4]
+        newvalues['name'] = name + '.mht'
+
+def init(db):
+    db.file.audit('create', eml_to_mht)
+

Added: tracker/vendor/roundup/current/detectors/newissuecopy.py
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/detectors/newissuecopy.py	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,22 @@
+# copied from nosyreaction
+
+from roundup import roundupdb
+
+def newissuecopy(db, cl, nodeid, oldvalues):
+    ''' Copy a message about new issues to a team address.
+    '''
+    # so use all the messages in the create
+    change_note = cl.generateCreateNote(nodeid)
+
+    # send a copy to the nosy list
+    for msgid in cl.get(nodeid, 'messages'):
+        try:
+            # note: last arg must be a list
+            cl.send_message(nodeid, msgid, change_note, ['team at team.host'])
+        except roundupdb.MessageSendError, message:
+            raise roundupdb.DetectorError, message
+
+def init(db):
+    db.issue.react('create', newissuecopy)
+
+# vim: set filetype=python ts=4 sw=4 et si

Added: tracker/vendor/roundup/current/doc/.cvsignore
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/.cvsignore	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,21 @@
+announcement.html
+customizing.html
+developers.html
+implementation.html
+index.html
+installation.html
+user_guide.html
+FAQ.html
+security.html
+features.html
+upgrading.html
+glossary.html
+design.html
+admin_guide.html
+overview.html
+mysql.html
+postgresql.html
+tracker_templates.html
+whatsnew-0.7.html
+whatsnew-0.8.html
+*.ht

Added: tracker/vendor/roundup/current/doc/FAQ.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/FAQ.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,212 @@
+===========
+Roundup FAQ
+===========
+
+:Version: $Revision: 1.22 $
+
+.. contents::
+
+
+Installation
+------------
+
+Living without a mailserver
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Remove the nosy reactor, means delete the tracker file
+``detectors/nosyreactor.py`` from your tracker home.
+
+
+The cgi-bin is very slow!
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Yep, it sure is. It has to start up Python and load all of the support
+libraries for *every* request.
+
+The solution is to use the built in server.
+
+To make Roundup more seamless with your website, you may place the built
+in server behind apache and link it into your web tree
+
+
+How do I put Roundup behind Apache
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We have a project (foo) running on ``tracker.example:8080``.
+We want ``http://tracker.example/issues`` to use the roundup server, so we 
+set that up on port 8080 on ``tracker.example`` with the ``config.ini`` line::
+
+  [tracker]
+  ...
+  web = 'http://tracker.example/issues/'
+
+We have a "foo_issues" tracker and we run the server with::
+
+  roundup-server -p 8080 issues=/home/roundup/trackers/issues 
+
+Then, on the Apache machine (eg. redhat 7.3 with apache 1.3), in
+``/etc/httpd/conf/httpd.conf`` uncomment::
+
+  LoadModule proxy_module       modules/libproxy.so
+
+and::
+
+  AddModule mod_proxy.c
+
+Then add::
+
+  # roundup stuff (added manually)
+  <IfModule mod_proxy.c>
+  # proxy through one tracker
+  ProxyPass /issues/ http://tracker.example:8080/issues/
+  # proxy through all tracker(*)
+  #ProxyPass /roundup/ http://tracker.example:8080/
+  </IfModule>
+
+Then restart Apache. Now Apache will proxy the request on to the
+roundup-server.
+
+Note that if you're proxying multiple trackers, you'll need to use the
+second ProxyPass rule described above. It will mean that your TRACKER_WEB
+will change to::
+
+  TRACKER_WEB = 'http://tracker.example/roundup/issues/'
+
+Once you're done, you can firewall off port 8080 from the rest of the world.
+
+Note that in some situations (eg. virtual hosting) you might need to use a
+more complex rewrite rule instead of the simpler ProxyPass above. The
+following should be useful as a starting template::
+
+  # roundup stuff (added manually)
+  <IfModule mod_proxy.c>
+
+  RewriteEngine on
+  
+  # General Roundup
+  RewriteRule ^/roundup$  roundup/    [R]
+  RewriteRule ^/roundup/(.*)$ http://tracker.example:8080/$1   [P,L]
+  
+  # Handle Foo Issues
+  RewriteRule ^/issues$  issues/    [R]
+  RewriteRule ^/issues/(.*)$ http://tracker.example:8080/issues/$1 [P,L]
+  
+  </IfModule>
+
+
+How do I run Roundup through SSL (HTTPS)?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You should proxy through apache and use its SSL service. See the previous
+question on how to proxy through apache.
+
+
+Roundup runs very slowly on my XP machine when accessed from the Internet
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The issue is probably related to host name resolution for the client
+performing the request. You can turn off the resolution of the names
+when it's so slow like this. To do so, edit the module
+roundup/scripts/roundup_server.py around line 77 to add the following
+to the RoundupRequestHandler class:
+
+     def address_string(self):
+         return self.client_address[0]
+
+
+Templates
+---------
+
+What is that stuff in the tracker html directory?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the template code that Roundup uses to display the various pages.
+This is based upon the template markup language in Zope called, oddly
+enough "Zope Page Templates". There's documentation in the Roundup
+customisation_ documentation. For more information have a look at:
+
+   http://www.zope.org/Documentation/Books/ZopeBook/2_6Edition/ 
+
+specifically chapter 10 "Using Zope Page Templates" and chapter 14 "Advanced
+Page Templates".
+
+
+But I just want a select/option list for ....
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Really easy... edit ``html/issue.item``. For 'nosy', change line 53 from::
+
+  <span tal:replace="structure context/nosy/field" />
+
+to::
+
+  <span tal:replace="structure context/nosy/menu" />
+
+For 'assigned to', change line 61 from::
+
+  <td tal:content="structure context/assignedto/field">assignedto menu</td>
+
+to::
+
+  <td tal:content="structure context/assignedto/menu">assignedto menu</td>
+
+
+
+Great! But now the select/option list is too big
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Thats a little harder (but only a little ;^)
+
+Again, edit ``html/issue.item``. For nosy, change line 53 from:
+
+  <span tal:replace="structure context/nosy/field" />
+
+to::
+
+  <span tal:replace="structure python:context.nosy.menu(height=3)" />
+
+for more information, go and read about Zope Page Templates.
+
+
+Using Roundup
+-------------
+
+I got an error and I cant reload it!
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you're using Netscape/Mozilla, try holding shift and pressing reload.
+If you're using IE then install Mozilla and try again ;^)
+
+
+I keep getting logged out
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Make sure that the ``tracker`` -> ``web`` setting in your tracker's
+config.ini is set to the URL of the tracker.
+
+
+How is sorting performed, and why does it seem to fail sometimes?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When we sort items in the hyperdb, we use one of a number of methods,
+depending on the properties being sorted on:
+
+1. If it's a String, Number, Date or Interval property, we just sort the
+   scalar value of the property. Strings are sorted case-sensitively.
+2. If it's a Link property, we sort by either the linked item's "order"
+   property (if it has one) or the linked item's "id".
+3. Mulitlinks sort similar to #2, but we start with the first
+   Multilink list item, and if they're the same, we sort by the second item,
+   and so on.
+
+Note that if an "order" property is defined on a Class that is used for
+sorting, all items of that Class *must* have a value against the "order"
+property, or sorting will result in random ordering.
+
+-----------------
+
+Back to `Table of Contents`_
+
+.. _`Table of Contents`: index.html
+.. _`customisation`: customizing.html
+

Added: tracker/vendor/roundup/current/doc/Makefile
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/Makefile	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,25 @@
+STXTOHTML = rst2html.py
+STXTOHT = rst2ht.py
+WEBDIR = ../../htdocs/htdocs/doc-1.0
+
+SOURCE = announcement.txt customizing.txt developers.txt FAQ.txt features.txt \
+    glossary.txt implementation.txt index.txt design.txt mysql.txt \
+    installation.txt upgrading.txt user_guide.txt admin_guide.txt \
+	postgresql.txt tracker_templates.txt
+
+COMPILED := $(SOURCE:.txt=.html)
+WEBHT := $(SOURCE:.txt=.ht)
+
+all: ${COMPILED} ${WEBHT}
+
+website: ${WEBHT}
+	cp *.ht ${WEBDIR}
+
+%.html: %.txt
+	${STXTOHTML} --report=warning -d $< $@
+
+%.ht: %.txt
+	${STXTOHT} --report=warning -d $< $@
+
+clean:
+	rm -f ${COMPILED}

Added: tracker/vendor/roundup/current/doc/ZPL.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/ZPL.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,59 @@
+Zope Public License (ZPL) Version 2.0
+-----------------------------------------------
+
+This software is Copyright (c) Zope Corporation (tm) and
+Contributors. All rights reserved.
+
+This license has been certified as open source. It has also
+been designated as GPL compatible by the Free Software
+Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the
+following conditions are met:
+
+1. Redistributions in source code must retain the above
+   copyright notice, this list of conditions, and the following
+   disclaimer.
+
+2. Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions, and the following
+   disclaimer in the documentation and/or other materials
+   provided with the distribution.
+
+3. The name Zope Corporation (tm) must not be used to
+   endorse or promote products derived from this software
+   without prior written permission from Zope Corporation.
+
+4. The right to distribute this software or to use it for
+   any purpose does not give you the right to use Servicemarks
+   (sm) or Trademarks (tm) of Zope Corporation. Use of them is
+   covered in a separate agreement (see
+   http://www.zope.com/Marks).
+
+5. If any files are modified, you must cause the modified
+   files to carry prominent notices stating that you changed
+   the files and the date of any change.
+
+Disclaimer
+
+  THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``AS IS''
+  AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+  NO EVENT SHALL ZOPE CORPORATION OR ITS CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+  DAMAGE.
+
+
+This software consists of contributions made by Zope
+Corporation and many individuals on behalf of Zope
+Corporation.  Specific attributions are listed in the
+accompanying credits file.

Added: tracker/vendor/roundup/current/doc/admin_guide.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/admin_guide.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,357 @@
+====================
+Administration Guide
+====================
+
+:Version: $Revision: 1.20 $
+
+.. contents::
+
+What does Roundup install?
+==========================
+
+There's two "installations" that we talk about when using Roundup:
+
+1. The installation of the software and its support files. This uses the
+   standard Python mechanism called "distutils" and thus Roundup's core code,
+   executable scripts and support data files are installed in Python's
+   directories. On Windows, this is typically:
+
+   Scripts
+     ``<python dir>\scripts\...``
+   Core code
+     ``<python dir>\lib\site-packages\roundup\...``
+   Support files
+     ``<python dir>\share\roundup\...``
+
+   and on Unix-like systems (eg. Linux):
+
+   Scripts
+     ``<python root>/bin/...``
+   Core code
+     ``<python root>/lib-<python version>/site-packages/roundup/...``
+   Support files
+     ``<python root>/share/roundup/...``
+
+2. The installation of a specific tracker. When invoking the roundup-admin
+   "inst" (and "init") commands, you're creating a new Roundup tracker. This
+   installs configuration files, HTML templates, detector code and a new
+   database. You have complete control over where this stuff goes through
+   both choosing your "tracker home" and the ``main`` -> ``database`` variable
+   in the tracker's config.ini. 
+
+
+Configuring Roundup's Logging of Messages For Sysadmins
+=======================================================
+
+You may configure where Roundup logs messages in your tracker's config.ini
+file. Roundup will use the standard Python (2.3+) logging implementation
+when available. If not, then a very basic logging implementation will be used
+(see BasicLogging in the roundup.rlog module for details).
+
+Configuration for standard "logging" module:
+ - tracker configuration file specifies the location of a logging
+   configration file as ``logging`` -> ``config``
+ - ``roundup-server`` specifies the location of a logging configuration
+   file on the command line
+Configuration for "BasicLogging" implementation:
+ - tracker configuration file specifies the location of a log file
+   ``logging`` -> ``filename``
+ - tracker configuration file specifies the level to log to as
+   ``logging`` -> ``level``
+ - ``roundup-server`` specifies the location of a log file on the command
+   line
+ - ``roundup-server`` specifies the level to log to on the command line
+
+(``roundup-mailgw`` always logs to the tracker's log file)
+
+In both cases, if no logfile is specified then logging will simply be sent
+to sys.stderr with only logging of ERROR messages.
+
+
+Configuring roundup-server
+==========================
+
+The basic configuration file layout is as follows (take from the
+``roundup-server.ini.example`` file in the "doc" directory)::
+
+    [main]
+    port = 8080
+    ;hostname = 
+    ;user = 
+    ;group = 
+    ;log_ip = yes
+    ;pidfile = 
+    ;logfile = 
+
+    [trackers]
+    ; Add one of these per tracker being served
+    name = /path/to/tracker/name
+
+Values ";commented out" are optional. The meaning of the various options
+are as follows:
+
+**port**
+  Defines the local TCP port to listen for clients on.
+**hostname**
+  Defines the local hostname to listen for clients on. Only required if
+  "localhost" is not sufficient.
+**user** and **group**
+  Defines the Unix user and group to run the server as. Only work if the
+  server is started as root.
+**log_ip**
+  If ``yes`` then we log IP addresses against accesses. If ``no`` then we
+  log the hostname of the client. The latter can be much slower.
+**pidfile**
+  If specified, the server will fork at startup and write its new PID to
+  the file.
+**logfile**
+  Any unhandled exception messages or other output from Roundup will be
+  written to this file. It must be specified if **pidfile** is specified.
+  If per-tracker logging is specified, then very little will be written to
+  this file.
+**trackers** section
+  Each line denotes a mapping from a URL component to a tracker home.
+  Make sure the name part doesn't include any url-unsafe characters like
+  spaces. Stick to alphanumeric characters and you'll be ok.
+
+
+Users and Security
+==================
+
+Roundup holds its own user database which primarily contains a username,
+password and email address for the user. Roundup *must* have its own user
+listing, in order to maintain internal consistency of its data. It is a
+relatively simple exercise to update this listing on a regular basis, or on
+demand, so that it matches an external listing (eg. unix passwd file, LDAP,
+etc.)
+
+Roundup identifies users in a number of ways:
+
+1. Through the web, users may be identified by either HTTP Basic
+   Authentication or cookie authentication. If you are running the web
+   server (roundup-server) through another HTTP server (eg. apache or IIS)
+   then that server may require HTTP Basic Authentication, and it will pass
+   the ``REMOTE_USER`` variable through to Roundup. If this variable is not
+   present, then Roundup defaults to using its own cookie-based login
+   mechanism.
+2. In email messages handled by roundup-mailgw, users are identified by the
+   From address in the message.
+
+In both cases, Roundup's behaviour when dealing with unknown users is
+controlled by Permissions defined in the "SECURITY SETTINGS" section of the
+tracker's ``schema.py`` module:
+
+Web Registration
+  If granted to the Anonymous Role, then anonymous users will be able to
+  register through the web.
+Email Registration
+  If granted to the Anonymous Role, then email messages from unknown users
+  will result in those users being registered with the tracker.
+
+More information about how to customise your tracker's security settings
+may be found in the `customisation documentation`_.
+
+
+Tasks
+=====
+
+Maintenance of Roundup can involve one of the following:
+
+1. `tracker backup`_ 
+2. `software upgrade`_
+3. `migrating backends`_
+4. `moving a tracker`_
+5. `migrating from other software`_
+6. `adding a user from the command-line`_
+
+
+Tracker Backup
+--------------
+
+Stop the web and email frontends and to copy the contents of the tracker home
+directory to some other place using standard backup tools.
+
+
+Software Upgrade
+----------------
+
+Always make a backup of your tracker before upgrading software. Steps you may
+take:
+
+1. Ensure that the unit tests run on your system::
+
+    python run_tests.py
+
+2. If you're using an RDBMS backend, make a backup of its contents now.
+3. Make a backup of the tracker home itself.
+4. Stop the tracker web and email frontends.
+5. Follow the steps in the `upgrading documentation`_ for the new version of
+   the software in the copied.
+6. You may test each of the admin tool, web interface and mail gateway using
+   the new version of the software. To do this, invoke the scripts directly
+   in the source directory with::
+
+    PYTHONPATH=. python roundup/scripts/roundup_server.py <normal arguments>
+    PYTHONPATH=. python roundup/scripts/roundup_admin.py <normal arguments>
+    PYTHONPATH=. python roundup/scripts/roundup_mailgw.py <normal arguments>
+
+   Note that on Windows, this would read::
+
+    C:\sources\roundup-0.7.4> SET PYTHONPATH=.
+    C:\sources\roundup-0.7.4> python roundup/scripts/roundup_server.py <normal arguments>
+
+7. Once you're comfortable that the upgrade will work using that copy, you
+   should install the new version of the software::
+
+    python setup.py install
+
+8. Restart your tracker web and email frontends.
+
+If something bad happens, you may reinstate your backup of the tracker and
+reinstall the older version of the sofware using the same install command::
+
+    python setup.py install
+
+
+Migrating Backends
+------------------
+
+1. stop the existing tracker web and email frontends (preventing changes)
+2. use the roundup-admin tool "export" command to export the contents of
+   your tracker to disk
+3. copy the tracker home to a new directory
+4. delete the "db" directory from the new directory
+5. enter the new backend name in the tracker home ``db/backend_name`` file
+6. use the roundup-admin "import" command to import the previous export with
+   the new tracker home
+7. test each of the admin tool, web interface and mail gateway using the new
+   backend
+8. move the old tracker home out of the way (rename to "tracker.old") and 
+   move the new tracker home into its place
+9. restart web and email frontends
+
+
+Moving a Tracker
+----------------
+
+If you're moving the tracker to a similar machine, you should:
+
+1. install Roundup on the new machine and test that it works there,
+2. stop the existing tracker web and email frontends (preventing changes),
+3. copy the tracker home directory over to the new machine, and
+4. start the tracker web and email frontends on the new machine.
+
+Most of the backends are actually portable across platforms (ie. from Unix to
+Windows to Mac). If this isn't the case (ie. the tracker doesn't work when
+moved using the above steps) then you'll need to:
+
+1. install Roundup on the new machine and test that it works there,
+2. stop the existing tracker web and email frontends (preventing changes),
+3. use the roundup-admin tool "export" command to export the contents of
+   the existing tracker,
+4. copy the export to the new machine,
+5. use the roundup-admin "import" command to import the tracker on the new
+   machine, and
+6. start the tracker web and email frontends on the new machine.
+
+
+Migrating From Other Software
+-----------------------------
+
+You have a couple of choices. You can either use a CSV import into Roundup,
+or you can write a simple Python script which uses the Roundup API
+directly. The latter is almost always simpler -- see the "scripts"
+directory in the Roundup source for some example uses of the API.
+
+"roundup-admin import" will import data into your tracker from a 
+directory containing files with the following format:
+
+- one colon-separated-values file per Class with columns for each property,
+  named <classname>.csv
+- one colon-separated-values file per Class with journal information,
+  named <classname>-journals.csv (this is required, even if it's empty)
+- if the Class is a FileClass, you may have the "content" property 
+  stored in separate files from the csv files. This goes in a directory
+  structure::
+
+      <classname>-files/<N>/<designator>
+
+  where ``<designator>`` is the item's ``<classname><id>`` combination.
+  The ``<N>`` value is ``int(<id> / 1000)``.
+
+
+Adding A User From The Command-Line
+-----------------------------------
+
+The ``roundup-admin`` program can create any data you wish to in the
+database. To create a new user, use::
+
+    roundup-admin create user
+
+To figure out what good values might be for some of the fields (eg. Roles)
+you can just display another user::
+
+    roundup-admin list user
+
+(or if you know their username, and it happens to be "richard")::
+
+    roundup-admin find username=richard
+
+then using the user id you get from one of the above commands, you may
+display the user's details::
+
+    roundup-admin display <userid>
+
+
+Running the Servers
+===================
+
+Unix
+----
+
+On Unix systems, use the scripts/server-ctl script to control the
+roundup-server server. Copy it somewhere and edit the variables at the top
+to reflect your specific installation.
+
+
+Windows
+-------
+
+On Windows, the roundup-server program runs as a Windows Service, and 
+therefore may be controlled through the Services control panel. The
+roundup-server program may also control the service directly:
+
+**install the service**
+  ``roundup-server -c install``
+**start the service**
+  ``roundup-server -c start``
+**stop the service**
+  ``roundup-server -c stop``
+
+To bring up the services panel:
+
+Windows 2000 and later
+  Start/Control Panel/Administrative Tools/Services
+Windows NT4
+  Start/Control Panel/Services
+
+Running the Mail Gateway Script
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The mail gateway script should be scheduled to run regularly on your
+Windows server. Normally this will result in a window popping up. The
+solution to this is to:
+
+1. Create a new local account on the Roundup server
+2. Set the scheduled task to run in the context of this user instead
+   of your normal login
+
+
+-------------------
+
+Back to `Table of Contents`_
+
+.. _`Table of Contents`: index.html
+.. _`customisation documentation`: customizing.html
+.. _`upgrading documentation`: upgrading.html
+

Added: tracker/vendor/roundup/current/doc/announcement.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/announcement.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,72 @@
+I'm proud to release version 1.1.2 of Roundup.
+
+Feature:
+
+- server-ctl script uses server configuration file (sf bug 1443805)
+
+Fixed:
+
+- indexing may be turned off for FileClass "content" now
+  ("content" and "type" properties are now automatically included in the
+  FileClass schema where previously the "content" property was faked and
+  "type" was optional)
+- reduced frequency of session timestamp update
+- progress display in roundup-admin reindex
+- bug in menu() permission filter (sf bug 1444440)
+- verbose output during import is optional now (sf bug 1475624)
+- escape *all* uses of "schema" in mysql backend (sf bug 1472120)
+- responses to user rego email (sf bug 1470254)
+- dangling connections in session handling (sf bug 1463359)
+- classhelp popup pagination forgot about "type" (sf bug 1465836)
+- umask is now configurable (with the same 0002 default)
+- sorting of entries in classhelp popup (sf bug 1449000)
+- allow single digit seconds in date spec (sf bug 1447141)
+- prevent generation of new single-digit seconds dates (sf bug 1429390)
+- implement close() on all indexers (sf bug 1242477)
+
+
+If you're upgrading from an older version of Roundup you *must* follow
+the "Software Upgrade" guidelines given in the maintenance documentation.
+
+Roundup requires python 2.3 or later for correct operation.
+
+To give Roundup a try, just download (see below), unpack and run::
+
+    python demo.py
+
+Release info and download page:
+     http://cheeseshop.python.org/pypi/roundup
+Source and documentation is available at the website:
+     http://roundup.sourceforge.net/
+Mailing lists - the place to ask questions:
+     http://sourceforge.net/mail/?group_id=31577
+
+
+About Roundup
+=============
+
+Roundup is a simple-to-use and -install issue-tracking system with
+command-line, web and e-mail interfaces. It is based on the winning design
+from Ka-Ping Yee in the Software Carpentry "Track" design competition.
+
+Note: Ping is not responsible for this project. The contact for this
+project is richard at users.sourceforge.net.
+
+Roundup manages a number of issues (with flexible properties such as
+"description", "priority", and so on) and provides the ability to:
+
+(a) submit new issues,
+(b) find and edit existing issues, and
+(c) discuss issues with other participants.
+
+The system will facilitate communication among the participants by managing
+discussions and notifying interested parties when issues are edited. One of
+the major design goals for Roundup that it be simple to get going. Roundup
+is therefore usable "out of the box" with any python 2.3+ installation. It
+doesn't even need to be "installed" to be operational, though a
+disutils-based install script is provided.
+
+It comes with two issue tracker templates (a classic bug/feature tracker and
+a minimal skeleton) and five database back-ends (anydbm, sqlite, metakit,
+mysql and postgresql).
+

Added: tracker/vendor/roundup/current/doc/customizing.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/customizing.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,4549 @@
+===================
+Customising Roundup
+===================
+
+:Version: $Revision: 1.197 $
+
+.. This document borrows from the ZopeBook section on ZPT. The original is at:
+   http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx
+
+.. contents::
+   :depth: 1
+
+What You Can Do
+===============
+
+Before you get too far, it's probably worth having a quick read of the Roundup
+`design documentation`_.
+
+Customisation of Roundup can take one of six forms:
+
+1. `tracker configuration`_ changes
+2. database, or `tracker schema`_ changes
+3. "definition" class `database content`_ changes
+4. behavioural changes, through detectors_
+5. `security / access controls`_
+6. change the `web interface`_
+
+The third case is special because it takes two distinctly different forms
+depending upon whether the tracker has been initialised or not. The other two
+may be done at any time, before or after tracker initialisation. Yes, this
+includes adding or removing properties from classes.
+
+
+Trackers in a Nutshell
+======================
+
+Trackers have the following structure:
+
+=================== ========================================================
+Tracker File        Description
+=================== ========================================================
+config.ini          Holds the basic `tracker configuration`_                 
+schema.py           Holds the `tracker schema`_                              
+initial_data.py     Holds any data to be entered into the database when the
+                    tracker is initialised.
+db/                 Holds the tracker's database                             
+db/files/           Holds the tracker's upload files and messages            
+db/backend_name     Names the database back-end for the tracker            
+detectors/          Auditors and reactors for this tracker                   
+extensions/         Additional web actions and templating utilities.
+html/               Web interface templates, images and style sheets         
+=================== ======================================================== 
+
+
+Tracker Configuration
+=====================
+
+The ``config.ini`` located in your tracker home contains the basic
+configuration for the web and e-mail components of roundup's interfaces.
+
+Changes to the data captured by your tracker is controlled by the `tracker
+schema`_.  Some configuration is also performed using permissions - see the 
+`security / access controls`_ section. For example, to allow users to
+automatically register through the email interface, you must grant the
+"Anonymous" Role the "Email Access" Permission.
+
+The following is taken from the `Python Library Reference`__ (May 20, 2004)
+section "ConfigParser -- Configuration file parser":
+
+ The configuration file consists of sections, led by a "[section]" header
+ and followed by "name = value" entries, with line continuations on a
+ newline with leading whitespace. Note that leading whitespace is removed
+ from values. The optional values can contain format strings which
+ refer to other values in the same section. Lines beginning with "#" or ";"
+ are ignored and may be used to provide comments. 
+
+ For example::
+
+   [My Section]
+   foodir = %(dir)s/whatever
+   dir = frob
+
+ would resolve the "%(dir)s" to the value of "dir" ("frob" in this case)
+ resulting in "foodir" being "frob/whatever".
+
+__ http://docs.python.org/lib/module-ConfigParser.html
+
+Section **main**
+ database -- ``db``
+  Database directory path. The path may be either absolute or relative
+  to the directory containig this config file.
+
+ templates -- ``html``
+  Path to the HTML templates directory. The path may be either absolute
+  or relative to the directory containig this config file.
+
+ admin_email -- ``roundup-admin``
+  Email address that roundup will complain to if it runs into trouble. If
+  the email address doesn't contain an ``@`` part, the MAIL_DOMAIN defined
+  below is used.
+
+ dispatcher_email -- ``roundup-admin``
+  The 'dispatcher' is a role that can get notified of new items to the
+  database. It is used by the ERROR_MESSAGES_TO config setting. If the
+  email address doesn't contain an ``@`` part, the MAIL_DOMAIN defined
+  below is used.
+
+ email_from_tag -- default *blank*
+  Additional text to include in the "name" part of the From: address used
+  in nosy messages. If the sending user is "Foo Bar", the From: line
+  is usually: ``"Foo Bar" <issue_tracker at tracker.example>``
+  the EMAIL_FROM_TAG goes inside the "Foo Bar" quotes like so:
+  ``"Foo Bar EMAIL_FROM_TAG" <issue_tracker at tracker.example>``
+
+ new_web_user_roles -- ``User``
+  Roles that a user gets when they register with Web User Interface.
+  This is a comma-separated list of role names (e.g. ``Admin,User``).
+
+ new_email_user_roles -- ``User``
+  Roles that a user gets when they register with Email Gateway.
+  This is a comma-separated string of role names (e.g. ``Admin,User``).
+
+ error_messages_to -- ``user``
+  Send error message emails to the ``dispatcher``, ``user``, or ``both``?
+  The dispatcher is configured using the DISPATCHER_EMAIL setting.
+  Allowed values: ``dispatcher``, ``user``, or ``both``
+
+ html_version -- ``html4``
+  HTML version to generate. The templates are ``html4`` by default.
+  If you wish to make them xhtml, then you'll need to change this
+  var to ``xhtml`` too so all auto-generated HTML is compliant.
+  Allowed values: ``html4``, ``xhtml``
+
+ timezone -- ``0``
+  Numeric timezone offset used when users do not choose their own
+  in their settings.
+
+ instant_registration -- ``yes``
+  Register new users instantly, or require confirmation via
+  email?
+  Allowed values: ``yes``, ``no``
+
+ email_registration_confirmation -- ``yes``
+  Offer registration confirmation by email or only through the web?
+  Allowed values: ``yes``, ``no``
+
+ indexer_stopwords -- default *blank*
+  Additional stop-words for the full-text indexer specific to
+  your tracker. See the indexer source for the default list of
+  stop-words (e.g. ``A,AND,ARE,AS,AT,BE,BUT,BY, ...``).
+
+Section **tracker**
+ name -- ``Roundup issue tracker``
+  A descriptive name for your roundup instance.
+
+ web -- ``http://host.example/demo/``
+  The web address that the tracker is viewable at.
+  This will be included in information sent to users of the tracker.
+  The URL MUST include the cgi-bin part or anything else
+  that is required to get to the home page of the tracker.
+  You MUST include a trailing '/' in the URL.
+
+ email -- ``issue_tracker``
+  Email address that mail to roundup should go to.
+
+Section **web**
+ http_auth -- ``yes``
+  Whether to use HTTP Basic Authentication, if present.
+  Roundup will use either the REMOTE_USER or HTTP_AUTHORIZATION
+  variables supplied by your web server (in that order).
+  Set this option to 'no' if you do not wish to use HTTP Basic
+  Authentication in your web interface.
+
+ use_browser_language -- ``yes``
+  Whether to use HTTP Accept-Language, if present.
+  Browsers send a language-region preference list.
+  It's usually set in the client's browser or in their
+  Operating System.
+  Set this option to 'no' if you want to ignore it.
+
+ debug -- ``no``
+  Setting this option makes Roundup display error tracebacks
+  in the user's browser rather than emailing them to the
+  tracker admin."),
+
+Section **rdbms**
+ Settings in this section are used by Postgresql and MySQL backends only
+
+ name -- ``roundup``
+  Name of the database to use.
+
+ host -- ``localhost``
+  Database server host.
+
+ port -- default *blank*
+  TCP port number of the database server. Postgresql usually resides on
+  port 5432 (if any), for MySQL default port number is 3306. Leave this
+  option empty to use backend default.
+
+ user -- ``roundup``
+  Database user name that Roundup should use.
+
+ password -- ``roundup``
+  Database user password.
+
+Section **logging**
+ config -- default *blank*
+  Path to configuration file for standard Python logging module. If this
+  option is set, logging configuration is loaded from specified file;
+  options 'filename' and 'level' in this section are ignored. The path may
+  be either absolute or relative to the directory containig this config file.
+
+ filename -- default *blank*
+  Log file name for minimal logging facility built into Roundup.  If no file
+  name specified, log messages are written on stderr. If above 'config'
+  option is set, this option has no effect. The path may be either absolute
+  or relative to the directory containig this config file.
+
+ level -- ``ERROR``
+  Minimal severity level of messages written to log file. If above 'config'
+  option is set, this option has no effect.
+  Allowed values: ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR``
+
+Section **mail**
+ Outgoing email options. Used for nosy messages, password reset and
+ registration approval requests.
+
+ domain -- ``localhost``
+  Domain name used for email addresses.
+
+ host -- default *blank*
+  SMTP mail host that roundup will use to send mail
+
+ username -- default *blank*
+  SMTP login name. Set this if your mail host requires authenticated access.
+  If username is not empty, password (below) MUST be set!
+
+ password -- default *blank*
+  SMTP login password.
+  Set this if your mail host requires authenticated access.
+
+ tls -- ``no``
+  If your SMTP mail host provides or requires TLS (Transport Layer Security)
+  then you may set this option to 'yes'.
+  Allowed values: ``yes``, ``no``
+
+ tls_keyfile -- default *blank*
+  If TLS is used, you may set this option to the name of a PEM formatted
+  file that contains your private key. The path may be either absolute or
+  relative to the directory containig this config file.
+
+ tls_certfile -- default *blank*
+  If TLS is used, you may set this option to the name of a PEM formatted
+  certificate chain file. The path may be either absolute or relative
+  to the directory containig this config file.
+
+ charset -- utf-8
+  Character set to encode email headers with. We use utf-8 by default, as
+  it's the most flexible. Some mail readers (eg. Eudora) can't cope with
+  that, so you might need to specify a more limited character set
+  (eg. iso-8859-1).
+
+ debug -- default *blank*
+  Setting this option makes Roundup to write all outgoing email messages
+  to this file *instead* of sending them. This option has the same effect
+  as environment variable SENDMAILDEBUG. Environment variable takes
+  precedence. The path may be either absolute or relative to the directory
+  containig this config file.
+
+Section **mailgw**
+ Roundup Mail Gateway options
+
+ keep_quoted_text -- ``yes``
+  Keep email citations when accepting messages. Setting this to ``no`` strips
+  out "quoted" text from the message. Signatures are also stripped.
+  Allowed values: ``yes``, ``no``
+
+ leave_body_unchanged -- ``no``
+  Preserve the email body as is - that is, keep the citations *and*
+  signatures.
+  Allowed values: ``yes``, ``no``
+
+ default_class -- ``issue``
+  Default class to use in the mailgw if one isn't supplied in email subjects.
+  To disable, leave the value blank.
+
+ subject_prefix_parsing -- ``strict``
+  Controls the parsing of the [prefix] on subject lines in incoming emails.
+  ``strict`` will return an error to the sender if the [prefix] is not
+  recognised. ``loose`` will attempt to parse the [prefix] but just
+  pass it through as part of the issue title if not recognised. ``none``
+  will always pass any [prefix] through as part of the issue title.
+
+ subject_suffix_parsing -- ``strict``
+  Controls the parsing of the [suffix] on subject lines in incoming emails.
+  ``strict`` will return an error to the sender if the [suffix] is not
+  recognised. ``loose`` will attempt to parse the [suffix] but just
+  pass it through as part of the issue title if not recognised. ``none``
+  will always pass any [suffix] through as part of the issue title.
+
+ subject_suffix_delimiters -- ``[]``
+  Defines the brackets used for delimiting the commands suffix in a subject
+  line.
+
+ subject_content_match -- ``always``
+  Controls matching of the incoming email subject line against issue titles
+  in the case where there is no designator [prefix]. ``never`` turns off
+  matching. ``creation + interval`` or ``activity + interval`` will match
+  an issue for the interval after the issue's creation or last activity.
+  The interval is a standard Roundup interval.
+
+Section **nosy**
+ Nosy messages sending
+
+ messages_to_author -- ``no``
+  Send nosy messages to the author of the message.
+  Allowed values: ``yes``, ``no``, ``new``
+
+ signature_position -- ``bottom``
+  Where to place the email signature.
+  Allowed values: ``top``, ``bottom``, ``none``
+
+ add_author -- ``new``
+  Does the author of a message get placed on the nosy list automatically?
+  If ``new`` is used, then the author will only be added when a message
+  creates a new issue. If ``yes``, then the author will be added on
+  followups too. If ``no``, they're never added to the nosy.
+  Allowed values: ``yes``, ``no``, ``new``
+  
+ add_recipients -- ``new``
+  Do the recipients (``To:``, ``Cc:``) of a message get placed on the nosy
+  list?  If ``new`` is used, then the recipients will only be added when a
+  message creates a new issue. If ``yes``, then the recipients will be added
+  on followups too. If ``no``, they're never added to the nosy.
+  Allowed values: ``yes``, ``no``, ``new``
+
+ email_sending -- ``single``
+  Controls the email sending from the nosy reactor. If ``multiple`` then
+  a separate email is sent to each recipient. If ``single`` then a single
+  email is sent with each recipient as a CC address.
+
+You may generate a new default config file using the ``roundup-admin
+genconfig`` command.
+
+Configuration variables may be referred to in lower or upper case. In code,
+variables not in the "main" section are referred to using their section and
+name, so "domain" in the section "mail" becomes MAIL_DOMAIN. The
+configuration variables available are:
+
+
+Tracker Schema
+==============
+
+.. note::
+   if you modify the schema, you'll most likely need to edit the
+   `web interface`_ HTML template files and `detectors`_ to reflect
+   your changes.
+
+A tracker schema defines what data is stored in the tracker's database.
+Schemas are defined using Python code in the ``schema.py`` module of your
+tracker.
+
+The ``schema.py`` module
+------------------------
+
+The ``schema.py`` module contains two functions:
+
+**open**
+  This function defines what your tracker looks like on the inside, the
+  **schema** of the tracker. It defines the **Classes** and **properties**
+  on each class. It also defines the **security** for those Classes. The
+  next few sections describe how schemas work and what you can do with
+  them.
+**init**
+  This function is responsible for setting up the initial state of your
+  tracker. It's called exactly once - but the ``roundup-admin initialise``
+  command.  See the start of the section on `database content`_ for more
+  info about how this works.
+
+
+The "classic" schema
+--------------------
+
+The "classic" schema looks like this (see section `setkey(property)`_
+below for the meaning of ``'setkey'`` -- you may also want to look into
+the sections `setlabelprop(property)`_ and `setorderprop(property)`_ for
+specifying (default) labelling and ordering of classes.)::
+
+    pri = Class(db, "priority", name=String(), order=String())
+    pri.setkey("name")
+
+    stat = Class(db, "status", name=String(), order=String())
+    stat.setkey("name")
+
+    keyword = Class(db, "keyword", name=String())
+    keyword.setkey("name")
+
+    user = Class(db, "user", username=String(), organisation=String(),
+        password=String(), address=String(), realname=String(),
+        phone=String())
+    user.setkey("username")
+
+    msg = FileClass(db, "msg", author=Link("user"), summary=String(),
+        date=Date(), recipients=Multilink("user"),
+        files=Multilink("file"))
+
+    file = FileClass(db, "file", name=String(), type=String())
+
+    issue = IssueClass(db, "issue", topic=Multilink("keyword"),
+        status=Link("status"), assignedto=Link("user"),
+        priority=Link("priority"))
+    issue.setkey('title')
+
+
+What you can't do to the schema
+-------------------------------
+
+You must never:
+
+**Remove the users class**
+  This class is the only *required* class in Roundup.
+
+**Remove the "username", "address", "password" or "realname" user properties**
+  Various parts of Roundup require these properties. Don't remove them.
+
+**Change the type of a property**
+  Property types must *never* be changed - the database simply doesn't take
+  this kind of action into account. Note that you can't just remove a
+  property and re-add it as a new type either. If you wanted to make the
+  assignedto property a Multilink, you'd need to create a new property
+  assignedto_list and remove the old assignedto property.
+
+
+What you can do to the schema
+-----------------------------
+
+Your schema may be changed at any time before or after the tracker has been
+initialised (or used). You may:
+
+**Add new properties to classes, or add whole new classes**
+  This is painless and easy to do - there are generally no repurcussions
+  from adding new information to a tracker's schema.
+
+**Remove properties**
+  Removing properties is a little more tricky - you need to make sure that
+  the property is no longer used in the `web interface`_ *or* by the
+  detectors_.
+
+
+
+Classes and Properties - creating a new information store
+---------------------------------------------------------
+
+In the tracker above, we've defined 7 classes of information:
+
+  priority
+      Defines the possible levels of urgency for issues.
+
+  status
+      Defines the possible states of processing the issue may be in.
+
+  keyword
+      Initially empty, will hold keywords useful for searching issues.
+
+  user
+      Initially holding the "admin" user, will eventually have an entry
+      for all users using roundup.
+
+  msg
+      Initially empty, will hold all e-mail messages sent to or
+      generated by roundup.
+
+  file
+      Initially empty, will hold all files attached to issues.
+
+  issue
+      Initially empty, this is where the issue information is stored.
+
+We define the "priority" and "status" classes to allow two things:
+reduction in the amount of information stored on the issue and more
+powerful, accurate searching of issues by priority and status. By only
+requiring a link on the issue (which is stored as a single number) we
+reduce the chance that someone mis-types a priority or status - or
+simply makes a new one up.
+
+
+Class and Items
+~~~~~~~~~~~~~~~
+
+A Class defines a particular class (or type) of data that will be stored
+in the database. A class comprises one or more properties, which gives
+the information about the class items.
+
+The actual data entered into the database, using ``class.create()``, are
+called items. They have a special immutable property called ``'id'``. We
+sometimes refer to this as the *itemid*.
+
+
+Properties
+~~~~~~~~~~
+
+A Class is comprised of one or more properties of the following types:
+
+* String properties are for storing arbitrary-length strings.
+* Password properties are for storing encoded arbitrary-length strings.
+  The default encoding is defined on the ``roundup.password.Password``
+  class.
+* Date properties store date-and-time stamps. Their values are Timestamp
+  objects.
+* Number properties store numeric values.
+* Boolean properties store on/off, yes/no, true/false values.
+* A Link property refers to a single other item selected from a
+  specified class. The class is part of the property; the value is an
+  integer, the id of the chosen item.
+* A Multilink property refers to possibly many items in a specified
+  class. The value is a list of integers.
+
+All Classes automatically have a number of properties by default:
+
+*creator*
+  Link to the user that created the item.
+*creation*
+  Date the item was created.
+*actor*
+  Link to the user that last modified the item.
+*activity*
+  Date the item was last modified.
+
+
+FileClass
+~~~~~~~~~
+
+FileClasses save their "content" attribute off in a separate file from
+the rest of the database. This reduces the number of large entries in
+the database, which generally makes databases more efficient, and also
+allows us to use command-line tools to operate on the files. They are
+stored in the files sub-directory of the ``'db'`` directory in your
+tracker.
+
+
+IssueClass
+~~~~~~~~~~
+
+IssueClasses automatically include the "messages", "files", "nosy", and
+"superseder" properties.
+
+The messages and files properties list the links to the messages and
+files related to the issue. The nosy property is a list of links to
+users who wish to be informed of changes to the issue - they get "CC'ed"
+e-mails when messages are sent to or generated by the issue. The nosy
+reactor (in the ``'detectors'`` directory) handles this action. The
+superseder link indicates an issue which has superseded this one.
+
+They also have the dynamically generated "creation", "activity" and
+"creator" properties.
+
+The value of the "creation" property is the date when an item was
+created, and the value of the "activity" property is the date when any
+property on the item was last edited (equivalently, these are the dates
+on the first and last records in the item's journal). The "creator"
+property holds a link to the user that created the issue.
+
+
+setkey(property)
+~~~~~~~~~~~~~~~~
+
+Select a String property of the class to be the key property. The key
+property must be unique, and allows references to the items in the class
+by the content of the key property. That is, we can refer to users by
+their username: for example, let's say that there's an issue in roundup,
+issue 23. There's also a user, richard, who happens to be user 2. To
+assign an issue to him, we could do either of::
+
+     roundup-admin set issue23 assignedto=2
+
+or::
+
+     roundup-admin set issue23 assignedto=richard
+
+Note, the same thing can be done in the web and e-mail interfaces. 
+
+setlabelprop(property)
+~~~~~~~~~~~~~~~~~~~~~~
+
+Select a property of the class to be the label property. The label
+property is used whereever an item should be uniquely identified, e.g.,
+when displaying a link to an item. If setlabelprop is not specified for
+a class, the following values are tried for the label: 
+
+ * the key of the class (see the `setkey(property)`_ section above)
+ * the "name" property
+ * the "title" property
+ * the first property from the sorted property name list
+
+So in most cases you can get away without specifying setlabelprop
+explicitly.
+
+setorderprop(property)
+~~~~~~~~~~~~~~~~~~~~~~
+
+Select a property of the class to be the order property. The order
+property is used whenever using a default sort order for the class,
+e.g., when grouping or sorting class A by a link to class B in the user
+interface, the order property of class B is used for sorting.  If
+setorderprop is not specified for a class, the following values are tried
+for the order property:
+
+ * the property named "order"
+ * the label property (see `setlabelprop(property)`_ above)
+
+So in most cases you can get away without specifying setorderprop
+explicitly.
+
+create(information)
+~~~~~~~~~~~~~~~~~~~
+
+Create an item in the database. This is generally used to create items
+in the "definitional" classes like "priority" and "status".
+
+
+A note about ordering
+~~~~~~~~~~~~~~~~~~~~~
+
+When we sort items in the hyperdb, we use one of a number of methods,
+depending on the properties being sorted on:
+
+1. If it's a String, Number, Date or Interval property, we just sort the
+   scalar value of the property. Strings are sorted case-sensitively.
+2. If it's a Link property, we sort by either the linked item's "order"
+   property (if it has one) or the linked item's "id".
+3. Mulitlinks sort similar to #2, but we start with the first Multilink
+   list item, and if they're the same, we sort by the second item, and
+   so on.
+
+Note that if an "order" property is defined on a Class that is used for
+sorting, all items of that Class *must* have a value against the "order"
+property, or sorting will result in random ordering.
+
+
+Examples of adding to your schema
+---------------------------------
+
+TODO
+
+
+Detectors - adding behaviour to your tracker
+============================================
+.. _detectors:
+
+Detectors are initialised every time you open your tracker database, so
+you're free to add and remove them any time, even after the database is
+initialised via the ``roundup-admin initialise`` command.
+
+The detectors in your tracker fire *before* (**auditors**) and *after*
+(**reactors**) changes to the contents of your database. They are Python
+modules that sit in your tracker's ``detectors`` directory. You will
+have some installed by default - have a look. You can write new
+detectors or modify the existing ones. The existing detectors installed
+for you are:
+
+**nosyreaction.py**
+  This provides the automatic nosy list maintenance and email sending.
+  The nosy reactor (``nosyreaction``) fires when new messages are added
+  to issues. The nosy auditor (``updatenosy``) fires when issues are
+  changed, and figures out what changes need to be made to the nosy list
+  (such as adding new authors, etc.)
+**statusauditor.py**
+  This provides the ``chatty`` auditor which changes the issue status
+  from ``unread`` or ``closed`` to ``chatting`` if new messages appear.
+  It also provides the ``presetunread`` auditor which pre-sets the
+  status to ``unread`` on new items if the status isn't explicitly
+  defined.
+**messagesummary.py**
+  Generates the ``summary`` property for new messages based on the message
+  content.
+**userauditor.py**
+  Verifies the content of some of the user fields (email addresses and
+  roles lists).
+
+If you don't want this default behaviour, you're completely free to change
+or remove these detectors.
+
+See the detectors section in the `design document`__ for details of the
+interface for detectors.
+
+__ design.html
+
+
+Detector API
+------------
+
+Auditors are called with the arguments::
+
+    audit(db, cl, itemid, newdata)
+
+where ``db`` is the database, ``cl`` is an instance of Class or
+IssueClass within the database, and ``newdata`` is a dictionary mapping
+property names to values.
+
+For a ``create()`` operation, the ``itemid`` argument is None and
+newdata contains all of the initial property values with which the item
+is about to be created.
+
+For a ``set()`` operation, newdata contains only the names and values of
+properties that are about to be changed.
+
+For a ``retire()`` or ``restore()`` operation, newdata is None.
+
+Reactors are called with the arguments::
+
+    react(db, cl, itemid, olddata)
+
+where ``db`` is the database, ``cl`` is an instance of Class or
+IssueClass within the database, and ``olddata`` is a dictionary mapping
+property names to values.
+
+For a ``create()`` operation, the ``itemid`` argument is the id of the
+newly-created item and ``olddata`` is None.
+
+For a ``set()`` operation, ``olddata`` contains the names and previous
+values of properties that were changed.
+
+For a ``retire()`` or ``restore()`` operation, ``itemid`` is the id of
+the retired or restored item and ``olddata`` is None.
+
+
+Additional Detectors Ready For Use
+----------------------------------
+
+Sample additional detectors that have been found useful will appear in
+the ``'detectors'`` directory of the Roundup distribution. If you want
+to use one, copy it to the ``'detectors'`` of your tracker instance:
+
+**newissuecopy.py**
+  This detector sends an email to a team address whenever a new issue is
+  created. The address is hard-coded into the detector, so edit it
+  before you use it (look for the text 'team at team.host') or you'll get
+  email errors!
+**creator_resolution.py**
+  Catch attempts to set the status to "resolved" - if the assignedto
+  user isn't the creator, then set the status to "confirm-done". Note that
+  "classic" Roundup doesn't have that status, so you'll have to add it. If
+  you don't want to though, it'll just use "in-progress" instead.
+**email_auditor.py**
+  If a file added to an issue is of type message/rfc822, we tack on the
+  extension .eml.
+  The reason for this is that Microsoft Internet Explorer will not open
+  things with a .eml attachment, as they deem it 'unsafe'. Worse yet,
+  they'll just give you an incomprehensible error message. For more 
+  information, see the detector code - it has a length explanation.
+
+
+Auditor or Reactor?
+-------------------
+
+Generally speaking, the following rules should be observed:
+
+**Auditors**
+  Are used for `vetoing creation of or changes to items`_. They might
+  also make automatic changes to item properties.
+**Reactors**
+  Detect changes in the database and react accordingly. They should avoid
+  making changes to the database where possible, as this could create
+  detector loops.
+
+
+Vetoing creation of or changes to items
+---------------------------------------
+
+Auditors may raise the ``Reject`` exception to prevent the creation of
+or changes to items in the database.  The mail gateway, for example, will
+not attach files or messages to issues when the creation of those files or
+messages are prevented through the ``Reject`` exception. It'll also not create
+users if that creation is ``Reject``'ed too.
+
+To use, simply add at the top of your auditor::
+
+   from roundup.exceptions import Reject
+
+And then when your rejection criteria have been detected, simply::
+
+   raise Reject
+
+
+Generating email from Roundup
+-----------------------------
+
+The module ``roundup.mailer`` contains most of the nuts-n-bolts required
+to generate email messages from Roundup.
+
+In addition, the ``IssueClass`` methods ``nosymessage()`` and
+``send_message()`` are used to generate nosy messages, and may generate
+messages which only consist of a change note (ie. the message id parameter
+is not required - this is referred to as a "System Message" because it
+comes from "the system" and not a user).
+
+
+Database Content
+================
+
+.. note::
+   if you modify the content of definitional classes, you'll most
+   likely need to edit the tracker `detectors`_ to reflect your changes.
+
+Customisation of the special "definitional" classes (eg. status,
+priority, resolution, ...) may be done either before or after the
+tracker is initialised. The actual method of doing so is completely
+different in each case though, so be careful to use the right one.
+
+**Changing content before tracker initialisation**
+    Edit the initial_data.py module in your tracker to alter the items
+    created using the ``create( ... )`` methods.
+
+**Changing content after tracker initialisation**
+    As the "admin" user, click on the "class list" link in the web
+    interface to bring up a list of all database classes. Click on the
+    name of the class you wish to change the content of.
+
+    You may also use the ``roundup-admin`` interface's create, set and
+    retire methods to add, alter or remove items from the classes in
+    question.
+
+See "`adding a new field to the classic schema`_" for an example that
+requires database content changes.
+
+
+Security / Access Controls
+==========================
+
+A set of Permissions is built into the security module by default:
+
+- Create (everything)
+- Edit (everything)
+- View (everything)
+
+These are assigned to the "Admin" Role by default, and allow a user to do
+anything. Every Class you define in your `tracker schema`_ also gets an
+Create, Edit and View Permission of its own. The web and email interfaces
+also define:
+
+*Email Access*
+  If defined, the user may use the email interface. Used by default to deny
+  Anonymous users access to the email interface. When granted to the
+  Anonymous user, they will be automatically registered by the email
+  interface (see also the ``new_email_user_roles`` configuration option).
+*Web Access*
+  If defined, the user may use the web interface. All users are able to see
+  the login form, regardless of this setting (thus enabling logging in).
+*Web Roles*
+  Controls user access to editing the "roles" property of the "user" class.
+  TODO: deprecate in favour of a property-based control.
+
+These are hooked into the default Roles:
+
+- Admin (Create, Edit, View and everything; Web Roles)
+- User (Web Access; Email Access)
+- Anonymous (Web Access)
+
+And finally, the "admin" user gets the "Admin" Role, and the "anonymous"
+user gets "Anonymous" assigned when the tracker is installed.
+
+For the "User" Role, the "classic" tracker defines:
+
+- Create, Edit and View issue, file, msg, query, keyword 
+- View priority, status
+- View user
+- Edit their own user record
+
+And the "Anonymous" Role is defined as:
+
+- Web interface access
+- Create user (for registration)
+- View issue, file, msg, query, keyword, priority, status
+
+Put together, these settings appear in the tracker's ``schema.py`` file::
+
+    #
+    # TRACKER SECURITY SETTINGS
+    #
+    # See the configuration and customisation document for information
+    # about security setup.
+
+    #
+    # REGULAR USERS
+    #
+    # Give the regular users access to the web and email interface
+    db.security.addPermissionToRole('User', 'Web Access')
+    db.security.addPermissionToRole('User', 'Email Access')
+
+    # Assign the access and edit Permissions for issue, file and message
+    # to regular users now
+    for cl in 'issue', 'file', 'msg', 'query', 'keyword':
+        db.security.addPermissionToRole('User', 'View', cl)
+        db.security.addPermissionToRole('User', 'Edit', cl)
+        db.security.addPermissionToRole('User', 'Create', cl)
+    for cl in 'priority', 'status':
+        db.security.addPermissionToRole('User', 'View', cl)
+
+    # May users view other user information? Comment these lines out
+    # if you don't want them to
+    db.security.addPermissionToRole('User', 'View', 'user')
+
+    # Users should be able to edit their own details -- this permission
+    # is limited to only the situation where the Viewed or Edited item
+    # is their own.
+    def own_record(db, userid, itemid):
+        '''Determine whether the userid matches the item being accessed.'''
+        return userid == itemid
+    p = db.security.addPermission(name='View', klass='user', check=own_record,
+        description="User is allowed to view their own user details")
+    db.security.addPermissionToRole('User', p)
+    p = db.security.addPermission(name='Edit', klass='user', check=own_record,
+        description="User is allowed to edit their own user details")
+    db.security.addPermissionToRole('User', p)
+
+    #
+    # ANONYMOUS USER PERMISSIONS
+    #
+    # Let anonymous users access the web interface. Note that almost all
+    # trackers will need this Permission. The only situation where it's not
+    # required is in a tracker that uses an HTTP Basic Authenticated front-end.
+    db.security.addPermissionToRole('Anonymous', 'Web Access')
+
+    # Let anonymous users access the email interface (note that this implies
+    # that they will be registered automatically, hence they will need the
+    # "Create" user Permission below)
+    # This is disabled by default to stop spam from auto-registering users on
+    # public trackers.
+    #db.security.addPermissionToRole('Anonymous', 'Email Access')
+
+    # Assign the appropriate permissions to the anonymous user's Anonymous
+    # Role. Choices here are:
+    # - Allow anonymous users to register
+    db.security.addPermissionToRole('Anonymous', 'Create', 'user')
+
+    # Allow anonymous users access to view issues (and the related, linked
+    # information)
+    for cl in 'issue', 'file', 'msg', 'keyword', 'priority', 'status':
+        db.security.addPermissionToRole('Anonymous', 'View', cl)
+
+    # [OPTIONAL]
+    # Allow anonymous users access to create or edit "issue" items (and the
+    # related file and message items)
+    #for cl in 'issue', 'file', 'msg':
+    #   db.security.addPermissionToRole('Anonymous', 'Create', cl)
+    #   db.security.addPermissionToRole('Anonymous', 'Edit', cl)
+
+
+Automatic Permission Checks
+---------------------------
+
+Permissions are automatically checked when information is rendered
+through the web. This includes:
+
+1. View checks for properties when being rendered via the ``plain()`` or
+   similar methods. If the check fails, the text "[hidden]" will be
+   displayed.
+2. Edit checks for properties when the edit field is being rendered via
+   the ``field()`` or similar methods. If the check fails, the property
+   will be rendered via the ``plain()`` method (see point 1. for subsequent
+   checking performed)
+3. View checks are performed in index pages for each item being displayed
+   such that if the user does not have permission, the row is not rendered.
+4. View checks are performed at the top of item pages for the Item being
+   displayed. If the user does not have permission, the text "You are not
+   allowed to view this page." will be displayed.
+5. View checks are performed at the top of index pages for the Class being
+   displayed. If the user does not have permission, the text "You are not
+   allowed to view this page." will be displayed.
+
+
+New User Roles
+--------------
+
+New users are assigned the Roles defined in the config file as:
+
+- NEW_WEB_USER_ROLES
+- NEW_EMAIL_USER_ROLES
+
+The `users may only edit their issues`_ example shows customisation of
+these parameters.
+
+
+Changing Access Controls
+------------------------
+
+You may alter the configuration variables to change the Role that new
+web or email users get, for example to not give them access to the web
+interface if they register through email. 
+
+You may use the ``roundup-admin`` "``security``" command to display the
+current Role and Permission configuration in your tracker.
+
+
+Adding a new Permission
+~~~~~~~~~~~~~~~~~~~~~~~
+
+When adding a new Permission, you will need to:
+
+1. add it to your tracker's ``schema.py`` so it is created, using
+   ``security.addPermission``, for example::
+
+    self.security.addPermission(name="View", klass='frozzle',
+        description="User is allowed to access frozzles")
+
+   will set up a new "View" permission on the Class "frozzle".
+2. enable it for the Roles that should have it (verify with
+   "``roundup-admin security``")
+3. add it to the relevant HTML interface templates
+4. add it to the appropriate xxxPermission methods on in your tracker
+   interfaces module
+
+The ``addPermission`` method takes a couple of optional parameters:
+
+**properties**
+  A sequence of property names that are the only properties to apply the
+  new Permission to (eg. ``... klass='user', properties=('name',
+  'email') ...``)
+**check**
+  A function to be execute which returns boolean determining whether the
+  Permission is allowed. The function has the signature ``check(db, userid,
+  itemid)`` where ``db`` is a handle on the open database, ``userid`` is
+  the user attempting access and ``itemid`` is the specific item being
+  accessed.
+
+Example Scenarios
+~~~~~~~~~~~~~~~~~
+
+See the `examples`_ section for longer examples of customisation.
+
+**anonymous access through the e-mail gateway**
+ Give the "anonymous" user the "Email Access", ("Edit", "issue") and
+ ("Create", "msg") Permissions but do not not give them the ("Create",
+ "user") Permission. This means that when an unknown user sends email
+ into the tracker, they're automatically logged in as "anonymous".
+ Since they don't have the ("Create", "user") Permission, they won't
+ be automatically registered, but since "anonymous" has permission to
+ use the gateway, they'll still be able to submit issues. Note that
+ the Sender information - their email address - will not be available
+ - they're *anonymous*.
+
+**automatic registration of users in the e-mail gateway**
+ By giving the "anonymous" user the ("Create", "user" Permission, any
+ unidentified user will automatically be registered with the tracker
+ (with no password, so they won't be able to log in through
+ the web until an admin sets their password). This is the default
+ behaviour in the tracker templates that ship with Roundup. The new user
+ is given the Roles list defined in the "new_email_user_roles" config
+ variable.
+
+**only developers may be assigned issues**
+ Create a new Permission called "Fixer" for the "issue" class. Create a
+ new Role "Developer" which has that Permission, and assign that to the
+ appropriate users. Filter the list of users available in the assignedto
+ list to include only those users. Enforce the Permission with an
+ auditor. See the example 
+ `restricting the list of users that are assignable to a task`_.
+
+**only managers may sign off issues as complete**
+ Create a new Permission called "Closer" for the "issue" class. Create a
+ new Role "Manager" which has that Permission, and assign that to the
+ appropriate users. In your web interface, only display the "resolved"
+ issue state option when the user has the "Closer" Permissions. Enforce
+ the Permission with an auditor. This is very similar to the previous
+ example, except that the web interface check would look like::
+
+   <option tal:condition="python:request.user.hasPermission('Closer')"
+           value="resolved">Resolved</option>
+ 
+**don't give web access to users who register through email**
+ Create a new Role called "Email User" which has all the Permissions of
+ the normal "User" Role minus the "Web Access" Permission. This will
+ allow users to send in emails to the tracker, but not access the web
+ interface.
+
+**let some users edit the details of all users**
+ Create a new Role called "User Admin" which has the Permission for
+ editing users::
+
+    db.security.addRole(name='User Admin', description='Managing users')
+    p = db.security.getPermission('Edit', 'user')
+    db.security.addPermissionToRole('User Admin', p)
+
+ and assign the Role to the users who need the permission.
+
+
+Web Interface
+=============
+
+.. contents::
+   :local:
+
+The web interface is provided by the ``roundup.cgi.client`` module and
+is used by ``roundup.cgi``, ``roundup-server`` and ``ZRoundup``
+(``ZRoundup``  is broken, until further notice). In all cases, we
+determine which tracker is being accessed (the first part of the URL
+path inside the scope of the CGI handler) and pass control on to the
+``roundup.cgi.client.Client`` class - which handles the rest of the
+access through its ``main()`` method. This means that you can do pretty
+much anything you want as a web interface to your tracker.
+
+
+
+Repercussions of changing the tracker schema
+---------------------------------------------
+
+If you choose to change the `tracker schema`_ you will need to ensure
+the web interface knows about it:
+
+1. Index, item and search pages for the relevant classes may need to
+   have properties added or removed,
+2. The "page" template may require links to be changed, as might the
+   "home" page's content arguments.
+
+
+How requests are processed
+--------------------------
+
+The basic processing of a web request proceeds as follows:
+
+1. figure out who we are, defaulting to the "anonymous" user
+2. figure out what the request is for - we call this the "context"
+3. handle any requested action (item edit, search, ...)
+4. render the template requested by the context, resulting in HTML
+   output
+
+In some situations, exceptions occur:
+
+- HTTP Redirect  (generally raised by an action)
+- SendFile       (generally raised by ``determine_context``)
+    here we serve up a FileClass "content" property
+- SendStaticFile (generally raised by ``determine_context``)
+    here we serve up a file from the tracker "html" directory
+- Unauthorised   (generally raised by an action)
+    here the action is cancelled, the request is rendered and an error
+    message is displayed indicating that permission was not granted for
+    the action to take place
+- NotFound       (raised wherever it needs to be)
+    this exception percolates up to the CGI interface that called the
+    client
+
+
+Determining web context
+-----------------------
+
+To determine the "context" of a request, we look at the URL and the
+special request variable ``@template``. The URL path after the tracker
+identifier is examined. Typical URL paths look like:
+
+1.  ``/tracker/issue``
+2.  ``/tracker/issue1``
+3.  ``/tracker/@@file/style.css``
+4.  ``/cgi-bin/roundup.cgi/tracker/file1``
+5.  ``/cgi-bin/roundup.cgi/tracker/file1/kitten.png``
+
+where the "tracker identifier" is "tracker" in the above cases. That means
+we're looking at "issue", "issue1", "@@file/style.css", "file1" and
+"file1/kitten.png" in the cases above. The path is generally only one
+entry long - longer paths are handled differently.
+
+a. if there is no path, then we are in the "home" context. See `the "home"
+   context`_ below for more information about how it may be used.
+b. if the path starts with "@@file" (as in example 3,
+   "/tracker/@@file/style.css"), then the additional path entry,
+   "style.css" specifies the filename of a static file we're to serve up
+   from the tracker TEMPLATES (or STATIC_FILES, if configured) directory.
+   This is usually the tracker's "html" directory. Raises a SendStaticFile
+   exception.
+c. if there is something in the path (as in example 1, "issue"), it
+   identifies the tracker class we're to display.
+d. if the path is an item designator (as in examples 2 and 4, "issue1"
+   and "file1"), then we're to display a specific item.
+e. if the path starts with an item designator and is longer than one
+   entry (as in example 5, "file1/kitten.png"), then we're assumed to be
+   handling an item of a ``FileClass``, and the extra path information
+   gives the filename that the client is going to label the download
+   with (i.e. "file1/kitten.png" is nicer to download than "file1").
+   This raises a ``SendFile`` exception.
+
+Both b. and e. stop before we bother to determine the template we're
+going to use. That's because they don't actually use templates.
+
+The template used is specified by the ``@template`` CGI variable, which
+defaults to:
+
+- only classname suplied:        "index"
+- full item designator supplied: "item"
+
+
+The "home" Context
+------------------
+
+The "home" context is special because it allows you to add templated
+pages to your tracker that don't rely on a class or item (ie. an issues
+list or specific issue).
+
+Let's say you wish to add frames to control the layout of your tracker's
+interface. You'd probably have:
+
+- A top-level frameset page. This page probably wouldn't be templated, so
+  it could be served as a static file (see `serving static content`_)
+- A sidebar frame that is templated. Let's call this page
+  "home.navigation.html" in your tracker's "html" directory. To load that
+  page up, you use the URL:
+
+    <tracker url>/home?@template=navigation
+
+
+Serving static content
+----------------------
+
+See the previous section `determining web context`_ where it describes
+``@@file`` paths.
+
+
+Performing actions in web requests
+----------------------------------
+
+When a user requests a web page, they may optionally also request for an
+action to take place. As described in `how requests are processed`_, the
+action is performed before the requested page is generated. Actions are
+triggered by using a ``@action`` CGI variable, where the value is one
+of:
+
+**login**
+ Attempt to log a user in.
+
+**logout**
+ Log the user out - make them "anonymous".
+
+**register**
+ Attempt to create a new user based on the contents of the form and then
+ log them in.
+
+**edit**
+ Perform an edit of an item in the database. There are some `special form
+ variables`_ you may use.
+
+**new**
+ Add a new item to the database. You may use the same `special form
+ variables`_ as in the "edit" action.
+
+**retire**
+ Retire the item in the database.
+
+**editCSV**
+ Performs an edit of all of a class' items in one go. See also the
+ *class*.csv templating method which generates the CSV data to be
+ edited, and the ``'_generic.index'`` template which uses both of these
+ features.
+
+**search**
+ Mangle some of the form variables:
+
+ - Set the form ":filter" variable based on the values of the filter
+   variables - if they're set to anything other than "dontcare" then add
+   them to :filter.
+
+ - Also handle the ":queryname" variable and save off the query to the
+   user's query list.
+
+Each of the actions is implemented by a corresponding ``*XxxAction*`` (where
+"Xxx" is the name of the action) class in the ``roundup.cgi.actions`` module.
+These classes are registered with ``roundup.cgi.client.Client``. If you need
+to define new actions, you may add them there (see `defining new
+web actions`_).
+
+Each action class also has a ``*permission*`` method which determines whether
+the action is permissible given the current user. The base permission checks
+for each action are:
+
+**login**
+ Determine whether the user has the "Web Access" Permission.
+**logout**
+ No permission checks are made.
+**register**
+ Determine whether the user has the ("Create", "user") Permission.
+**edit**
+ Determine whether the user has permission to edit this item. If we're
+ editing the "user" class, users are allowed to edit their own details -
+ unless they try to edit the "roles" property, which requires the
+ special Permission "Web Roles".
+**new**
+ Determine whether the user has permission to create this item. No
+ additional property checks are made. Additionally, new user items may
+ be created if the user has the ("Create", "user") Permission.
+**editCSV**
+ Determine whether the user has permission to edit this class.
+**search**
+ Determine whether the user has permission to view this class.
+
+
+Special form variables
+----------------------
+
+Item properties and their values are edited with html FORM
+variables and their values. You can:
+
+- Change the value of some property of the current item.
+- Create a new item of any class, and edit the new item's
+  properties,
+- Attach newly created items to a multilink property of the
+  current item.
+- Remove items from a multilink property of the current item.
+- Specify that some properties are required for the edit
+  operation to be successful.
+- Set up user interface locale.
+
+These operations will only take place if the form action (the
+``@action`` variable) is "edit" or "new".
+
+In the following, <bracketed> values are variable, "@" may be
+either ":" or "@", and other text "required" is fixed.
+
+Two special form variables are used to specify user language preferences:
+
+``@language``
+  value may be locale name or ``none``. If this variable is set to
+  locale name, web interface language is changed to given value
+  (provided that appropriate translation is available), the value
+  is stored in the browser cookie and will be used for all following
+  requests.  If value is ``none`` the cookie is removed and the
+  language is changed to the tracker default, set up in the tracker
+  configuration or OS environment.
+
+``@charset``
+  value may be character set name or ``none``.  Character set name
+  is stored in the browser cookie and sets output encoding for all
+  HTML pages generated by Roundup.  If value is ``none`` the cookie
+  is removed and HTML output is reset to Roundup internal encoding
+  (UTF-8).
+
+Most properties are specified as form variables:
+
+``<propname>``
+  property on the current context item
+
+``<designator>"@"<propname>``
+  property on the indicated item (for editing related information)
+
+Designators name a specific item of a class.
+
+``<classname><N>``
+    Name an existing item of class <classname>.
+
+``<classname>"-"<N>``
+    Name the <N>th new item of class <classname>. If the form
+    submission is successful, a new item of <classname> is
+    created. Within the submitted form, a particular
+    designator of this form always refers to the same new
+    item.
+
+Once we have determined the "propname", we look at it to see
+if it's special:
+
+``@required``
+    The associated form value is a comma-separated list of
+    property names that must be specified when the form is
+    submitted for the edit operation to succeed.  
+
+    When the <designator> is missing, the properties are
+    for the current context item.  When <designator> is
+    present, they are for the item specified by
+    <designator>.
+
+    The "@required" specifier must come before any of the
+    properties it refers to are assigned in the form.
+
+``@remove@<propname>=id(s)`` or ``@add@<propname>=id(s)``
+    The "@add@" and "@remove@" edit actions apply only to
+    Multilink properties.  The form value must be a
+    comma-separate list of keys for the class specified by
+    the simple form variable.  The listed items are added
+    to (respectively, removed from) the specified
+    property.
+
+``@link@<propname>=<designator>``
+    If the edit action is "@link@", the simple form
+    variable must specify a Link or Multilink property.
+    The form value is a comma-separated list of
+    designators.  The item corresponding to each
+    designator is linked to the property given by simple
+    form variable.
+
+None of the above (ie. just a simple form value)
+    The value of the form variable is converted
+    appropriately, depending on the type of the property.
+
+    For a Link('klass') property, the form value is a
+    single key for 'klass', where the key field is
+    specified in schema.py.  
+
+    For a Multilink('klass') property, the form value is a
+    comma-separated list of keys for 'klass', where the
+    key field is specified in schema.py.  
+
+    Note that for simple-form-variables specifiying Link
+    and Multilink properties, the linked-to class must
+    have a key field.
+
+    For a String() property specifying a filename, the
+    file named by the form value is uploaded. This means we
+    try to set additional properties "filename" and "type" (if
+    they are valid for the class).  Otherwise, the property
+    is set to the form value.
+
+    For Date(), Interval(), Boolean(), and Number()
+    properties, the form value is converted to the
+    appropriate
+
+Any of the form variables may be prefixed with a classname or
+designator.
+
+Two special form values are supported for backwards compatibility:
+
+ at note
+    This is equivalent to::
+
+        @link at messages=msg-1
+        msg-1 at content=value
+
+    except that in addition, the "author" and "date" properties of
+    "msg-1" are set to the userid of the submitter, and the current
+    time, respectively.
+
+ at file
+    This is equivalent to::
+
+        @link at files=file-1
+        file-1 at content=value
+
+    The String content value is handled as described above for file
+    uploads.
+
+If both the "@note" and "@file" form variables are
+specified, the action::
+
+        @link at msg-1@files=file-1
+
+is also performed.
+
+We also check that FileClass items have a "content" property with
+actual content, otherwise we remove them from all_props before
+returning.
+
+
+Default templates
+-----------------
+
+The default templates are html4 compliant. If you wish to change them to be
+xhtml compliant, you'll need to change the ``html_version`` configuration
+variable in ``config.ini`` to ``'xhtml'`` instead of ``'html4'``.
+
+Most customisation of the web view can be done by modifying the
+templates in the tracker ``'html'`` directory. There are several types
+of files in there. The *minimal* template includes:
+
+**page.html**
+  This template usually defines the overall look of your tracker. When
+  you view an issue, it appears inside this template. When you view an
+  index, it also appears inside this template. This template defines a
+  macro called "icing" which is used by almost all other templates as a
+  coating for their content, using its "content" slot. It also defines
+  the "head_title" and "body_title" slots to allow setting of the page
+  title.
+**home.html**
+  the default page displayed when no other page is indicated by the user
+**home.classlist.html**
+  a special version of the default page that lists the classes in the
+  tracker
+**classname.item.html**
+  displays an item of the *classname* class
+**classname.index.html**
+  displays a list of *classname* items
+**classname.search.html**
+  displays a search page for *classname* items
+**_generic.index.html**
+  used to display a list of items where there is no
+  ``*classname*.index`` available
+**_generic.help.html**
+  used to display a "class help" page where there is no
+  ``*classname*.help``
+**user.register.html**
+  a special page just for the user class, that renders the registration
+  page
+**style.css.html**
+  a static file that is served up as-is
+
+The *classic* template has a number of additional templates.
+
+Remember that you can create any template extension you want to,
+so if you just want to play around with the templating for new issues,
+you can copy the current "issue.item" template to "issue.test", and then
+access the test template using the "@template" URL argument::
+
+   http://your.tracker.example/tracker/issue?@template=test
+
+and it won't affect your users using the "issue.item" template.
+
+
+How the templates work
+----------------------
+
+
+Basic Templating Actions
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Roundup's templates consist of special attributes on the HTML tags.
+These attributes form the `Template Attribute Language`_, or TAL.
+The basic TAL commands are:
+
+**tal:define="variable expression; variable expression; ..."**
+   Define a new variable that is local to this tag and its contents. For
+   example::
+
+      <html tal:define="title request/description">
+       <head><title tal:content="title"></title></head>
+      </html>
+
+   In this example, the variable "title" is defined as the result of the
+   expression "request/description". The "tal:content" command inside the
+   <html> tag may then use the "title" variable.
+
+**tal:condition="expression"**
+   Only keep this tag and its contents if the expression is true. For
+   example::
+
+     <p tal:condition="python:request.user.hasPermission('View', 'issue')">
+      Display some issue information.
+     </p>
+
+   In the example, the <p> tag and its contents are only displayed if
+   the user has the "View" permission for issues. We consider 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!).
+
+**tal:repeat="variable expression"**
+   Repeat this tag and its contents for each element of the sequence
+   that the expression returns, defining a new local variable and a
+   special "repeat" variable for each element. For example::
+
+     <tr tal:repeat="u user/list">
+      <td tal:content="u/id"></td>
+      <td tal:content="u/username"></td>
+      <td tal:content="u/realname"></td>
+     </tr>
+
+   The example would iterate over the sequence of users returned by
+   "user/list" and define the local variable "u" for each entry. Using
+   the repeat command creates a new variable called "repeat" which you
+   may access to gather information about the iteration. See the section
+   below on `the repeat variable`_.
+
+**tal:replace="expression"**
+   Replace this tag with the result of the expression. For example::
+
+    <span tal:replace="request/user/realname" />
+
+   The example would replace the <span> tag and its contents with the
+   user's realname. If the user's realname was "Bruce", then the
+   resultant output would be "Bruce".
+
+**tal:content="expression"**
+   Replace the contents of this tag with the result of the expression.
+   For example::
+
+    <span tal:content="request/user/realname">user's name appears here
+    </span>
+
+   The example would replace the contents of the <span> tag with the
+   user's realname. If the user's realname was "Bruce" then the
+   resultant output would be "<span>Bruce</span>".
+
+**tal:attributes="attribute expression; attribute expression; ..."**
+   Set attributes on this tag to the results of expressions. For
+   example::
+
+     <a tal:attributes="href string:user${request/user/id}">My Details</a>
+
+   In the example, the "href" attribute of the <a> tag is set to the
+   value of the "string:user${request/user/id}" expression, which will
+   be something like "user123".
+
+**tal:omit-tag="expression"**
+   Remove this tag (but not its contents) if the expression is true. For
+   example::
+
+      <span tal:omit-tag="python:1">Hello, world!</span>
+
+   would result in output of::
+
+      Hello, world!
+
+Note that the commands on a given tag are evaulated in the order above,
+so *define* comes before *condition*, and so on.
+
+Additionally, you may include tags such as <tal:block>, which are
+removed from output. Its content is kept, but the tag itself is not (so
+don't go using any "tal:attributes" commands on it). This is useful for
+making arbitrary blocks of HTML conditional or repeatable (very handy
+for repeating multiple table rows, which would othewise require an
+illegal tag placement to effect the repeat).
+
+.. _TAL:
+.. _Template Attribute Language:
+   http://dev.zope.org/Wikis/DevSite/Projects/ZPT/TAL%20Specification%201.4
+
+
+Templating Expressions
+~~~~~~~~~~~~~~~~~~~~~~
+
+Templating Expressions are covered by `Template Attribute Language
+Expression Syntax`_, or TALES. The expressions you may use in the
+attribute values may be one of the following forms:
+
+**Path Expressions** - eg. ``item/status/checklist``
+   These are object attribute / item accesses. Roughly speaking, the
+   path ``item/status/checklist`` is broken into parts ``item``,
+   ``status`` and ``checklist``. The ``item`` part is the root of the
+   expression. We then look for a ``status`` attribute on ``item``, or
+   failing that, a ``status`` item (as in ``item['status']``). If that
+   fails, the path expression fails. When we get to the end, the object
+   we're left with is evaluated to get a string - if it is a method, it
+   is called; if it is an object, it is stringified. Path expressions
+   may have an optional ``path:`` prefix, but they are the default
+   expression type, so it's not necessary.
+
+   If an expression evaluates to ``default``, then the expression is
+   "cancelled" - whatever HTML already exists in the template will
+   remain (tag content in the case of ``tal:content``, attributes in the
+   case of ``tal:attributes``).
+
+   If an expression evaluates to ``nothing`` then the target of the
+   expression is removed (tag content in the case of ``tal:content``,
+   attributes in the case of ``tal:attributes`` and the tag itself in
+   the case of ``tal:replace``).
+
+   If an element in the path may not exist, then you can use the ``|``
+   operator in the expression to provide an alternative. So, the
+   expression ``request/form/foo/value | default`` would simply leave
+   the current HTML in place if the "foo" form variable doesn't exist.
+
+   You may use the python function ``path``, as in
+   ``path("item/status")``, to embed path expressions in Python
+   expressions.
+
+**String Expressions** - eg. ``string:hello ${user/name}`` 
+   These expressions are simple string interpolations - though they can
+   be just plain strings with no interpolation if you want. The
+   expression in the ``${ ... }`` is just a path expression as above.
+
+**Python Expressions** - eg. ``python: 1+1`` 
+   These expressions give the full power of Python. All the "root level"
+   variables are available, so ``python:item.status.checklist()`` would
+   be equivalent to ``item/status/checklist``, assuming that
+   ``checklist`` is a method.
+
+Modifiers:
+
+**structure** - eg. ``structure python:msg.content.plain(hyperlink=1)``
+   The result of expressions are normally *escaped* to be safe for HTML
+   display (all "<", ">" and "&" are turned into special entities). The
+   ``structure`` expression modifier turns off this escaping - the
+   result of the expression is now assumed to be HTML, which is passed
+   to the web browser for rendering.
+
+**not:** - eg. ``not:python:1=1``
+   This simply inverts the logical true/false value of another
+   expression.
+
+.. _TALES:
+.. _Template Attribute Language Expression Syntax:
+   http://dev.zope.org/Wikis/DevSite/Projects/ZPT/TALES%20Specification%201.3
+
+
+Template Macros
+~~~~~~~~~~~~~~~
+
+Macros are used in Roundup to save us from repeating the same common
+page stuctures over and over. The most common (and probably only) macro
+you'll use is the "icing" macro defined in the "page" template.
+
+Macros are generated and used inside your templates using special
+attributes similar to the `basic templating actions`_. In this case,
+though, the attributes belong to the `Macro Expansion Template
+Attribute Language`_, or METAL. The macro commands are:
+
+**metal:define-macro="macro name"**
+  Define that the tag and its contents are now a macro that may be
+  inserted into other templates using the *use-macro* command. For
+  example::
+
+    <html metal:define-macro="page">
+     ...
+    </html>
+
+  defines a macro called "page" using the ``<html>`` tag and its
+  contents. Once defined, macros are stored on the template they're
+  defined on in the ``macros`` attribute. You can access them later on
+  through the ``templates`` variable, eg. the most common
+  ``templates/page/macros/icing`` to access the "page" macro of the
+  "page" template.
+
+**metal:use-macro="path expression"**
+  Use a macro, which is identified by the path expression (see above).
+  This will replace the current tag with the identified macro contents.
+  For example::
+
+   <tal:block metal:use-macro="templates/page/macros/icing">
+    ...
+   </tal:block>
+
+   will replace the tag and its contents with the "page" macro of the
+   "page" template.
+
+**metal:define-slot="slot name"** and **metal:fill-slot="slot name"**
+  To define *dynamic* parts of the macro, you define "slots" which may
+  be filled when the macro is used with a *use-macro* command. For
+  example, the ``templates/page/macros/icing`` macro defines a slot like
+  so::
+
+    <title metal:define-slot="head_title">title goes here</title>
+
+  In your *use-macro* command, you may now use a *fill-slot* command
+  like this::
+
+    <title metal:fill-slot="head_title">My Title</title>
+
+  where the tag that fills the slot completely replaces the one defined
+  as the slot in the macro.
+
+Note that you may not mix `METAL`_ and `TAL`_ commands on the same tag, but
+TAL commands may be used freely inside METAL-using tags (so your
+*fill-slots* tags may have all manner of TAL inside them).
+
+.. _METAL:
+.. _Macro Expansion Template Attribute Language:
+   http://dev.zope.org/Wikis/DevSite/Projects/ZPT/METAL%20Specification%201.0
+
+Information available to templates
+----------------------------------
+
+This is implemented by ``roundup.cgi.templating.RoundupPageTemplate``
+
+The following variables are available to templates.
+
+**context**
+  The current context. This is either None, a `hyperdb class wrapper`_
+  or a `hyperdb item wrapper`_
+**request**
+  Includes information about the current request, including:
+   - the current index information (``filterspec``, ``filter`` args,
+     ``properties``, etc) parsed out of the form. 
+   - methods for easy filterspec link generation
+   - *user*, the current user item as an HTMLItem instance
+   - *form*
+     The current CGI form information as a mapping of form argument name
+     to value
+**config**
+  This variable holds all the values defined in the tracker config.ini
+  file (eg. TRACKER_NAME, etc.)
+**db**
+  The current database, used to access arbitrary database items.
+**templates**
+  Access to all the tracker templates by name. Used mainly in
+  *use-macro* commands.
+**utils**
+  This variable makes available some utility functions like batching.
+**nothing**
+  This is a special variable - if an expression evaluates to this, then
+  the tag (in the case of a ``tal:replace``), its contents (in the case
+  of ``tal:content``) or some attributes (in the case of
+  ``tal:attributes``) will not appear in the the output. So, for
+  example::
+
+    <span tal:attributes="class nothing">Hello, World!</span>
+
+  would result in::
+
+    <span>Hello, World!</span>
+
+**default**
+  Also a special variable - if an expression evaluates to this, then the
+  existing HTML in the template will not be replaced or removed, it will
+  remain. So::
+
+    <span tal:replace="default">Hello, World!</span>
+
+  would result in::
+
+    <span>Hello, World!</span>
+
+**true**, **false**
+  Boolean constants that may be used in `templating expressions`_
+  instead of ``python:1`` and ``python:0``.
+**i18n**
+  Internationalization service, providing two string translation methods:
+
+  **gettext** (*message*)
+    Return the localized translation of message
+  **ngettext** (*singular*, *plural*, *number*)
+    Like ``gettext()``, but consider plural forms. If a translation
+    is found, apply the plural formula to *number*, and return the
+    resulting message (some languages have more than two plural forms).
+    If no translation is found, return singular if *number* is 1;
+    return plural otherwise.
+
+    This function requires python2.3; in earlier python versions
+    may not work as expected.
+
+The context variable
+~~~~~~~~~~~~~~~~~~~~
+
+The *context* variable is one of three things based on the current
+context (see `determining web context`_ for how we figure this out):
+
+1. if we're looking at a "home" page, then it's None
+2. if we're looking at a specific hyperdb class, it's a
+   `hyperdb class wrapper`_.
+3. if we're looking at a specific hyperdb item, it's a
+   `hyperdb item wrapper`_.
+
+If the context is not None, we can access the properties of the class or
+item. The only real difference between cases 2 and 3 above are:
+
+1. the properties may have a real value behind them, and this will
+   appear if the property is displayed through ``context/property`` or
+   ``context/property/field``.
+2. the context's "id" property will be a false value in the second case,
+   but a real, or true value in the third. Thus we can determine whether
+   we're looking at a real item from the hyperdb by testing
+   "context/id".
+
+Hyperdb class wrapper
+:::::::::::::::::::::
+
+This is implemented by the ``roundup.cgi.templating.HTMLClass``
+class.
+
+This wrapper object provides access to a hyperb class. It is used
+primarily in both index view and new item views, but it's also usable
+anywhere else that you wish to access information about a class, or the
+items of a class, when you don't have a specific item of that class in
+mind.
+
+We allow access to properties. There will be no "id" property. The value
+accessed through the property will be the current value of the same name
+from the CGI form.
+
+There are several methods available on these wrapper objects:
+
+=========== =============================================================
+Method      Description
+=========== =============================================================
+properties  return a `hyperdb property wrapper`_ for all of this class's
+            properties.
+list        lists all of the active (not retired) items in the class.
+csv         return the items of this class as a chunk of CSV text.
+propnames   lists the names of the properties of this class.
+filter      lists of items from this class, filtered and sorted. Two
+            options are avaible for sorting:
+
+            1. by the current *request* filterspec/filter/sort/group args
+            2. by the "filterspec", "sort" and "group" keyword args.
+               "filterspec" is ``{propname: value(s)}``. "sort" and
+               "group" are ``(dir, prop)`` where dir is '+', '-' or None
+               and prop is a prop name or None.
+
+            eg. ``issue.filter(filterspec={"priority": "1"},
+            sort=('activity', '+'))``
+
+classhelp   display a link to a javascript popup containing this class'
+            "help" template.
+
+            This generates a link to a popup window which displays the
+            properties indicated by "properties" of the class named by
+            "classname". The "properties" should be a comma-separated list
+            (eg. 'id,name,description'). Properties defaults to all the
+            properties of a class (excluding id, creator, created and
+            activity).
+
+            You may optionally override the "label" displayed, the "width",
+            the "height", the number of items per page ("pagesize") and
+            the field on which the list is sorted ("sort").
+
+            With the "filter" arg it is possible to specify a filter for
+            which items are supposed to be displayed. It has to be of
+            the format "<field>=<values>;<field>=<values>;...".
+
+            The popup window will be resizable and scrollable.
+
+            If the "property" arg is given, it's passed through to the
+            javascript help_window function. This allows updating of a
+            property in the calling HTML page.
+
+            If the "form" arg is given, it's passed through to the
+            javascript help_window function - it's the name of the form
+            the "property" belongs to.
+
+submit      generate a submit button (and action hidden element)
+renderWith  render this class with the given template.
+history     returns 'New node - no history' :)
+is_edit_ok  is the user allowed to Edit the current class?
+is_view_ok  is the user allowed to View the current class?
+=========== =============================================================
+
+Note that if you have a property of the same name as one of the above
+methods, you'll need to access it using a python "item access"
+expression. For example::
+
+   python:context['list']
+
+will access the "list" property, rather than the list method.
+
+
+Hyperdb item wrapper
+::::::::::::::::::::
+
+This is implemented by the ``roundup.cgi.templating.HTMLItem``
+class.
+
+This wrapper object provides access to a hyperb item.
+
+We allow access to properties. There will be no "id" property. The value
+accessed through the property will be the current value of the same name
+from the CGI form.
+
+There are several methods available on these wrapper objects:
+
+=============== ========================================================
+Method          Description
+=============== ========================================================
+submit          generate a submit button (and action hidden element)
+journal         return the journal of the current item (**not
+                implemented**)
+history         render the journal of the current item as HTML
+renderQueryForm specific to the "query" class - render the search form
+                for the query
+hasPermission   specific to the "user" class - determine whether the
+                user has a Permission. The signature is::
+
+                    hasPermission(self, permission, [classname=],
+                        [property=], [itemid=])
+
+                where the classname defaults to the current context.
+hasRole         specific to the "user" class - determine whether the
+                user has a Role. The signature is::
+
+                    hasRole(self, rolename)
+
+is_edit_ok      is the user allowed to Edit the current item?
+is_view_ok      is the user allowed to View the current item?
+is_retired      is the item retired?
+download_url    generate a url-quoted link for download of FileClass
+                item contents (ie. file<id>/<name>)
+copy_url        generate a url-quoted link for creating a copy
+                of this item.  By default, the copy will acquire
+                all properties of the current item except for
+                ``messages`` and ``files``.  This can be overridden
+                by passing ``exclude`` argument which contains a list
+                (or any iterable) of property names that shall not be
+                copied.  Database-driven properties like ``id`` or
+                ``activity`` cannot be copied.
+=============== ========================================================
+
+Note that if you have a property of the same name as one of the above
+methods, you'll need to access it using a python "item access"
+expression. For example::
+
+   python:context['journal']
+
+will access the "journal" property, rather than the journal method.
+
+
+Hyperdb property wrapper
+::::::::::::::::::::::::
+
+This is implemented by subclasses of the
+``roundup.cgi.templating.HTMLProperty`` class (``HTMLStringProperty``,
+``HTMLNumberProperty``, and so on).
+
+This wrapper object provides access to a single property of a class. Its
+value may be either:
+
+1. if accessed through a `hyperdb item wrapper`_, then it's a value from
+   the hyperdb
+2. if access through a `hyperdb class wrapper`_, then it's a value from
+   the CGI form
+
+
+The property wrapper has some useful attributes:
+
+=============== ========================================================
+Attribute       Description
+=============== ========================================================
+_name           the name of the property
+_value          the value of the property if any - this is the actual
+                value retrieved from the hyperdb for this property
+=============== ========================================================
+
+There are several methods available on these wrapper objects:
+
+=========== ================================================================
+Method      Description
+=========== ================================================================
+plain       render a "plain" representation of the property. This method
+            may take two arguments:
+
+            escape
+             If true, escape the text so it is HTML safe (default: no). The
+             reason this defaults to off is that text is usually escaped
+             at a later stage by the TAL commands, unless the "structure"
+             option is used in the template. The following ``tal:content``
+             expressions are all equivalent::
+ 
+              "structure python:msg.content.plain(escape=1)"
+              "python:msg.content.plain()"
+              "msg/content/plain"
+              "msg/content"
+
+             Usually you'll only want to use the escape option in a
+             complex expression.
+
+            hyperlink
+             If true, turn URLs, email addresses and hyperdb item
+             designators in the text into hyperlinks (default: no). Note
+             that you'll need to use the "structure" TAL option if you
+             want to use this ``tal:content`` expression::
+  
+              "structure python:msg.content.plain(hyperlink=1)"
+
+             The text is automatically HTML-escaped before the hyperlinking
+             transformation done in the plain() method.
+
+hyperlinked The same as msg.content.plain(hyperlink=1), but nicer::
+
+              "structure msg/content/hyperlinked"
+
+field       render an appropriate form edit field for the property - for
+            most types this is a text entry box, but for Booleans it's a
+            tri-state yes/no/neither selection. This method may take some
+            arguments:
+
+            size
+              Sets the width in characters of the edit field
+
+            format (Date properties only)
+              Sets the format of the date in the field - uses the same
+              format string argument as supplied to the ``pretty`` method
+              below.
+
+stext       only on String properties - render the value of the property
+            as StructuredText (requires the StructureText module to be
+            installed separately)
+multiline   only on String properties - render a multiline form edit
+            field for the property
+email       only on String properties - render the value of the property
+            as an obscured email address
+confirm     only on Password properties - render a second form edit field
+            for the property, used for confirmation that the user typed
+            the password correctly. Generates a field with name
+            "name:confirm".
+now         only on Date properties - return the current date as a new
+            property
+reldate     only on Date properties - render the interval between the date
+            and now
+local       only on Date properties - return this date as a new property
+            with some timezone offset, for example::
+            
+                python:context.creation.local(10)
+
+            will render the date with a +10 hour offset.
+pretty      Date properties - render the date as "dd Mon YYYY" (eg. "19
+            Mar 2004"). Takes an optional format argument, for example::
+
+                python:context.activity.pretty('%Y-%m-%d')
+
+            Will format as "2004-03-19" instead.
+
+            Interval properties - render the interval in a pretty
+            format (eg. "yesterday"). The format arguments are those used
+            in the standard ``strftime`` call (see the `Python Library
+            Reference: time module`__)
+popcal      Generate a link to a popup calendar which may be used to
+            edit the date field, for example::
+
+              <span tal:replace="structure context/due/popcal" />
+
+menu        only on Link and Multilink properties - render a form select
+            list for this property. Takes a number of optional arguments
+
+            size
+               is used to limit the length of the list labels
+            height
+               is used to set the <select> tag's "size" attribute
+            showid
+               includes the item ids in the list labels
+            additional
+               lists properties which should be included in the label
+            sort_on
+                indicates the property to sort the list on as (direction,
+                (direction, property) where direction is '+' or '-'. A
+                single string with the direction prepended may be used.
+                For example: ('-', 'order'), '+name'.
+            value
+                gives a default value to preselect in the menu
+
+            The remaining keyword arguments are used as conditions for
+            filtering the items in the list - they're passed as the
+            "filterspec" argument to a Class.filter() call. For example::
+
+             <span tal:replace="structure context/status/menu" />
+
+             <span tal:replace="python:context.status.menu(order='+name",
+                                   value='chatting', 
+                                   filterspec={'status': '1,2,3,4'}" />
+
+sorted      only on Multilink properties - produce a list of the linked
+            items sorted by some property, for example::
+            
+                python:context.files.sorted('creation')
+
+            Will list the files by upload date.
+reverse     only on Multilink properties - produce a list of the linked
+            items in reverse order
+isset       returns True if the property has been set to a value
+=========== ================================================================
+
+__ http://docs.python.org/lib/module-time.html
+
+All of the above functions perform checks for permissions required to
+display or edit the data they are manipulating. The simplest case is
+editing an issue title. Including the expression::
+
+   context/title/field
+
+Will present the user with an edit field, if they have edit permission. If
+not, then they will be presented with a static display if they have view
+permission. If they don't even have view permission, then an error message
+is raised, preventing the display of the page, indicating that they don't
+have permission to view the information.
+
+
+The request variable
+~~~~~~~~~~~~~~~~~~~~
+
+This is implemented by the ``roundup.cgi.templating.HTMLRequest``
+class.
+
+The request variable is packed with information about the current
+request.
+
+.. taken from ``roundup.cgi.templating.HTMLRequest`` docstring
+
+=========== ============================================================
+Variable    Holds
+=========== ============================================================
+form        the CGI form as a cgi.FieldStorage
+env         the CGI environment variables
+base        the base URL for this tracker
+user        a HTMLUser instance for this user
+classname   the current classname (possibly None)
+template    the current template (suffix, also possibly None)
+form        the current CGI form variables in a FieldStorage
+=========== ============================================================
+
+**Index page specific variables (indexing arguments)**
+
+=========== ============================================================
+Variable    Holds
+=========== ============================================================
+columns     dictionary of the columns to display in an index page
+show        a convenience access to columns - request/show/colname will
+            be true if the columns should be displayed, false otherwise
+sort        index sort column (direction, column name)
+group       index grouping property (direction, column name)
+filter      properties to filter the index on
+filterspec  values to filter the index on
+search_text text to perform a full-text search on for an index
+=========== ============================================================
+
+There are several methods available on the request variable:
+
+=============== ========================================================
+Method          Description
+=============== ========================================================
+description     render a description of the request - handle for the
+                page title
+indexargs_form  render the current index args as form elements
+indexargs_url   render the current index args as a URL
+base_javascript render some javascript that is used by other components
+                of the templating
+batch           run the current index args through a filter and return a
+                list of items (see `hyperdb item wrapper`_, and
+                `batching`_)
+=============== ========================================================
+
+The form variable
+:::::::::::::::::
+
+The form variable is a bit special because it's actually a python
+FieldStorage object. That means that you have two ways to access its
+contents. For example, to look up the CGI form value for the variable
+"name", use the path expression::
+
+   request/form/name/value
+
+or the python expression::
+
+   python:request.form['name'].value
+
+Note the "item" access used in the python case, and also note the
+explicit "value" attribute we have to access. That's because the form
+variables are stored as MiniFieldStorages. If there's more than one
+"name" value in the form, then the above will break since
+``request/form/name`` is actually a *list* of MiniFieldStorages. So it's
+best to know beforehand what you're dealing with.
+
+
+The db variable
+~~~~~~~~~~~~~~~
+
+This is implemented by the ``roundup.cgi.templating.HTMLDatabase``
+class.
+
+Allows access to all hyperdb classes as attributes of this variable. If
+you want access to the "user" class, for example, you would use::
+
+  db/user
+  python:db.user
+
+Also, the current id of the current user is available as
+``db.getuid()``. This isn't so useful in templates (where you have
+``request/user``), but it can be useful in detectors or interfaces.
+
+The access results in a `hyperdb class wrapper`_.
+
+
+The templates variable
+~~~~~~~~~~~~~~~~~~~~~~
+
+This is implemented by the ``roundup.cgi.templating.Templates``
+class.
+
+This variable doesn't have any useful methods defined. It supports being
+used in expressions to access the templates, and consequently the
+template macros. You may access the templates using the following path
+expression::
+
+   templates/name
+
+or the python expression::
+
+   templates[name]
+
+where "name" is the name of the template you wish to access. The
+template has one useful attribute, namely "macros". To access a specific
+macro (called "macro_name"), use the path expression::
+
+   templates/name/macros/macro_name
+
+or the python expression::
+
+   templates[name].macros[macro_name]
+
+The repeat variable
+~~~~~~~~~~~~~~~~~~~
+
+The repeat variable holds an entry for each active iteration. That is, if
+you have a ``tal:repeat="user db/users"`` command, then there will be a
+repeat variable entry called "user". This may be accessed as either::
+
+    repeat/user
+    python:repeat['user']
+
+The "user" entry has a number of methods available for information:
+
+=============== =========================================================
+Method          Description
+=============== =========================================================
+first           True if the current item is the first in the sequence.
+last            True if the current item is the last in the sequence.
+even            True if the current item is an even item in the sequence.
+odd             True if the current item is an odd item in the sequence.
+number          Current position in the sequence, starting from 1.
+letter          Current position in the sequence as a letter, a through
+                z, then aa through zz, and so on.
+Letter          Same as letter(), except uppercase.
+roman           Current position in the sequence as lowercase roman
+                numerals.
+Roman           Same as roman(), except uppercase.
+=============== =========================================================
+
+
+The utils variable
+~~~~~~~~~~~~~~~~~~
+
+This is implemented by the
+``roundup.cgi.templating.TemplatingUtils`` class, but it may be extended
+as described below.
+
+=============== ========================================================
+Method          Description
+=============== ========================================================
+Batch           return a batch object using the supplied list
+url_quote       quote some text as safe for a URL (ie. space, %, ...)
+html_quote      quote some text as safe in HTML (ie. <, >, ...)
+html_calendar   renders an HTML calendar used by the
+                ``_generic.calendar.html`` template (itself invoked by
+                the popupCalendar DateHTMLProperty method
+=============== ========================================================
+
+You may add additional utility methods by writing them in your tracker
+``extensions`` directory and registering them with the templating system
+using ``instance.registerUtil`` (see `adding a time log to your issues`_ for
+an example of this).
+
+
+Batching
+::::::::
+
+Use Batch to turn a list of items, or item ids of a given class, into a
+series of batches. Its usage is::
+
+    python:utils.Batch(sequence, size, start, end=0, orphan=0,
+    overlap=0)
+
+or, to get the current index batch::
+
+    request/batch
+
+The parameters are:
+
+========= ==============================================================
+Parameter  Usage
+========= ==============================================================
+sequence  a list of HTMLItems
+size      how big to make the sequence.
+start     where to start (0-indexed) in the sequence.
+end       where to end (0-indexed) in the sequence.
+orphan    if the next batch would contain less items than this value,
+          then it is combined with this batch
+overlap   the number of items shared between adjacent batches
+========= ==============================================================
+
+All of the parameters are assigned as attributes on the batch object. In
+addition, it has several more attributes:
+
+=============== ========================================================
+Attribute       Description
+=============== ========================================================
+start           indicates the start index of the batch. *Unlike
+                the argument, is a 1-based index (I know, lame)*
+first           indicates the start index of the batch *as a 0-based
+                index*
+length          the actual number of elements in the batch
+sequence_length the length of the original, unbatched, sequence.
+=============== ========================================================
+
+And several methods:
+
+=============== ========================================================
+Method          Description
+=============== ========================================================
+previous        returns a new Batch with the previous batch settings
+next            returns a new Batch with the next batch settings
+propchanged     detect if the named property changed on the current item
+                when compared to the last item
+=============== ========================================================
+
+An example of batching::
+
+ <table class="otherinfo">
+  <tr><th colspan="4" class="header">Existing Keywords</th></tr>
+  <tr tal:define="keywords db/keyword/list"
+      tal:repeat="start python:range(0, len(keywords), 4)">
+   <td tal:define="batch python:utils.Batch(keywords, 4, start)"
+       tal:repeat="keyword batch" tal:content="keyword/name">
+       keyword here</td>
+  </tr>
+ </table>
+
+... which will produce a table with four columns containing the items of
+the "keyword" class (well, their "name" anyway).
+
+
+Displaying Properties
+---------------------
+
+Properties appear in the user interface in three contexts: in indices,
+in editors, and as search arguments. For each type of property, there
+are several display possibilities. For example, in an index view, a
+string property may just be printed as a plain string, but in an editor
+view, that property may be displayed in an editable field.
+
+
+Index Views
+-----------
+
+This is one of the class context views. It is also the default view for
+classes. The template used is "*classname*.index".
+
+
+Index View Specifiers
+~~~~~~~~~~~~~~~~~~~~~
+
+An index view specifier (URL fragment) looks like this (whitespace has
+been added for clarity)::
+
+    /issue?status=unread,in-progress,resolved&
+        topic=security,ui&
+        @group=priority&
+        @sort=-activity&
+        @filters=status,topic&
+        @columns=title,status,fixer
+
+The index view is determined by two parts of the specifier: the layout
+part and the filter part. The layout part consists of the query
+parameters that begin with colons, and it determines the way that the
+properties of selected items are displayed. The filter part consists of
+all the other query parameters, and it determines the criteria by which
+items are selected for display. The filter part is interactively
+manipulated with the form widgets displayed in the filter section. The
+layout part is interactively manipulated by clicking on the column
+headings in the table.
+
+The filter part selects the union of the sets of items with values
+matching any specified Link properties and the intersection of the sets
+of items with values matching any specified Multilink properties.
+
+The example specifies an index of "issue" items. Only items with a
+"status" of either "unread" or "in-progress" or "resolved" are
+displayed, and only items with "topic" values including both "security"
+and "ui" are displayed. The items are grouped by priority, arranged in
+ascending order; and within groups, sorted by activity, arranged in
+descending order. The filter section shows filters for the "status" and
+"topic" properties, and the table includes columns for the "title",
+"status", and "fixer" properties.
+
+============ =============================================================
+Argument     Description
+============ =============================================================
+ at sort        sort by prop name, optionally preceeded with '-' to give
+             descending or nothing for ascending sorting.
+ at group       group by prop name, optionally preceeded with '-' or to sort
+             in descending or nothing for ascending order.
+ at columns     selects the columns that should be displayed. Default is
+             all.                     
+ at filter      indicates which properties are being used in filtering.
+             Default is none.
+propname     selects the values the item properties given by propname must
+             have (very basic search/filter).
+ at search_text if supplied, performs a full-text search (message bodies,
+             issue titles, etc)
+============ =============================================================
+
+
+Searching Views
+---------------
+
+.. note::
+   if you add a new column to the ``@columns`` form variable potentials
+   then you will need to add the column to the appropriate `index views`_
+   template so that it is actually displayed.
+
+This is one of the class context views. The template used is typically
+"*classname*.search". The form on this page should have "search" as its
+``@action`` variable. The "search" action:
+
+- sets up additional filtering, as well as performing indexed text
+  searching
+- sets the ``@filter`` variable correctly
+- saves the query off if ``@query_name`` is set.
+
+The search page should lay out any fields that you wish to allow the
+user to search on. If your schema contains a large number of properties,
+you should be wary of making all of those properties available for
+searching, as this can cause confusion. If the additional properties are
+Strings, consider having their value indexed, and then they will be
+searchable using the full text indexed search. This is both faster, and
+more useful for the end user.
+
+If the search view does specify the "search" ``@action``, then it may also
+provide an additional argument:
+
+============ =============================================================
+Argument     Description
+============ =============================================================
+ at query_name  if supplied, the index parameters (including @search_text)
+             will be saved off as a the query item and registered against
+             the user's queries property. Note that the *classic* template
+             schema has this ability, but the *minimal* template schema
+             does not.
+============ =============================================================
+
+
+Item Views
+----------
+
+The basic view of a hyperdb item is provided by the "*classname*.item"
+template. It generally has three sections; an "editor", a "spool" and a
+"history" section.
+
+
+Editor Section
+~~~~~~~~~~~~~~
+
+The editor section is used to manipulate the item - it may be a static
+display if the user doesn't have permission to edit the item.
+
+Here's an example of a basic editor template (this is the default
+"classic" template issue item edit form - from the "issue.item.html"
+template)::
+
+ <table class="form">
+ <tr>
+  <th>Title</th>
+  <td colspan="3" tal:content="structure python:context.title.field(size=60)">title</td>
+ </tr>
+ 
+ <tr>
+  <th>Priority</th>
+  <td tal:content="structure context/priority/menu">priority</td>
+  <th>Status</th>
+  <td tal:content="structure context/status/menu">status</td>
+ </tr>
+ 
+ <tr>
+  <th>Superseder</th>
+  <td>
+   <span tal:replace="structure python:context.superseder.field(showid=1, size=20)" />
+   <span tal:replace="structure python:db.issue.classhelp('id,title')" />
+   <span tal:condition="context/superseder">
+    <br>View: <span tal:replace="structure python:context.superseder.link(showid=1)" />
+   </span>
+  </td>
+  <th>Nosy List</th>
+  <td>
+   <span tal:replace="structure context/nosy/field" />
+   <span tal:replace="structure python:db.user.classhelp('username,realname,address,phone')" />
+  </td>
+ </tr>
+ 
+ <tr>
+  <th>Assigned To</th>
+  <td tal:content="structure context/assignedto/menu">
+   assignedto menu
+  </td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+ </tr>
+ 
+ <tr>
+  <th>Change Note</th>
+  <td colspan="3">
+   <textarea name=":note" wrap="hard" rows="5" cols="60"></textarea>
+  </td>
+ </tr>
+ 
+ <tr>
+  <th>File</th>
+  <td colspan="3"><input type="file" name=":file" size="40"></td>
+ </tr>
+ 
+ <tr>
+  <td>&nbsp;</td>
+  <td colspan="3" tal:content="structure context/submit">
+   submit button will go here
+  </td>
+ </tr>
+ </table>
+
+
+When a change is submitted, the system automatically generates a message
+describing the changed properties. As shown in the example, the editor
+template can use the ":note" and ":file" fields, which are added to the
+standard changenote message generated by Roundup.
+
+
+Form values
+:::::::::::
+
+We have a number of ways to pull properties out of the form in order to
+meet the various needs of:
+
+1. editing the current item (perhaps an issue item)
+2. editing information related to the current item (eg. messages or
+   attached files)
+3. creating new information to be linked to the current item (eg. time
+   spent on an issue)
+
+In the following, ``<bracketed>`` values are variable, ":" may be one of
+":" or "@", and other text ("required") is fixed.
+
+Properties are specified as form variables:
+
+``<propname>``
+  property on the current context item
+
+``<designator>:<propname>``
+  property on the indicated item (for editing related information)
+
+``<classname>-<N>:<propname>``
+  property on the Nth new item of classname (generally for creating new
+  items to attach to the current item)
+
+Once we have determined the "propname", we check to see if it is one of
+the special form values:
+
+``@required``
+  The named property values must be supplied or a ValueError will be
+  raised.
+
+``@remove@<propname>=id(s)``
+  The ids will be removed from the multilink property.
+
+``:add:<propname>=id(s)``
+  The ids will be added to the multilink property.
+
+``:link:<propname>=<designator>``
+  Used to add a link to new items created during edit. These are
+  collected and returned in ``all_links``. This will result in an
+  additional linking operation (either Link set or Multilink append)
+  after the edit/create is done using ``all_props`` in ``_editnodes``.
+  The <propname> on the current item will be set/appended the id of the
+  newly created item of class <designator> (where <designator> must be
+  <classname>-<N>).
+
+Any of the form variables may be prefixed with a classname or
+designator.
+
+Two special form values are supported for backwards compatibility:
+
+``:note``
+  create a message (with content, author and date), linked to the
+  context item. This is ALWAYS designated "msg-1".
+``:file``
+  create a file, attached to the current item and any message created by
+  :note. This is ALWAYS designated "file-1".
+
+
+Spool Section
+~~~~~~~~~~~~~
+
+The spool section lists related information like the messages and files
+of an issue.
+
+TODO
+
+
+History Section
+~~~~~~~~~~~~~~~
+
+The final section displayed is the history of the item - its database
+journal. This is generally generated with the template::
+
+ <tal:block tal:replace="structure context/history" />
+
+*To be done:*
+
+*The actual history entries of the item may be accessed for manual
+templating through the "journal" method of the item*::
+
+ <tal:block tal:repeat="entry context/journal">
+  a journal entry
+ </tal:block>
+
+*where each journal entry is an HTMLJournalEntry.*
+
+
+Defining new web actions
+------------------------
+
+You may define new actions to be triggered by the ``@action`` form variable.
+These are added to the tracker ``extensions`` directory and registered
+using ``instance.registerAction``.
+
+All the existing Actions are defined in ``roundup.cgi.actions``.
+
+Adding action classes takes three steps; first you `define the new
+action class`_, then you `register the action class`_ with the cgi
+interface so it may be triggered by the ``@action`` form variable.
+Finally you `use the new action`_ in your HTML form.
+
+See "`setting up a "wizard" (or "druid") for controlled adding of
+issues`_" for an example.
+
+
+Define the new action class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Create a new action class in your tracker's ``extensions`` directory, for
+example ``myaction.py``::
+
+ from roundup.cgi.actions import Action
+
+ class MyAction(Action):
+     def handle(self):
+         ''' Perform some action. No return value is required.
+         '''
+
+The *self.client* attribute is an instance of ``roundup.cgi.client.Client``.
+See the docstring of that class for details of what it can do.
+
+The method will typically check the ``self.form`` variable's contents.
+It may then:
+
+- add information to ``self.client.ok_message`` or ``self.client.error_message``
+- change the ``self.client.template`` variable to alter what the user will see
+  next
+- raise Unauthorised, SendStaticFile, SendFile, NotFound or Redirect
+  exceptions (import them from roundup.cgi.exceptions)
+
+
+Register the action class
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The class is now written, but isn't available to the user until you register
+it with the following code appended to your ``myaction.py`` file::
+
+    def init(instance):
+        instance.registerAction('myaction', myActionClass)
+
+This maps the action name "myaction" to the action class we defined.
+
+
+Use the new action
+~~~~~~~~~~~~~~~~~~
+
+In your HTML form, add a hidden form element like so::
+
+  <input type="hidden" name="@action" value="myaction">
+
+where "myaction" is the name you registered in the previous step.
+
+Actions may return content to the user
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Actions generally perform some database manipulation and then pass control
+on to the rendering of a template in the current context (see `Determining
+web context`_ for how that works.) Some actions will want to generate the
+actual content returned to the user. Action methods may return their own
+content string to be displayed to the user, overriding the templating step.
+In this situation, we assume that the content is HTML by default. You may
+override the content type indicated to the user by calling ``setHeader``::
+
+   self.client.setHeader('Content-Type', 'text/csv')
+
+This example indicates that the value sent back to the user is actually
+comma-separated value content (eg. something to be loaded into a
+spreadsheet or database).
+
+
+8-bit character set support in Web interface
+--------------------------------------------
+
+The web interface uses UTF-8 default. It may be overridden in both forms
+and a browser cookie.
+
+- In forms, use the ``@charset`` variable.
+- To use the cookie override, have the ``roundup_charset`` cookie set.
+
+In both cases, the value is a valid charset name (eg. ``utf-8`` or
+``kio8-r``).
+
+Inside Roundup, all strings are stored and processed in utf-8.
+Unfortunately, some older browsers do not work properly with
+utf-8-encoded pages (e.g. Netscape Navigator 4 displays wrong
+characters in form fields).  This version allows one to change
+the character set for http transfers.  To do so, you may add
+the following code to your ``page.html`` template::
+
+ <tal:block define="uri string:${request/base}${request/env/PATH_INFO}">
+  <a tal:attributes="href python:request.indexargs_url(uri,
+   {'@charset':'utf-8'})">utf-8</a>
+  <a tal:attributes="href python:request.indexargs_url(uri,
+   {'@charset':'koi8-r'})">koi8-r</a>
+ </tal:block>
+
+(substitute ``koi8-r`` with appropriate charset for your language).
+Charset preference is kept in the browser cookie ``roundup_charset``.
+
+``meta http-equiv`` lines added to the tracker templates in version 0.6.0
+should be changed to include actual character set name::
+
+ <meta http-equiv="Content-Type"
+  tal:attributes="content string:text/html;; charset=${request/client/charset}"
+ />
+
+The charset is also sent in the http header.
+
+
+Examples
+========
+
+.. contents::
+   :local:
+   :depth: 2
+
+
+Changing what's stored in the database
+--------------------------------------
+
+The following examples illustrate ways to change the information stored in
+the database.
+
+
+Adding a new field to the classic schema
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows how to add a simple field (a due date) to the default
+classic schema. It does not add any additional behaviour, such as enforcing
+the due date, or causing automatic actions to fire if the due date passes.
+
+You add new fields by editing the ``schema.py`` file in you tracker's home.
+Schema changes are automatically applied to the database on the next
+tracker access (note that roundup-server would need to be restarted as it
+caches the schema).
+
+1. modify the schema::
+
+    issue = IssueClass(db, "issue", 
+                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    priority=Link("priority"), status=Link("status"),
+                    due_date=Date())
+
+2. add an edit field to the issue.item.html template::
+
+    <tr> 
+     <th>Due Date</th> 
+     <td tal:content="structure context/due_date/field" /> 
+    </tr> 
+
+3. add the property to the issue.index.html page::
+
+    (in the heading row)
+      <th tal:condition="request/show/due_date">Due Date</th>
+    (in the data row)
+      <td tal:condition="request/show/due_date" tal:content="i/due_date" />
+
+4. add the property to the issue.search.html page::
+
+     <tr tal:define="name string:due_date">
+       <th i18n:translate="">Due Date:</th>
+       <td metal:use-macro="search_input"></td>
+       <td metal:use-macro="column_input"></td>
+       <td metal:use-macro="sort_input"></td>
+       <td metal:use-macro="group_input"></td>
+     </tr>
+
+
+Adding a new constrained field to the classic schema
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows how to add a new constrained property (i.e. a
+selection of distinct values) to your tracker.
+
+
+Introduction
+::::::::::::
+
+To make the classic schema of Roundup useful as a TODO tracking system
+for a group of systems administrators, it needs an extra data field per
+issue: a category.
+
+This would let sysadmins quickly list all TODOs in their particular area
+of interest without having to do complex queries, and without relying on
+the spelling capabilities of other sysadmins (a losing proposition at
+best).
+
+
+Adding a field to the database
+::::::::::::::::::::::::::::::
+
+This is the easiest part of the change. The category would just be a
+plain string, nothing fancy. To change what is in the database you need
+to add some lines to the ``schema.py`` file of your tracker instance.
+Under the comment::
+
+    # add any additional database schema configuration here
+
+add::
+
+    category = Class(db, "category", name=String())
+    category.setkey("name")
+
+Here we are setting up a chunk of the database which we are calling
+"category". It contains a string, which we are refering to as "name" for
+lack of a more imaginative title. (Since "name" is one of the properties
+that Roundup looks for on items if you do not set a key for them, it's
+probably a good idea to stick with it for new classes if at all
+appropriate.) Then we are setting the key of this chunk of the database
+to be that "name". This is equivalent to an index for database types.
+This also means that there can only be one category with a given name.
+
+Adding the above lines allows us to create categories, but they're not
+tied to the issues that we are going to be creating. It's just a list of
+categories off on its own, which isn't much use. We need to link it in
+with the issues. To do that, find the lines 
+in ``schema.py`` which set up the "issue" class, and then add a link to
+the category::
+
+    issue = IssueClass(db, "issue", ... ,
+        category=Multilink("category"), ... )
+
+The ``Multilink()`` means that each issue can have many categories. If
+you were adding something with a one-to-one relationship to issues (such
+as the "assignedto" property), use ``Link()`` instead.
+
+That is all you need to do to change the schema. The rest of the effort
+is fiddling around so you can actually use the new category.
+
+
+Populating the new category class
+:::::::::::::::::::::::::::::::::
+
+If you haven't initialised the database with the ``roundup-admin``
+"initialise" command, then you can add the following to the tracker
+``initial_data.py`` under the comment::
+
+    # add any additional database creation steps here - but only if you
+    # haven't initialised the database with the admin "initialise" command
+
+Add::
+
+     category = db.getclass('category')
+     category.create(name="scipy")
+     category.create(name="chaco")
+     category.create(name="weave")
+
+If the database has already been initalised, then you need to use the
+``roundup-admin`` tool::
+
+     % roundup-admin -i <tracker home>
+     Roundup <version> ready for input.
+     Type "help" for help.
+     roundup> create category name=scipy
+     1
+     roundup> create category name=chaco
+     2
+     roundup> create category name=weave
+     3
+     roundup> exit...
+     There are unsaved changes. Commit them (y/N)? y
+
+
+Setting up security on the new objects
+::::::::::::::::::::::::::::::::::::::
+
+By default only the admin user can look at and change objects. This
+doesn't suit us, as we want any user to be able to create new categories
+as required, and obviously everyone needs to be able to view the
+categories of issues for it to be useful.
+
+We therefore need to change the security of the category objects. This
+is also done in ``schema.py``.
+
+There are currently two loops which set up permissions and then assign
+them to various roles. Simply add the new "category" to both lists::
+
+    # Assign the access and edit permissions for issue, file and message
+    # to regular users now
+    for cl in 'issue', 'file', 'msg', 'category':
+        p = db.security.getPermission('View', cl)
+        db.security.addPermissionToRole('User', 'View', cl)
+        db.security.addPermissionToRole('User', 'Edit', cl)
+        db.security.addPermissionToRole('User', 'Create', cl)
+
+These lines assign the "View" and "Edit" Permissions to the "User" role,
+so that normal users can view and edit "category" objects.
+
+This is all the work that needs to be done for the database. It will
+store categories, and let users view and edit them. Now on to the
+interface stuff.
+
+
+Changing the web left hand frame
+::::::::::::::::::::::::::::::::
+
+We need to give the users the ability to create new categories, and the
+place to put the link to this functionality is in the left hand function
+bar, under the "Issues" area. The file that defines how this area looks
+is ``html/page.html``, which is what we are going to be editing next.
+
+If you look at this file you can see that it contains a lot of
+"classblock" sections which are chunks of HTML that will be included or
+excluded in the output depending on whether the condition in the
+classblock is met. We are going to add the category code at the end of
+the classblock for the *issue* class::
+
+  <p class="classblock"
+     tal:condition="python:request.user.hasPermission('View', 'category')">
+   <b>Categories</b><br>
+   <a tal:condition="python:request.user.hasPermission('Edit', 'category')"
+      href="category?@template=item">New Category<br></a>
+  </p>
+
+The first two lines is the classblock definition, which sets up a
+condition that only users who have "View" permission for the "category"
+object will have this section included in their output. Next comes a
+plain "Categories" header in bold. Everyone who can view categories will
+get that.
+
+Next comes the link to the editing area of categories. This link will
+only appear if the condition - that the user has "Edit" permissions for
+the "category" objects - is matched. If they do have permission then
+they will get a link to another page which will let the user add new
+categories.
+
+Note that if you have permission to *view* but not to *edit* categories,
+then all you will see is a "Categories" header with nothing underneath
+it. This is obviously not very good interface design, but will do for
+now. I just claim that it is so I can add more links in this section
+later on. However, to fix the problem you could change the condition in
+the classblock statement, so that only users with "Edit" permission
+would see the "Categories" stuff.
+
+
+Setting up a page to edit categories
+::::::::::::::::::::::::::::::::::::
+
+We defined code in the previous section which let users with the
+appropriate permissions see a link to a page which would let them edit
+conditions. Now we have to write that page.
+
+The link was for the *item* template of the *category* object. This
+translates into Roundup looking for a file called ``category.item.html``
+in the ``html`` tracker directory. This is the file that we are going to
+write now.
+
+First, we add an info tag in a comment which doesn't affect the outcome
+of the code at all, but is useful for debugging. If you load a page in a
+browser and look at the page source, you can see which sections come
+from which files by looking for these comments::
+
+    <!-- category.item -->
+
+Next we need to add in the METAL macro stuff so we get the normal page
+trappings::
+
+ <tal:block metal:use-macro="templates/page/macros/icing">
+  <title metal:fill-slot="head_title">Category editing</title>
+  <td class="page-header-top" metal:fill-slot="body_title">
+   <h2>Category editing</h2>
+  </td>
+  <td class="content" metal:fill-slot="content">
+
+Next we need to setup up a standard HTML form, which is the whole
+purpose of this file. We link to some handy javascript which sends the
+form through only once. This is to stop users hitting the send button
+multiple times when they are impatient and thus having the form sent
+multiple times::
+
+    <form method="POST" onSubmit="return submit_once()"
+          enctype="multipart/form-data">
+
+Next we define some code which sets up the minimum list of fields that
+we require the user to enter. There will be only one field - "name" - so
+they better put something in it, otherwise the whole form is pointless::
+
+    <input type="hidden" name="@required" value="name">
+
+To get everything to line up properly we will put everything in a table,
+and put a nice big header on it so the user has an idea what is
+happening::
+
+    <table class="form">
+     <tr><th class="header" colspan="2">Category</th></tr>
+
+Next, we need the field into which the user is going to enter the new
+category. The ``context.name.field(size=60)`` bit tells Roundup to
+generate a normal HTML field of size 60, and the contents of that field
+will be the "name" variable of the current context (namely "category").
+The upshot of this is that when the user types something in
+to the form, a new category will be created with that name::
+
+    <tr>
+     <th>Name</th>
+     <td tal:content="structure python:context.name.field(size=60)">
+     name</td>
+    </tr>
+
+Then a submit button so that the user can submit the new category::
+
+    <tr>
+     <td>&nbsp;</td>
+     <td colspan="3" tal:content="structure context/submit">
+      submit button will go here
+     </td>
+    </tr>
+
+Finally we finish off the tags we used at the start to do the METAL
+stuff::
+
+  </td>
+ </tal:block>
+
+So putting it all together, and closing the table and form we get::
+
+ <!-- category.item -->
+ <tal:block metal:use-macro="templates/page/macros/icing">
+  <title metal:fill-slot="head_title">Category editing</title>
+  <td class="page-header-top" metal:fill-slot="body_title">
+   <h2>Category editing</h2>
+  </td>
+  <td class="content" metal:fill-slot="content">
+   <form method="POST" onSubmit="return submit_once()"
+         enctype="multipart/form-data">
+
+    <table class="form">
+     <tr><th class="header" colspan="2">Category</th></tr>
+
+     <tr>
+      <th>Name</th>
+      <td tal:content="structure python:context.name.field(size=60)">
+      name</td>
+     </tr>
+
+     <tr>
+      <td>
+        &nbsp;
+        <input type="hidden" name="@required" value="name"> 
+      </td>
+      <td colspan="3" tal:content="structure context/submit">
+       submit button will go here
+      </td>
+     </tr>
+    </table>
+   </form>
+  </td>
+ </tal:block>
+
+This is quite a lot to just ask the user one simple question, but there
+is a lot of setup for basically one line (the form line) to do its work.
+To add another field to "category" would involve one more line (well,
+maybe a few extra to get the formatting correct).
+
+
+Adding the category to the issue
+::::::::::::::::::::::::::::::::
+
+We now have the ability to create issues to our heart's content, but
+that is pointless unless we can assign categories to issues.  Just like
+the ``html/category.item.html`` file was used to define how to add a new
+category, the ``html/issue.item.html`` is used to define how a new issue
+is created.
+
+Just like ``category.issue.html``, this file defines a form which has a
+table to lay things out. It doesn't matter where in the table we add new
+stuff, it is entirely up to your sense of aesthetics::
+
+   <th>Category</th>
+   <td>
+    <span tal:replace="structure context/category/field" />
+    <span tal:replace="structure python:db.category.classhelp('name',
+                property='category', width='200')" />
+   </td>
+
+First, we define a nice header so that the user knows what the next
+section is, then the middle line does what we are most interested in.
+This ``context/category/field`` gets replaced by a field which contains
+the category in the current context (the current context being the new
+issue).
+
+The classhelp lines generate a link (labelled "list") to a popup window
+which contains the list of currently known categories.
+
+
+Searching on categories
+:::::::::::::::::::::::
+
+Now we can add categories, and create issues with categories. The next
+obvious thing that we would like to be able to do, would be to search
+for issues based on their category, so that, for example, anyone working
+on the web server could look at all issues in the category "Web".
+
+If you look for "Search Issues" in the ``html/page.html`` file, you will
+find that it looks something like 
+``<a href="issue?@template=search">Search Issues</a>``. This shows us
+that when you click on "Search Issues" it will be looking for a
+``issue.search.html`` file to display. So that is the file that we will
+change.
+
+If you look at this file it should begin to seem familiar, although it
+does use some new macros. You can add the new category search code anywhere you
+like within that form::
+
+  <tr tal:define="name string:category;
+                  db_klass string:category;
+                  db_content string:name;">
+    <th>Priority:</th>
+    <td metal:use-macro="search_select"></td>
+    <td metal:use-macro="column_input"></td>
+    <td metal:use-macro="sort_input"></td>
+    <td metal:use-macro="group_input"></td>
+  </tr>
+
+The definitions in the ``<tr>`` opening tag are used by the macros:
+
+- ``search_select`` expands to a drop-down box with all categories using
+  ``db_klass`` and ``db_content``.
+- ``column_input`` expands to a checkbox for selecting what columns
+  should be displayed.
+- ``sort_input`` expands to a radio button for selecting what property
+  should be sorted on.
+- ``group_input`` expands to a radio button for selecting what property
+  should be grouped on.
+
+The category search code above would expand to the following::
+
+  <tr>
+    <th>Category:</th>
+    <td>
+      <select name="category">
+        <option value="">don't care</option>
+        <option value="">------------</option>      
+        <option value="1">scipy</option>
+        <option value="2">chaco</option>
+        <option value="3">weave</option>
+      </select>
+    </td>
+    <td><input type="checkbox" name=":columns" value="category"></td>
+    <td><input type="radio" name=":sort" value="category"></td>
+    <td><input type="radio" name=":group" value="category"></td>
+  </tr>
+
+Adding category to the default view
+:::::::::::::::::::::::::::::::::::
+
+We can now add categories, add issues with categories, and search for
+issues based on categories. This is everything that we need to do;
+however, there is some more icing that we would like. I think the
+category of an issue is important enough that it should be displayed by
+default when listing all the issues.
+
+Unfortunately, this is a bit less obvious than the previous steps. The
+code defining how the issues look is in ``html/issue.index.html``. This
+is a large table with a form down at the bottom for redisplaying and so
+forth. 
+
+Firstly we need to add an appropriate header to the start of the table::
+
+    <th tal:condition="request/show/category">Category</th>
+
+The *condition* part of this statement is to avoid displaying the
+Category column if the user has selected not to see it.
+
+The rest of the table is a loop which will go through every issue that
+matches the display criteria. The loop variable is "i" - which means
+that every issue gets assigned to "i" in turn.
+
+The new part of code to display the category will look like this::
+
+    <td tal:condition="request/show/category"
+        tal:content="i/category"></td>
+
+The condition is the same as above: only display the condition when the
+user hasn't asked for it to be hidden. The next part is to set the
+content of the cell to be the category part of "i" - the current issue.
+
+Finally we have to edit ``html/page.html`` again. This time, we need to
+tell it that when the user clicks on "Unassigned Issues" or "All Issues",
+the category column should be included in the resulting list. If you
+scroll down the page file, you can see the links with lots of options.
+The option that we are interested in is the ``:columns=`` one which
+tells roundup which fields of the issue to display. Simply add
+"category" to that list and it all should work.
+
+Adding a time log to your issues
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We want to log the dates and amount of time spent working on issues, and
+be able to give a summary of the total time spent on a particular issue.
+
+1. Add a new class to your tracker ``schema.py``::
+
+    # storage for time logging
+    timelog = Class(db, "timelog", period=Interval())
+
+   Note that we automatically get the date of the time log entry
+   creation through the standard property "creation".
+
+2. Link to the new class from your issue class (again, in
+   ``schema.py``)::
+
+    issue = IssueClass(db, "issue", 
+                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    priority=Link("priority"), status=Link("status"),
+                    times=Multilink("timelog"))
+
+   the "times" property is the new link to the "timelog" class.
+
+3. We'll need to let people add in times to the issue, so in the web
+   interface we'll have a new entry field. This is a special field
+   because unlike the other fields in the ``issue.item`` template, it
+   affects a different item (a timelog item) and not the template's
+   item (an issue). We have a special syntax for form fields that affect
+   items other than the template default item (see the cgi 
+   documentation on `special form variables`_). In particular, we add a
+   field to capture a new timelog item's period::
+
+    <tr> 
+     <th>Time Log</th> 
+     <td colspan=3><input type="text" name="timelog-1 at period" /> 
+      <br />(enter as '3y 1m 4d 2:40:02' or parts thereof) 
+     </td> 
+    </tr> 
+         
+   and another hidden field that links that new timelog item (new
+   because it's marked as having id "-1") to the issue item. It looks
+   like this::
+
+     <input type="hidden" name="@link at times" value="timelog-1" />
+
+   On submission, the "-1" timelog item will be created and assigned a
+   real item id. The "times" property of the issue will have the new id
+   added to it.
+
+4. We want to display a total of the timelog times that have been
+   accumulated for an issue. To do this, we'll need to actually write
+   some Python code, since it's beyond the scope of PageTemplates to
+   perform such calculations. We do this by adding a module ``timespent.py``
+   to the ``extensions`` directory in our tracker. The contents of this
+   file is as follows::
+
+    def totalTimeSpent(times):
+        ''' Call me with a list of timelog items (which have an
+            Interval "period" property)
+        '''
+        total = Interval('0d')
+        for time in times:
+            total += time.period._value
+        return total
+
+    def init(instance):
+        instance.registerUtil('totalTimeSpent', totalTimeSpent)
+
+   We will now be able to access the ``totalTimeSpent`` function via the
+   ``utils`` variable in our templates, as shown in the next step.
+
+5. Display the timelog for an issue::
+
+     <table class="otherinfo" tal:condition="context/times">
+      <tr><th colspan="3" class="header">Time Log
+       <tal:block
+            tal:replace="python:utils.totalTimeSpent(context.times)" />
+      </th></tr>
+      <tr><th>Date</th><th>Period</th><th>Logged By</th></tr>
+      <tr tal:repeat="time context/times">
+       <td tal:content="time/creation"></td>
+       <td tal:content="time/period"></td>
+       <td tal:content="time/creator"></td>
+      </tr>
+     </table>
+
+   I put this just above the Messages log in my issue display. Note our
+   use of the ``totalTimeSpent`` method which will total up the times
+   for the issue and return a new Interval. That will be automatically
+   displayed in the template as text like "+ 1y 2:40" (1 year, 2 hours
+   and 40 minutes).
+
+8. If you're using a persistent web server - ``roundup-server`` or
+   ``mod_python`` for example - then you'll need to restart that to pick up
+   the code changes. When that's done, you'll be able to use the new
+   time logging interface.
+
+
+Tracking different types of issues
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes you will want to track different types of issues - developer,
+customer support, systems, sales leads, etc. A single Roundup tracker is
+able to support multiple types of issues. This example demonstrates adding
+a system support issue class to a tracker.
+
+1. Figure out what information you're going to want to capture. OK, so
+   this is obvious, but sometimes it's better to actually sit down for a
+   while and think about the schema you're going to implement.
+
+2. Add the new issue class to your tracker's ``schema.py``. Just after the
+   "issue" class definition, add::
+
+    # list our systems
+    system = Class(db, "system", name=String(), order=Number())
+    system.setkey("name")
+
+    # store issues related to those systems
+    support = IssueClass(db, "support", 
+                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    status=Link("status"), deadline=Date(),
+                    affects=Multilink("system"))
+
+3. Copy the existing ``issue.*`` (item, search and index) templates in the
+   tracker's ``html`` to ``support.*``. Edit them so they use the properties
+   defined in the ``support`` class. Be sure to check for hidden form
+   variables like "required" to make sure they have the correct set of
+   required properties.
+
+4. Edit the modules in the ``detectors``, adding lines to their ``init``
+   functions where appropriate. Look for ``audit`` and ``react`` registrations
+   on the ``issue`` class, and duplicate them for ``support``.
+
+5. Create a new sidebar box for the new support class. Duplicate the
+   existing issues one, changing the ``issue`` class name to ``support``.
+
+6. Re-start your tracker and start using the new ``support`` class.
+
+
+Optionally, you might want to restrict the users able to access this new
+class to just the users with a new "SysAdmin" Role. To do this, we add
+some security declarations::
+
+    db.security.addPermissionToRole('SysAdmin', 'View', 'support')
+    db.security.addPermissionToRole('SysAdmin', 'Create', 'support')
+    db.security.addPermissionToRole('SysAdmin', 'Edit', 'support')
+
+You would then (as an "admin" user) edit the details of the appropriate
+users, and add "SysAdmin" to their Roles list.
+
+Alternatively, you might want to change the Edit/View permissions granted
+for the ``issue`` class so that it's only available to users with the "System"
+or "Developer" Role, and then the new class you're adding is available to
+all with the "User" Role.
+
+
+Using External User Databases
+-----------------------------
+
+Using an external password validation source
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. note:: You will need to either have an "admin" user in your external
+          password source *or* have one of your regular users have
+          the Admin Role assigned. If you need to assign the Role *after*
+          making the changes below, you may use the ``roundup-admin``
+          program to edit a user's details.
+
+We have a centrally-managed password changing system for our users. This
+results in a UN*X passwd-style file that we use for verification of
+users. Entries in the file consist of ``name:password`` where the
+password is encrypted using the standard UN*X ``crypt()`` function (see
+the ``crypt`` module in your Python distribution). An example entry
+would be::
+
+    admin:aamrgyQfDFSHw
+
+Each user of Roundup must still have their information stored in the Roundup
+database - we just use the passwd file to check their password. To do this, we
+need to override the standard ``verifyPassword`` method defined in
+``roundup.cgi.actions.LoginAction`` and register the new class. The
+following is added as ``externalpassword.py`` in the tracker ``extensions``
+directory::
+
+    import os, crypt
+    from roundup.cgi.actions import LoginAction    
+
+    class ExternalPasswordLoginAction(LoginAction):
+        def verifyPassword(self, userid, password):
+            '''Look through the file, line by line, looking for a
+            name that matches.
+            '''
+            # get the user's username
+            username = self.db.user.get(userid, 'username')
+
+            # the passwords are stored in the "passwd.txt" file in the
+            # tracker home
+            file = os.path.join(self.db.config.TRACKER_HOME, 'passwd.txt')
+
+            # see if we can find a match
+            for ent in [line.strip().split(':') for line in
+                                                open(file).readlines()]:
+                if ent[0] == username:
+                    return crypt.crypt(password, ent[1][:2]) == ent[1]
+
+            # user doesn't exist in the file
+            return 0
+
+    def init(instance):
+        instance.registerAction('login', ExternalPasswordLoginAction)
+
+You should also remove the redundant password fields from the ``user.item``
+template.
+
+
+Using a UN*X passwd file as the user database
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+On some systems the primary store of users is the UN*X passwd file. It
+holds information on users such as their username, real name, password
+and primary user group.
+
+Roundup can use this store as its primary source of user information,
+but it needs additional information too - email address(es), roundup
+Roles, vacation flags, roundup hyperdb item ids, etc. Also, "retired"
+users must still exist in the user database, unlike some passwd files in
+which the users are removed when they no longer have access to a system.
+
+To make use of the passwd file, we therefore synchronise between the two
+user stores. We also use the passwd file to validate the user logins, as
+described in the previous example, `using an external password
+validation source`_. We keep the user lists in sync using a fairly
+simple script that runs once a day, or several times an hour if more
+immediate access is needed. In short, it:
+
+1. parses the passwd file, finding usernames, passwords and real names,
+2. compares that list to the current roundup user list:
+
+   a. entries no longer in the passwd file are *retired*
+   b. entries with mismatching real names are *updated*
+   c. entries only exist in the passwd file are *created*
+
+3. send an email to administrators to let them know what's been done.
+
+The retiring and updating are simple operations, requiring only a call
+to ``retire()`` or ``set()``. The creation operation requires more
+information though - the user's email address and their Roundup Roles.
+We're going to assume that the user's email address is the same as their
+login name, so we just append the domain name to that. The Roles are
+determined using the passwd group identifier - mapping their UN*X group
+to an appropriate set of Roles.
+
+The script to perform all this, broken up into its main components, is
+as follows. Firstly, we import the necessary modules and open the
+tracker we're to work on::
+
+    import sys, os, smtplib
+    from roundup import instance, date
+
+    # open the tracker
+    tracker_home = sys.argv[1]
+    tracker = instance.open(tracker_home)
+
+Next we read in the *passwd* file from the tracker home::
+
+    # read in the users from the "passwd.txt" file
+    file = os.path.join(tracker_home, 'passwd.txt')
+    users = [x.strip().split(':') for x in open(file).readlines()]
+
+Handle special users (those to ignore in the file, and those who don't
+appear in the file)::
+
+    # users to not keep ever, pre-load with the users I know aren't
+    # "real" users
+    ignore = ['ekmmon', 'bfast', 'csrmail']
+
+    # users to keep - pre-load with the roundup-specific users
+    keep = ['comment_pool', 'network_pool', 'admin', 'dev-team',
+            'cs_pool', 'anonymous', 'system_pool', 'automated']
+
+Now we map the UN*X group numbers to the Roles that users should have::
+
+    roles = {
+     '501': 'User,Tech',  # tech
+     '502': 'User',       # finance
+     '503': 'User,CSR',   # customer service reps
+     '504': 'User',       # sales
+     '505': 'User',       # marketing
+    }
+
+Now we do all the work. Note that the body of the script (where we have
+the tracker database open) is wrapped in a ``try`` / ``finally`` clause,
+so that we always close the database cleanly when we're finished. So, we
+now do all the work::
+
+    # open the database
+    db = tracker.open('admin')
+    try:
+        # store away messages to send to the tracker admins
+        msg = []
+
+        # loop over the users list read in from the passwd file
+        for user,passw,uid,gid,real,home,shell in users:
+            if user in ignore:
+                # this user shouldn't appear in our tracker
+                continue
+            keep.append(user)
+            try:
+                # see if the user exists in the tracker
+                uid = db.user.lookup(user)
+
+                # yes, they do - now check the real name for correctness
+                if real != db.user.get(uid, 'realname'):
+                    db.user.set(uid, realname=real)
+                    msg.append('FIX %s - %s'%(user, real))
+            except KeyError:
+                # nope, the user doesn't exist
+                db.user.create(username=user, realname=real,
+                    address='%s at ekit-inc.com'%user, roles=roles[gid])
+                msg.append('ADD %s - %s (%s)'%(user, real, roles[gid]))
+
+        # now check that all the users in the tracker are also in our
+        # "keep" list - retire those who aren't
+        for uid in db.user.list():
+            user = db.user.get(uid, 'username')
+            if user not in keep:
+                db.user.retire(uid)
+                msg.append('RET %s'%user)
+
+        # if we did work, then send email to the tracker admins
+        if msg:
+            # create the email
+            msg = '''Subject: %s user database maintenance
+
+            %s
+            '''%(db.config.TRACKER_NAME, '\n'.join(msg))
+
+            # send the email
+            smtp = smtplib.SMTP(db.config.MAILHOST)
+            addr = db.config.ADMIN_EMAIL
+            smtp.sendmail(addr, addr, msg)
+
+        # now we're done - commit the changes
+        db.commit()
+    finally:
+        # always close the database cleanly
+        db.close()
+
+And that's it!
+
+
+Using an LDAP database for user information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A script that reads users from an LDAP store using
+http://python-ldap.sf.net/ and then compares the list to the users in the
+roundup user database would be pretty easy to write. You'd then have it run
+once an hour / day (or on demand if you can work that into your LDAP store
+workflow). See the example `Using a UN*X passwd file as the user database`_
+for more information about doing this.
+
+To authenticate off the LDAP store (rather than using the passwords in the
+Roundup user database) you'd use the same python-ldap module inside an
+extension to the cgi interface. You'd do this by overriding the method called
+``verifyPassword`` on the ``LoginAction`` class in your tracker's
+``extensions`` directory (see `using an external password validation
+source`_). The method is implemented by default as::
+
+    def verifyPassword(self, userid, password):
+        ''' Verify the password that the user has supplied
+        '''
+        stored = self.db.user.get(self.userid, 'password')
+        if password == stored:
+            return 1
+        if not password and not stored:
+            return 1
+        return 0
+
+So you could reimplement this as something like::
+
+    def verifyPassword(self, userid, password):
+        ''' Verify the password that the user has supplied
+        '''
+        # look up some unique LDAP information about the user
+        username = self.db.user.get(self.userid, 'username')
+        # now verify the password supplied against the LDAP store
+
+
+Changes to Tracker Behaviour
+----------------------------
+
+Stop "nosy" messages going to people on vacation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When users go on vacation and set up vacation email bouncing, you'll
+start to see a lot of messages come back through Roundup "Fred is on
+vacation". Not very useful, and relatively easy to stop.
+
+1. add a "vacation" flag to your users::
+
+         user = Class(db, "user",
+                    username=String(),   password=Password(),
+                    address=String(),    realname=String(),
+                    phone=String(),      organisation=String(),
+                    alternate_addresses=String(),
+                    roles=String(), queries=Multilink("query"),
+                    vacation=Boolean())
+
+2. So that users may edit the vacation flags, add something like the
+   following to your ``user.item`` template::
+
+     <tr>
+      <th>On Vacation</th> 
+      <td tal:content="structure context/vacation/field">vacation</td> 
+     </tr> 
+
+3. edit your detector ``nosyreactor.py`` so that the ``nosyreaction()``
+   consists of::
+
+    def nosyreaction(db, cl, nodeid, oldvalues):
+        users = db.user
+        messages = db.msg
+        # send a copy of all new messages to the nosy list
+        for msgid in determineNewMessages(cl, nodeid, oldvalues):
+            try:
+                # figure the recipient ids
+                sendto = []
+                seen_message = {}
+                recipients = messages.get(msgid, 'recipients')
+                for recipid in messages.get(msgid, 'recipients'):
+                    seen_message[recipid] = 1
+
+                # figure the author's id, and indicate they've received
+                # the message
+                authid = messages.get(msgid, 'author')
+
+                # possibly send the message to the author, as long as
+                # they aren't anonymous
+                if (db.config.MESSAGES_TO_AUTHOR == 'yes' and
+                        users.get(authid, 'username') != 'anonymous'):
+                    sendto.append(authid)
+                seen_message[authid] = 1
+
+                # now figure the nosy people who weren't recipients
+                nosy = cl.get(nodeid, 'nosy')
+                for nosyid in nosy:
+                    # Don't send nosy mail to the anonymous user (that
+                    # user shouldn't appear in the nosy list, but just
+                    # in case they do...)
+                    if users.get(nosyid, 'username') == 'anonymous':
+                        continue
+                    # make sure they haven't seen the message already
+                    if not seen_message.has_key(nosyid):
+                        # send it to them
+                        sendto.append(nosyid)
+                        recipients.append(nosyid)
+
+                # generate a change note
+                if oldvalues:
+                    note = cl.generateChangeNote(nodeid, oldvalues)
+                else:
+                    note = cl.generateCreateNote(nodeid)
+
+                # we have new recipients
+                if sendto:
+                    # filter out the people on vacation
+                    sendto = [i for i in sendto 
+                              if not users.get(i, 'vacation', 0)]
+
+                    # map userids to addresses
+                    sendto = [users.get(i, 'address') for i in sendto]
+
+                    # update the message's recipients list
+                    messages.set(msgid, recipients=recipients)
+
+                    # send the message
+                    cl.send_message(nodeid, msgid, note, sendto)
+            except roundupdb.MessageSendError, message:
+                raise roundupdb.DetectorError, message
+
+   Note that this is the standard nosy reaction code, with the small
+   addition of::
+
+    # filter out the people on vacation
+    sendto = [i for i in sendto if not users.get(i, 'vacation', 0)]
+
+   which filters out the users that have the vacation flag set to true.
+
+Adding in state transition control
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes tracker admins want to control the states to which users may
+move issues. You can do this by following these steps:
+
+1. make "status" a required variable. This is achieved by adding the
+   following to the top of the form in the ``issue.item.html``
+   template::
+
+     <input type="hidden" name="@required" value="status">
+
+   This will force users to select a status.
+
+2. add a Multilink property to the status class::
+
+     stat = Class(db, "status", ... , transitions=Multilink('status'),
+                  ...)
+
+   and then edit the statuses already created, either:
+
+   a. through the web using the class list -> status class editor, or
+   b. using the ``roundup-admin`` "set" command.
+
+3. add an auditor module ``checktransition.py`` in your tracker's
+   ``detectors`` directory, for example::
+
+     def checktransition(db, cl, nodeid, newvalues):
+         ''' Check that the desired transition is valid for the "status"
+             property.
+         '''
+         if not newvalues.has_key('status'):
+             return
+         current = cl.get(nodeid, 'status')
+         new = newvalues['status']
+         if new == current:
+             return
+         ok = db.status.get(current, 'transitions')
+         if new not in ok:
+             raise ValueError, 'Status not allowed to move from "%s" to "%s"'%(
+                 db.status.get(current, 'name'), db.status.get(new, 'name'))
+
+     def init(db):
+         db.issue.audit('set', checktransition)
+
+4. in the ``issue.item.html`` template, change the status editing bit
+   from::
+
+    <th>Status</th>
+    <td tal:content="structure context/status/menu">status</td>
+
+   to::
+
+    <th>Status</th>
+    <td>
+     <select tal:condition="context/id" name="status">
+      <tal:block tal:define="ok context/status/transitions"
+                 tal:repeat="state db/status/list">
+       <option tal:condition="python:state.id in ok"
+               tal:attributes="
+                    value state/id;
+                    selected python:state.id == context.status.id"
+               tal:content="state/name"></option>
+      </tal:block>
+     </select>
+     <tal:block tal:condition="not:context/id"
+                tal:replace="structure context/status/menu" />
+    </td>
+
+   which displays only the allowed status to transition to.
+
+
+Blocking issues that depend on other issues
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We needed the ability to mark certain issues as "blockers" - that is,
+they can't be resolved until another issue (the blocker) they rely on is
+resolved. To achieve this:
+
+1. Create a new property on the ``issue`` class:
+   ``blockers=Multilink("issue")``. To do this, edit the definition of
+   this class in your tracker's ``schema.py`` file. Change this::
+
+    issue = IssueClass(db, "issue", 
+                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    priority=Link("priority"), status=Link("status"))
+
+   to this, adding the blockers entry::
+
+    issue = IssueClass(db, "issue", 
+                    blockers=Multilink("issue"),
+                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    priority=Link("priority"), status=Link("status"))
+
+2. Add the new ``blockers`` property to the ``issue.item.html`` edit
+   page, using something like::
+
+    <th>Waiting On</th>
+    <td>
+     <span tal:replace="structure python:context.blockers.field(showid=1,
+                                  size=20)" />
+     <span tal:replace="structure python:db.issue.classhelp('id,title')" />
+     <span tal:condition="context/blockers"
+           tal:repeat="blk context/blockers">
+      <br>View: <a tal:attributes="href string:issue${blk/id}"
+                   tal:content="blk/id"></a>
+     </span>
+
+   You'll need to fiddle with your item page layout to find an
+   appropriate place to put it - I'll leave that fun part up to you.
+   Just make sure it appears in the first table, possibly somewhere near
+   the "superseders" field.
+
+3. Create a new detector module (see below) which enforces the rules:
+
+   - issues may not be resolved if they have blockers
+   - when a blocker is resolved, it's removed from issues it blocks
+
+   The contents of the detector should be something like this::
+
+
+    def blockresolution(db, cl, nodeid, newvalues):
+        ''' If the issue has blockers, don't allow it to be resolved.
+        '''
+        if nodeid is None:
+            blockers = []
+        else:
+            blockers = cl.get(nodeid, 'blockers')
+        blockers = newvalues.get('blockers', blockers)
+
+        # don't do anything if there's no blockers or the status hasn't
+        # changed
+        if not blockers or not newvalues.has_key('status'):
+            return
+
+        # get the resolved state ID
+        resolved_id = db.status.lookup('resolved')
+
+        # format the info
+        u = db.config.TRACKER_WEB
+        s = ', '.join(['<a href="%sissue%s">%s</a>'%(
+                        u,id,id) for id in blockers])
+        if len(blockers) == 1:
+            s = 'issue %s is'%s
+        else:
+            s = 'issues %s are'%s
+
+        # ok, see if we're trying to resolve
+        if newvalues['status'] == resolved_id:
+            raise ValueError, "This issue can't be resolved until %s resolved."%s
+
+
+    def resolveblockers(db, cl, nodeid, oldvalues):
+        ''' When we resolve an issue that's a blocker, remove it from the
+            blockers list of the issue(s) it blocks.
+        '''
+        newstatus = cl.get(nodeid,'status')
+
+        # no change?
+        if oldvalues.get('status', None) == newstatus:
+            return
+
+        resolved_id = db.status.lookup('resolved')
+
+        # interesting?
+        if newstatus != resolved_id:
+            return
+
+        # yes - find all the blocked issues, if any, and remove me from
+        # their blockers list
+        issues = cl.find(blockers=nodeid)
+        for issueid in issues:
+            blockers = cl.get(issueid, 'blockers')
+            if nodeid in blockers:
+                blockers.remove(nodeid)
+                cl.set(issueid, blockers=blockers)
+
+    def init(db):
+        # might, in an obscure situation, happen in a create
+        db.issue.audit('create', blockresolution)
+        db.issue.audit('set', blockresolution)
+
+        # can only happen on a set
+        db.issue.react('set', resolveblockers)
+
+   Put the above code in a file called "blockers.py" in your tracker's
+   "detectors" directory.
+
+4. Finally, and this is an optional step, modify the tracker web page
+   URLs so they filter out issues with any blockers. You do this by
+   adding an additional filter on "blockers" for the value "-1". For
+   example, the existing "Show All" link in the "page" template (in the
+   tracker's "html" directory) looks like this::
+
+     <a href="issue?@sort=-activity&@group=priority&@filter=status&
+        @columns=id,activity,title,creator,assignedto,status&
+        status=-1,1,2,3,4,5,6,7">Show All</a><br>
+
+   modify it to add the "blockers" info to the URL (note, both the
+   "@filter" *and* "blockers" values must be specified)::
+
+     <a href="issue?@sort=-activity&@group=priority&@filter=status,blockers&
+        blockers=-1&@columns=id,activity,title,creator,assignedto,status&
+        status=-1,1,2,3,4,5,6,7">Show All</a><br>
+
+   The above examples are line-wrapped on the trailing & and should
+   be unwrapped.
+
+That's it. You should now be able to set blockers on your issues. Note
+that if you want to know whether an issue has any other issues dependent
+on it (i.e. it's in their blockers list) you can look at the journal
+history at the bottom of the issue page - look for a "link" event to
+another issue's "blockers" property.
+
+Add users to the nosy list based on the topic
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's say we need the ability to automatically add users to the nosy
+list based
+on the occurance of a topic. Every user should be allowed to edit their
+own list of topics for which they want to be added to the nosy list.
+
+Below, we'll show that this change can be done with minimal
+understanding of the Roundup system, using only copy and paste.
+
+This requires three changes to the tracker: a change in the database to
+allow per-user recording of the lists of topics for which he wants to
+be put on the nosy list, a change in the user view allowing them to edit
+this list of topics, and addition of an auditor which updates the nosy
+list when a topic is set.
+
+Adding the nosy topic list
+::::::::::::::::::::::::::
+
+The change to make in the database, is that for any user there should be
+a list of topics for which he wants to be put on the nosy list. Adding
+a ``Multilink`` of ``keyword`` seems to fullfill this (note that within
+the code, topics are called ``keywords``.) As such, all that has to be
+done is to add a new field to the definition of ``user`` within the
+file ``schema.py``.  We will call this new field ``nosy_keywords``, and
+the updated definition of user will be::
+
+    user = Class(db, "user", 
+                    username=String(),   password=Password(),
+                    address=String(),    realname=String(), 
+                    phone=String(),      organisation=String(),
+                    alternate_addresses=String(),
+                    queries=Multilink('query'), roles=String(),
+                    timezone=String(),
+                    nosy_keywords=Multilink('keyword'))
+ 
+Changing the user view to allow changing the nosy topic list
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+We want any user to be able to change the list of topics for which
+he will by default be added to the nosy list. We choose to add this
+to the user view, as is generated by the file ``html/user.item.html``.
+We can easily 
+see that the topic field in the issue view has very similar editing
+requirements as our nosy topics, both being lists of topics. As
+such, we look for Topics in ``issue.item.html``, and extract the
+associated parts from there. We add this to ``user.item.html`` at the 
+bottom of the list of viewed items (i.e. just below the 'Alternate
+E-mail addresses' in the classic template)::
+
+ <tr>
+  <th>Nosy Topics</th>
+  <td>
+  <span tal:replace="structure context/nosy_keywords/field" />
+  <span tal:replace="structure python:db.keyword.classhelp(property='nosy_keywords')" />
+  </td>
+ </tr>
+  
+
+Addition of an auditor to update the nosy list
+::::::::::::::::::::::::::::::::::::::::::::::
+
+The more difficult part is the logic to add
+the users to the nosy list when required. 
+We choose to perform this action whenever the topics on an
+item are set (this includes the creation of items).
+Here we choose to start out with a copy of the 
+``detectors/nosyreaction.py`` detector, which we copy to the file
+``detectors/nosy_keyword_reaction.py``. 
+This looks like a good start as it also adds users
+to the nosy list. A look through the code reveals that the
+``nosyreaction`` function actually sends the e-mail. 
+We don't need this. Therefore, we can change the ``init`` function to::
+
+    def init(db):
+        db.issue.audit('create', update_kw_nosy)
+        db.issue.audit('set', update_kw_nosy)
+
+After that, we rename the ``updatenosy`` function to ``update_kw_nosy``.
+The first two blocks of code in that function relate to setting
+``current`` to a combination of the old and new nosy lists. This
+functionality is left in the new auditor. The following block of
+code, which handled adding the assignedto user(s) to the nosy list in
+``updatenosy``, should be replaced by a block of code to add the
+interested users to the nosy list. We choose here to loop over all
+new topics, than looping over all users,
+and assign the user to the nosy list when the topic occurs in the user's
+``nosy_keywords``. The next part in ``updatenosy`` -- adding the author
+and/or recipients of a message to the nosy list -- is obviously not
+relevant here and is thus deleted from the new auditor. The last
+part, copying the new nosy list to ``newvalues``, can stay as is.
+This results in the following function::
+
+    def update_kw_nosy(db, cl, nodeid, newvalues):
+        '''Update the nosy list for changes to the topics
+        '''
+        # nodeid will be None if this is a new node
+        current = {}
+        if nodeid is None:
+            ok = ('new', 'yes')
+        else:
+            ok = ('yes',)
+            # old node, get the current values from the node if they haven't
+            # changed
+            if not newvalues.has_key('nosy'):
+                nosy = cl.get(nodeid, 'nosy')
+                for value in nosy:
+                    if not current.has_key(value):
+                        current[value] = 1
+
+        # if the nosy list changed in this transaction, init from the new value
+        if newvalues.has_key('nosy'):
+            nosy = newvalues.get('nosy', [])
+            for value in nosy:
+                if not db.hasnode('user', value):
+                    continue
+                if not current.has_key(value):
+                    current[value] = 1
+
+        # add users with topic in nosy_keywords to the nosy list
+        if newvalues.has_key('topic') and newvalues['topic'] is not None:
+            topic_ids = newvalues['topic']
+            for topic in topic_ids:
+                # loop over all users,
+                # and assign user to nosy when topic in nosy_keywords
+                for user_id in db.user.list():
+                    nosy_kw = db.user.get(user_id, "nosy_keywords")
+                    found = 0
+                    for kw in nosy_kw:
+                        if kw == topic:
+                            found = 1
+                    if found:
+                        current[user_id] = 1
+
+        # that's it, save off the new nosy list
+        newvalues['nosy'] = current.keys()
+
+These two function are the only ones needed in the file.
+
+TODO: update this example to use the ``find()`` Class method.
+
+Caveats
+:::::::
+
+A few problems with the design here can be noted:
+
+Multiple additions
+    When a user, after automatic selection, is manually removed
+    from the nosy list, he is added to the nosy list again when the
+    topic list of the issue is updated. A better design might be
+    to only check which topics are new compared to the old list
+    of topics, and only add users when they have indicated
+    interest on a new topic.
+
+    The code could also be changed to only trigger on the ``create()``
+    event, rather than also on the ``set()`` event, thus only setting
+    the nosy list when the issue is created.
+
+Scalability
+    In the auditor, there is a loop over all users. For a site with
+    only few users this will pose no serious problem; however, with
+    many users this will be a serious performance bottleneck.
+    A way out would be to link from the topics to the users who
+    selected these topics as nosy topics. This will eliminate the
+    loop over all users.
+
+Changes to Security and Permissions
+-----------------------------------
+
+Restricting the list of users that are assignable to a task
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. In your tracker's ``schema.py``, create a new Role, say "Developer"::
+
+     db.security.addRole(name='Developer', description='A developer')
+
+2. Just after that, create a new Permission, say "Fixer", specific to
+   "issue"::
+
+     p = db.security.addPermission(name='Fixer', klass='issue',
+         description='User is allowed to be assigned to fix issues')
+
+3. Then assign the new Permission to your "Developer" Role::
+
+     db.security.addPermissionToRole('Developer', p)
+
+4. In the issue item edit page (``html/issue.item.html`` in your tracker
+   directory), use the new Permission in restricting the "assignedto"
+   list::
+
+    <select name="assignedto">
+     <option value="-1">- no selection -</option>
+     <tal:block tal:repeat="user db/user/list">
+     <option tal:condition="python:user.hasPermission(
+                                'Fixer', context._classname)"
+             tal:attributes="
+                value user/id;
+                selected python:user.id == context.assignedto"
+             tal:content="user/realname"></option>
+     </tal:block>
+    </select>
+
+For extra security, you may wish to setup an auditor to enforce the
+Permission requirement (install this as ``assignedtoFixer.py`` in your
+tracker ``detectors`` directory)::
+
+  def assignedtoMustBeFixer(db, cl, nodeid, newvalues):
+      ''' Ensure the assignedto value in newvalues is used with the
+          Fixer Permission
+      '''
+      if not newvalues.has_key('assignedto'):
+          # don't care
+          return
+  
+      # get the userid
+      userid = newvalues['assignedto']
+      if not db.security.hasPermission('Fixer', userid, cl.classname):
+          raise ValueError, 'You do not have permission to edit %s'%cl.classname
+
+  def init(db):
+      db.issue.audit('set', assignedtoMustBeFixer)
+      db.issue.audit('create', assignedtoMustBeFixer)
+
+So now, if an edit action attempts to set "assignedto" to a user that
+doesn't have the "Fixer" Permission, the error will be raised.
+
+
+Users may only edit their issues
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In this case, users registering themselves are granted Provisional
+access, meaning they
+have access to edit the issues they submit, but not others. We create a new
+Role called "Provisional User" which is granted to newly-registered users,
+and has limited access. One of the Permissions they have is the new "Edit
+Own" on issues (regular users have "Edit".)
+
+First up, we create the new Role and Permission structure in
+``schema.py``::
+
+    #
+    # New users not approved by the admin
+    #
+    db.security.addRole(name='Provisional User',
+        description='New user registered via web or email')
+
+    # These users need to be able to view and create issues but only edit
+    # and view their own
+    db.security.addPermissionToRole('Provisional User', 'Create', 'issue')
+    def own_issue(db, userid, itemid):
+        '''Determine whether the userid matches the creator of the issue.'''
+        return userid == db.issue.get(itemid, 'creator')
+    p = db.security.addPermission(name='Edit', klass='issue',
+        check=own_issue, description='Can only edit own issues')
+    db.security.addPermissionToRole('Provisional User', p)
+    p = db.security.addPermission(name='View', klass='issue',
+        check=own_issue, description='Can only view own issues')
+    db.security.addPermissionToRole('Provisional User', p)
+
+    # Assign the Permissions for issue-related classes
+    for cl in 'file', 'msg', 'query', 'keyword':
+        db.security.addPermissionToRole('Provisional User', 'View', cl)
+        db.security.addPermissionToRole('Provisional User', 'Edit', cl)
+        db.security.addPermissionToRole('Provisional User', 'Create', cl)
+    for cl in 'priority', 'status':
+        db.security.addPermissionToRole('Provisional User', 'View', cl)
+
+    # and give the new users access to the web and email interface
+    db.security.addPermissionToRole('Provisional User', 'Web Access')
+    db.security.addPermissionToRole('Provisional User', 'Email Access')
+
+    # make sure they can view & edit their own user record
+    def own_record(db, userid, itemid):
+        '''Determine whether the userid matches the item being accessed.'''
+        return userid == itemid
+    p = db.security.addPermission(name='View', klass='user', check=own_record,
+        description="User is allowed to view their own user details")
+    db.security.addPermissionToRole('Provisional User', p)
+    p = db.security.addPermission(name='Edit', klass='user', check=own_record,
+        description="User is allowed to edit their own user details")
+    db.security.addPermissionToRole('Provisional User', p)
+
+Then, in ``config.ini``, we change the Role assigned to newly-registered
+users, replacing the existing ``'User'`` values::
+
+    [main]
+    ...
+    new_web_user_roles = 'Provisional User'
+    new_email_user_roles = 'Provisional User'
+
+
+All users may only view and edit issues, files and messages they create
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Replace the standard "classic" tracker View and Edit Permission assignments
+for the "issue", "file" and "msg" classes with the following::
+
+    def checker(klass):
+        def check(db, userid, itemid, klass=klass):
+            return db.getclass(klass).get(itemid, 'creator') == userid
+        return check
+    for cl in 'issue', 'file', 'msg':
+        p = db.security.addPermission(name='View', klass=cl,
+            check=checker(cl))
+        db.security.addPermissionToRole('User', p)
+        p = db.security.addPermission(name='Edit', klass=cl,
+            check=checker(cl))
+        db.security.addPermissionToRole('User', p)
+        db.security.addPermissionToRole('User', 'Create', cl)
+
+
+
+Changes to the Web User Interface
+---------------------------------
+
+Adding action links to the index page
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Add a column to the ``item.index.html`` template.
+
+Resolving the issue::
+
+  <a tal:attributes="href
+     string:issue${i/id}?:status=resolved&:action=edit">resolve</a>
+
+"Take" the issue::
+
+  <a tal:attributes="href
+     string:issue${i/id}?:assignedto=${request/user/id}&:action=edit">take</a>
+
+... and so on.
+
+Colouring the rows in the issue index according to priority
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A simple ``tal:attributes`` statement will do the bulk of the work here. In
+the ``issue.index.html`` template, add this to the ``<tr>`` that
+displays the rows of data::
+
+   <tr tal:attributes="class string:priority-${i/priority/plain}">
+
+and then in your stylesheet (``style.css``) specify the colouring for the
+different priorities, as follows::
+
+   tr.priority-critical td {
+       background-color: red;
+   }
+
+   tr.priority-urgent td {
+       background-color: orange;
+   }
+
+and so on, with far less offensive colours :)
+
+Editing multiple items in an index view
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To edit the status of all items in the item index view, edit the
+``issue.item.html``:
+
+1. add a form around the listing table (separate from the existing
+   index-page form), so at the top it reads::
+
+    <form method="POST" tal:attributes="action request/classname">
+     <table class="list">
+
+   and at the bottom of that table::
+
+     </table>
+    </form
+
+   making sure you match the ``</table>`` from the list table, not the
+   navigation table or the subsequent form table.
+
+2. in the display for the issue property, change::
+
+    <td tal:condition="request/show/status"
+        tal:content="python:i.status.plain() or default">&nbsp;</td>
+
+   to::
+
+    <td tal:condition="request/show/status"
+        tal:content="structure i/status/field">&nbsp;</td>
+
+   this will result in an edit field for the status property.
+
+3. after the ``tal:block`` which lists the index items (marked by
+   ``tal:repeat="i batch"``) add a new table row::
+
+    <tr>
+     <td tal:attributes="colspan python:len(request.columns)">
+      <input type="submit" value=" Save Changes ">
+      <input type="hidden" name="@action" value="edit">
+      <tal:block replace="structure request/indexargs_form" />
+     </td>
+    </tr>
+
+   which gives us a submit button, indicates that we are performing an edit
+   on any changed statuses. The final ``tal:block`` will make sure that the
+   current index view parameters (filtering, columns, etc) will be used in 
+   rendering the next page (the results of the editing).
+
+
+Displaying only message summaries in the issue display
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Alter the ``issue.item`` template section for messages to::
+
+ <table class="messages" tal:condition="context/messages">
+  <tr><th colspan="5" class="header">Messages</th></tr>
+  <tr tal:repeat="msg context/messages">
+   <td><a tal:attributes="href string:msg${msg/id}"
+          tal:content="string:msg${msg/id}"></a></td>
+   <td tal:content="msg/author">author</td>
+   <td class="date" tal:content="msg/date/pretty">date</td>
+   <td tal:content="msg/summary">summary</td>
+   <td>
+    <a tal:attributes="href string:?@remove at messages=${msg/id}&@action=edit">
+    remove</a>
+   </td>
+  </tr>
+ </table>
+
+
+Enabling display of either message summaries or the entire messages
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is pretty simple - all we need to do is copy the code from the
+example `displaying only message summaries in the issue display`_ into
+our template alongside the summary display, and then introduce a switch
+that shows either the one or the other. We'll use a new form variable,
+``@whole_messages`` to achieve this::
+
+ <table class="messages" tal:condition="context/messages">
+  <tal:block tal:condition="not:request/form/@whole_messages/value | python:0">
+   <tr><th colspan="3" class="header">Messages</th>
+       <th colspan="2" class="header">
+         <a href="?@whole_messages=yes">show entire messages</a>
+       </th>
+   </tr>
+   <tr tal:repeat="msg context/messages">
+    <td><a tal:attributes="href string:msg${msg/id}"
+           tal:content="string:msg${msg/id}"></a></td>
+    <td tal:content="msg/author">author</td>
+    <td class="date" tal:content="msg/date/pretty">date</td>
+    <td tal:content="msg/summary">summary</td>
+    <td>
+     <a tal:attributes="href string:?@remove at messages=${msg/id}&@action=edit">remove</a>
+    </td>
+   </tr>
+  </tal:block>
+
+  <tal:block tal:condition="request/form/@whole_messages/value | python:0">
+   <tr><th colspan="2" class="header">Messages</th>
+       <th class="header">
+         <a href="?@whole_messages=">show only summaries</a>
+       </th>
+   </tr>
+   <tal:block tal:repeat="msg context/messages">
+    <tr>
+     <th tal:content="msg/author">author</th>
+     <th class="date" tal:content="msg/date/pretty">date</th>
+     <th style="text-align: right">
+      (<a tal:attributes="href string:?@remove at messages=${msg/id}&@action=edit">remove</a>)
+     </th>
+    </tr>
+    <tr><td colspan="3" tal:content="msg/content"></td></tr>
+   </tal:block>
+  </tal:block>
+ </table>
+
+
+Setting up a "wizard" (or "druid") for controlled adding of issues
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Set up the page templates you wish to use for data input. My wizard
+   is going to be a two-step process: first figuring out what category
+   of issue the user is submitting, and then getting details specific to
+   that category. The first page includes a table of help, explaining
+   what the category names mean, and then the core of the form::
+
+    <form method="POST" onSubmit="return submit_once()"
+          enctype="multipart/form-data">
+      <input type="hidden" name="@template" value="add_page1">
+      <input type="hidden" name="@action" value="page1_submit">
+
+      <strong>Category:</strong>
+      <tal:block tal:replace="structure context/category/menu" />
+      <input type="submit" value="Continue">
+    </form>
+
+   The next page has the usual issue entry information, with the
+   addition of the following form fragments::
+
+    <form method="POST" onSubmit="return submit_once()"
+          enctype="multipart/form-data"
+          tal:condition="context/is_edit_ok"
+          tal:define="cat request/form/category/value">
+
+      <input type="hidden" name="@template" value="add_page2">
+      <input type="hidden" name="@required" value="title">
+      <input type="hidden" name="category" tal:attributes="value cat">
+       .
+       .
+       .
+    </form>
+
+   Note that later in the form, I use the value of "cat" to decide which
+   form elements should be displayed. For example::
+
+    <tal:block tal:condition="python:cat in '6 10 13 14 15 16 17'.split()">
+     <tr>
+      <th>Operating System</th>
+      <td tal:content="structure context/os/field"></td>
+     </tr>
+     <tr>
+      <th>Web Browser</th>
+      <td tal:content="structure context/browser/field"></td>
+     </tr>
+    </tal:block>
+
+   ... the above section will only be displayed if the category is one
+   of 6, 10, 13, 14, 15, 16 or 17.
+
+3. Determine what actions need to be taken between the pages - these are
+   usually to validate user choices and determine what page is next. Now encode
+   those actions in a new ``Action`` class (see `defining new web actions`_)::
+
+    from roundup.cgi.actions import Action
+
+    class Page1SubmitAction(Action):
+        def handle(self):
+            ''' Verify that the user has selected a category, and then move
+                on to page 2.
+            '''
+            category = self.form['category'].value
+            if category == '-1':
+                self.error_message.append('You must select a category of report')
+                return
+            # everything's ok, move on to the next page
+            self.template = 'add_page2'
+
+    def init(instance):
+        instance.registerAction('page1_submit', Page1SubmitAction)
+
+4. Use the usual "new" action as the ``@action`` on the final page, and
+   you're done (the standard context/submit method can do this for you).
+
+
+Debugging Trackers
+==================
+
+There are three switches in tracker configs that turn on debugging in
+Roundup:
+
+1. web :: debug
+2. mail :: debug
+3. logging :: level
+
+See the config.ini file or the `tracker configuration`_ section above for
+more information.
+
+Additionally, the ``roundup-server.py`` script has its own debugging mode
+in which it reloads edited templates immediately when they are changed,
+rather than requiring a web server restart.
+
+
+-------------------
+
+Back to `Table of Contents`_
+
+.. _`Table of Contents`: index.html
+.. _`design documentation`: design.html
+.. _`admin guide`: admin_guide.html
+

Added: tracker/vendor/roundup/current/doc/debugging.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/debugging.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,31 @@
+Debugging Flags
+---------------
+
+Roundup uses a number of debugging environment variables to help you
+figure out what the heck it's doing. 
+
+HYPERDBDEBUG 
+============
+
+This environment variable should be set to a filename - the hyperdb will
+write debugging information for various events (including, for instance,
+the SQL used).
+
+This is only obeyed when python is _not_ running in -O mode. 
+
+HYPERDBTRACE
+============
+
+This environment variable should be set to a filename - the hyperdb will
+write a timestamp entry for various events. This appears to be suffering
+rather extreme bit-rot and may go away soon.
+
+This is only obeyed when python is _not_ running in -O mode. 
+
+SENDMAILDEBUG
+=============
+
+Set to a filename and roundup will write a copy of each email message
+that it sends to that file. This environment variable is independent of
+the python -O flag.
+

Added: tracker/vendor/roundup/current/doc/default.css
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/default.css	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,239 @@
+/*
+:Author: David Goodger
+:Contact: goodger at users.sourceforge.net
+:date: $Date: 2004/06/09 00:25:32 $
+:version: $Revision: 1.13 $
+:copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+*/
+
+a.target {
+  color: blue }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+dd {
+  margin-bottom: 0.5em }
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.attention, div.caution, div.danger, div.error,
+div.important, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.hint, div.note {
+  font-size: 80%;
+  float: right;
+  width: 15em;
+  margin: 0.5em;
+  margin-left: 1em ;
+  border: solid #aaa;
+  background: #eee;
+  padding: 1em;
+}
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.hint p.admonition-title, div.important p.admonition-title,
+div.note p.admonition-title, div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em }
+
+div.footer, div.header {
+  font-size: smaller }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1 {
+  margin-top: 2em;
+  text-decoration: underline;
+}
+
+h1.title {
+  text-align: center;
+  margin-top: .5em;
+}
+
+h2.subtitle {
+  text-align: center }
+
+hr {
+  width: 75% }
+
+ol.simple, ul.simple {
+  margin-top: 0;
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.first {
+  margin-top: 0 }
+
+p.label {
+  white-space: nowrap }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.line-block {
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.field-argument {
+  font-style: italic }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option-argument {
+  font-style: italic }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+table {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em ;
+  }
+
+table.citation {
+  border-top: 0;
+  border-bottom: 0;
+  border-right: 0;
+  border-left: solid thin gray ;
+  padding-left: 0.5ex }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.footnote {
+  border-left: solid thin black ;
+  padding-left: 0.5ex }
+
+td, th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: baseline;
+}
+
+table.table {
+  border-spacing: 0px;
+  border-collapse: separate;
+}
+table.table td {
+  text-align: left;
+  border: solid thin gray;
+}
+
+table.table th {
+  text-align: left;
+  border: solid thin gray;
+}
+
+td > p:first-child, th > p:first-child {
+  margin-top: 0em }
+
+th.docinfo-name {
+  font-weight: bold ;
+  text-align: right }
+
+th.field-name {
+  font-weight: bold ;
+  text-align: right }
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+  font-size: 100% }
+
+tt {
+  background-color: #eeeeee }
+
+tt.literal span.pre {
+  background-color: #eeeeee
+}
+
+ul.auto-toc {
+  list-style-type: none }

Added: tracker/vendor/roundup/current/doc/design.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/design.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,1639 @@
+========================================================
+Roundup - An Issue-Tracking System for Knowledge Workers
+========================================================
+
+:Authors: Ka-Ping Yee (original), Richard Jones (implementation)
+
+.. contents::
+
+Introduction
+---------------
+
+This document presents a description of the components of the Roundup
+system and specifies their interfaces and behaviour in sufficient detail
+to guide an implementation. For the philosophy and rationale behind the
+Roundup design, see the first-round Software Carpentry `submission for
+Roundup`__. This document fleshes out that design as well as specifying
+interfaces so that the components can be developed separately.
+
+__ spec.html
+
+
+The Layer Cake
+-----------------
+
+Lots of software design documents come with a picture of a cake.
+Everybody seems to like them.  I also like cakes (i think they are
+tasty).  So I, too, shall include a picture of a cake here::
+
+     ________________________________________________________________
+    | E-mail Client |  Web Browser  |  Detector Scripts  |   Shell   |
+    |---------------+---------------+--------------------+-----------|
+    |  E-mail User  |   Web User    |     Detector       |  Command  | 
+    |----------------------------------------------------------------|
+    |                    Roundup Database Layer                      |
+    |----------------------------------------------------------------|
+    |                     Hyperdatabase Layer                        |
+    |----------------------------------------------------------------|
+    |                        Storage Layer                           |
+     ----------------------------------------------------------------
+
+The colourful parts of the cake are part of our system; the faint grey
+parts of the cake are external components.
+
+I will now proceed to forgo all table manners and eat from the bottom of
+the cake to the top.  You may want to stand back a bit so you don't get
+covered in crumbs.
+
+
+Hyperdatabase
+-------------
+
+The lowest-level component to be implemented is the hyperdatabase. The
+hyperdatabase is a flexible data store that can hold configurable data
+in records which we call items.
+
+The hyperdatabase is implemented on top of the storage layer, an
+external module for storing its data. The "batteries-includes" distribution
+implements the hyperdatabase on the standard anydbm module.  The storage
+layer could be a third-party RDBMS; for a low-maintenance solution,
+implementing the hyperdatabase on the SQLite RDBMS is suggested.
+
+
+Dates and Date Arithmetic
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before we get into the hyperdatabase itself, we need a way of handling
+dates.  The hyperdatabase module provides Timestamp objects for
+representing date-and-time stamps and Interval objects for representing
+date-and-time intervals.
+
+As strings, date-and-time stamps are specified with the date in
+international standard format (``yyyy-mm-dd``) joined to the time
+(``hh:mm:ss``) by a period "``.``".  Dates in this form can be easily
+compared and are fairly readable when printed.  An example of a valid
+stamp is "``2000-06-24.13:03:59``". We'll call this the "full date
+format".  When Timestamp objects are printed as strings, they appear in
+the full date format with the time always given in GMT.  The full date
+format is always exactly 19 characters long.
+
+For user input, some partial forms are also permitted: the whole time or
+just the seconds may be omitted; and the whole date may be omitted or
+just the year may be omitted.  If the time is given, the time is
+interpreted in the user's local time zone. The Date constructor takes
+care of these conversions. In the following examples, suppose that
+``yyyy`` is the current year, ``mm`` is the current month, and ``dd`` is
+the current day of the month; and suppose that the user is on Eastern
+Standard Time.
+
+-   "2000-04-17" means <Date 2000-04-17.00:00:00>
+-   "01-25" means <Date yyyy-01-25.00:00:00>
+-   "2000-04-17.03:45" means <Date 2000-04-17.08:45:00>
+-   "08-13.22:13" means <Date yyyy-08-14.03:13:00>
+-   "11-07.09:32:43" means <Date yyyy-11-07.14:32:43>
+-   "14:25" means
+-   <Date yyyy-mm-dd.19:25:00>
+-   "8:47:11" means
+-   <Date yyyy-mm-dd.13:47:11>
+-   the special date "." means "right now"
+
+
+Date intervals are specified using the suffixes "y", "m", and "d".  The
+suffix "w" (for "week") means 7 days. Time intervals are specified in
+hh:mm:ss format (the seconds may be omitted, but the hours and minutes
+may not).
+
+-   "3y" means three years
+-   "2y 1m" means two years and one month
+-   "1m 25d" means one month and 25 days
+-   "2w 3d" means two weeks and three days
+-   "1d 2:50" means one day, two hours, and 50 minutes
+-   "14:00" means 14 hours
+-   "0:04:33" means four minutes and 33 seconds
+
+
+The Date class should understand simple date expressions of the form
+*stamp* ``+`` *interval* and *stamp* ``-`` *interval*. When adding or
+subtracting intervals involving months or years, the components are
+handled separately.  For example, when evaluating "``2000-06-25 + 1m
+10d``", we first add one month to get 2000-07-25, then add 10 days to
+get 2000-08-04 (rather than trying to decide whether 1m 10d means 38 or
+40 or 41 days).
+
+Here is an outline of the Date and Interval classes::
+
+    class Date:
+        def __init__(self, spec, offset):
+            """Construct a date given a specification and a time zone
+            offset.
+
+            'spec' is a full date or a partial form, with an optional
+            added or subtracted interval.  'offset' is the local time
+            zone offset from GMT in hours.
+            """
+
+        def __add__(self, interval):
+            """Add an interval to this date to produce another date."""
+
+        def __sub__(self, interval):
+            """Subtract an interval from this date to produce another
+            date.
+            """
+
+        def __cmp__(self, other):
+            """Compare this date to another date."""
+
+        def __str__(self):
+            """Return this date as a string in the yyyy-mm-dd.hh:mm:ss
+            format.
+            """
+
+        def local(self, offset):
+            """Return this date as yyyy-mm-dd.hh:mm:ss in a local time
+            zone.
+            """
+
+    class Interval:
+        def __init__(self, spec):
+            """Construct an interval given a specification."""
+
+        def __cmp__(self, other):
+            """Compare this interval to another interval."""
+            
+        def __str__(self):
+            """Return this interval as a string."""
+
+
+
+Here are some examples of how these classes would behave in practice.
+For the following examples, assume that we are on Eastern Standard Time
+and the current local time is 19:34:02 on 25 June 2000::
+
+    >>> Date(".")
+    <Date 2000-06-26.00:34:02>
+    >>> _.local(-5)
+    "2000-06-25.19:34:02"
+    >>> Date(". + 2d")
+    <Date 2000-06-28.00:34:02>
+    >>> Date("1997-04-17", -5)
+    <Date 1997-04-17.00:00:00>
+    >>> Date("01-25", -5)
+    <Date 2000-01-25.00:00:00>
+    >>> Date("08-13.22:13", -5)
+    <Date 2000-08-14.03:13:00>
+    >>> Date("14:25", -5)
+    <Date 2000-06-25.19:25:00>
+    >>> Interval("  3w  1  d  2:00")
+    <Interval 22d 2:00>
+    >>> Date(". + 2d") - Interval("3w")
+    <Date 2000-06-07.00:34:02>
+
+
+Items and Classes
+~~~~~~~~~~~~~~~~~
+
+Items contain data in properties.  To Python, these properties are
+presented as the key-value pairs of a dictionary. Each item belongs to a
+class which defines the names and types of its properties.  The database
+permits the creation and modification of classes as well as items.
+
+
+Identifiers and Designators
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Each item has a numeric identifier which is unique among items in its
+class.  The items are numbered sequentially within each class in order
+of creation, starting from 1. The designator for an item is a way to
+identify an item in the database, and consists of the name of the item's
+class concatenated with the item's numeric identifier.
+
+For example, if "spam" and "eggs" are classes, the first item created in
+class "spam" has id 1 and designator "spam1". The first item created in
+class "eggs" also has id 1 but has the distinct designator "eggs1". Item
+designators are conventionally enclosed in square brackets when
+mentioned in plain text.  This permits a casual mention of, say,
+"[patch37]" in an e-mail message to be turned into an active hyperlink.
+
+
+Property Names and Types
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Property names must begin with a letter.
+
+A property may be one of five basic types:
+
+- String properties are for storing arbitrary-length strings.
+
+- Boolean properties are for storing true/false, or yes/no values.
+
+- Number properties are for storing numeric values.
+
+- Date properties store date-and-time stamps. Their values are Timestamp
+  objects.
+
+- A Link property refers to a single other item selected from a
+  specified class.  The class is part of the property; the value is an
+  integer, the id of the chosen item.
+
+- A Multilink property refers to possibly many items in a specified
+  class.  The value is a list of integers.
+
+*None* is also a permitted value for any of these property types.  An
+attempt to store None into a Multilink property stores an empty list.
+
+A property that is not specified will return as None from a *get*
+operation.
+
+
+Hyperdb Interface Specification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+TODO: replace the Interface Specifications with links to the pydoc
+
+The hyperdb module provides property objects to designate the different
+kinds of properties.  These objects are used when specifying what
+properties belong in classes::
+
+    class String:
+        def __init__(self, indexme='no'):
+            """An object designating a String property."""
+
+    class Boolean:
+        def __init__(self):
+            """An object designating a Boolean property."""
+
+    class Number:
+        def __init__(self):
+            """An object designating a Number property."""
+
+    class Date:
+        def __init__(self):
+            """An object designating a Date property."""
+
+    class Link:
+        def __init__(self, classname, do_journal='yes'):
+            """An object designating a Link property that links to
+            items in a specified class.
+
+            If the do_journal argument is not 'yes' then changes to
+            the property are not journalled in the linked item.
+            """
+
+    class Multilink:
+        def __init__(self, classname, do_journal='yes'):
+            """An object designating a Multilink property that links
+            to items in a specified class.
+
+            If the do_journal argument is not 'yes' then changes to
+            the property are not journalled in the linked item(s).
+            """
+
+
+Here is the interface provided by the hyperdatabase::
+
+    class Database:
+        """A database for storing records containing flexible data
+        types.
+        """
+
+        def __init__(self, config, journaltag=None):
+            """Open a hyperdatabase given a specifier to some storage.
+
+            The 'storagelocator' is obtained from config.DATABASE. The
+            meaning of 'storagelocator' depends on the particular
+            implementation of the hyperdatabase.  It could be a file
+            name, a directory path, a socket descriptor for a connection
+            to a database over the network, etc.
+
+            The 'journaltag' is a token that will be attached to the
+            journal entries for any edits done on the database.  If
+            'journaltag' is None, the database is opened in read-only
+            mode: the Class.create(), Class.set(), Class.retire(), and
+            Class.restore() methods are disabled.
+            """
+
+        def __getattr__(self, classname):
+            """A convenient way of calling self.getclass(classname)."""
+
+        def getclasses(self):
+            """Return a list of the names of all existing classes."""
+
+        def getclass(self, classname):
+            """Get the Class object representing a particular class.
+
+            If 'classname' is not a valid class name, a KeyError is
+            raised.
+            """
+
+    class Class:
+        """The handle to a particular class of items in a hyperdatabase.
+        """
+
+        def __init__(self, db, classname, **properties):
+            """Create a new class with a given name and property
+            specification.
+
+            'classname' must not collide with the name of an existing
+            class, or a ValueError is raised.  The keyword arguments in
+            'properties' must map names to property objects, or a
+            TypeError is raised.
+
+            A proxied reference to the database is available as the
+            'db' attribute on instances. For example, in
+            'IssueClass.send_message', the following is used to lookup
+            users, messages and files::
+
+                users = self.db.user
+                messages = self.db.msg
+                files = self.db.file
+            """
+
+        # Editing items:
+
+        def create(self, **propvalues):
+            """Create a new item of this class and return its id.
+
+            The keyword arguments in 'propvalues' map property names to
+            values. The values of arguments must be acceptable for the
+            types of their corresponding properties or a TypeError is
+            raised.  If this class has a key property, it must be
+            present and its value must not collide with other key
+            strings or a ValueError is raised.  Any other properties on
+            this class that are missing from the 'propvalues' dictionary
+            are set to None.  If an id in a link or multilink property
+            does not refer to a valid item, an IndexError is raised.
+            """
+
+        def get(self, itemid, propname):
+            """Get the value of a property on an existing item of this
+            class.
+
+            'itemid' must be the id of an existing item of this class or
+            an IndexError is raised.  'propname' must be the name of a
+            property of this class or a KeyError is raised.
+            """
+
+        def set(self, itemid, **propvalues):
+            """Modify a property on an existing item of this class.
+            
+            'itemid' must be the id of an existing item of this class or
+            an IndexError is raised.  Each key in 'propvalues' must be
+            the name of a property of this class or a KeyError is
+            raised.  All values in 'propvalues' must be acceptable types
+            for their corresponding properties or a TypeError is raised.
+            If the value of the key property is set, it must not collide
+            with other key strings or a ValueError is raised.  If the
+            value of a Link or Multilink property contains an invalid
+            item id, a ValueError is raised.
+            """
+
+        def retire(self, itemid):
+            """Retire an item.
+            
+            The properties on the item remain available from the get()
+            method, and the item's id is never reused.  Retired items
+            are not returned by the find(), list(), or lookup() methods,
+            and other items may reuse the values of their key
+            properties.
+            """
+
+        def restore(self, nodeid):
+        '''Restore a retired node.
+
+        Make node available for all operations like it was before
+        retirement.
+        '''
+
+        def history(self, itemid):
+            """Retrieve the journal of edits on a particular item.
+
+            'itemid' must be the id of an existing item of this class or
+            an IndexError is raised.
+
+            The returned list contains tuples of the form
+
+                (date, tag, action, params)
+
+            'date' is a Timestamp object specifying the time of the
+            change and 'tag' is the journaltag specified when the
+            database was opened. 'action' may be:
+
+                'create' or 'set' -- 'params' is a dictionary of
+                    property values
+                'link' or 'unlink' -- 'params' is (classname, itemid,
+                    propname)
+                'retire' -- 'params' is None
+            """
+
+        # Locating items:
+
+        def setkey(self, propname):
+            """Select a String property of this class to be the key
+            property.
+
+            'propname' must be the name of a String property of this
+            class or None, or a TypeError is raised.  The values of the
+            key property on all existing items must be unique or a
+            ValueError is raised.
+            """
+
+        def getkey(self):
+            """Return the name of the key property for this class or
+            None.
+            """
+
+        def lookup(self, keyvalue):
+            """Locate a particular item by its key property and return
+            its id.
+
+            If this class has no key property, a TypeError is raised.
+            If the 'keyvalue' matches one of the values for the key
+            property among the items in this class, the matching item's
+            id is returned; otherwise a KeyError is raised.
+            """
+
+        def find(self, **propspec):
+            """Get the ids of items in this class which link to the
+            given items.
+
+            'propspec' consists of keyword args propname=itemid or
+                       propname={<itemid 1>:1, <itemid 2>: 1, ...}
+            'propname' must be the name of a property in this class,
+                       or a KeyError is raised.  That property must
+                       be a Link or Multilink property, or a TypeError
+                       is raised.
+
+            Any item in this class whose 'propname' property links to
+            any of the itemids will be returned. Examples::
+
+                db.issue.find(messages='1')
+                db.issue.find(messages={'1':1,'3':1}, files={'7':1})
+            """
+
+        def filter(self, search_matches, filterspec, sort, group):
+            """ Return a list of the ids of the active items in this
+            class that match the 'filter' spec, sorted by the group spec
+            and then the sort spec.
+            """
+
+        def list(self):
+            """Return a list of the ids of the active items in this
+            class.
+            """
+
+        def count(self):
+            """Get the number of items in this class.
+
+            If the returned integer is 'numitems', the ids of all the
+            items in this class run from 1 to numitems, and numitems+1
+            will be the id of the next item to be created in this class.
+            """
+
+        # Manipulating properties:
+
+        def getprops(self):
+            """Return a dictionary mapping property names to property
+            objects.
+            """
+
+        def addprop(self, **properties):
+            """Add properties to this class.
+
+            The keyword arguments in 'properties' must map names to
+            property objects, or a TypeError is raised.  None of the
+            keys in 'properties' may collide with the names of existing
+            properties, or a ValueError is raised before any properties
+            have been added.
+            """
+
+        def getitem(self, itemid, cache=1):
+            """ Return a Item convenience wrapper for the item.
+
+            'itemid' must be the id of an existing item of this class or
+            an IndexError is raised.
+
+            'cache' indicates whether the transaction cache should be
+            queried for the item. If the item has been modified and you
+            need to determine what its values prior to modification are,
+            you need to set cache=0.
+            """
+
+    class Item:
+        """ A convenience wrapper for the given item. It provides a
+        mapping interface to a single item's properties
+        """
+
+Hyperdatabase Implementations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Hyperdatabase implementations exist to create the interface described in
+the `hyperdb interface specification`_ over an existing storage
+mechanism. Examples are relational databases, \*dbm key-value databases,
+and so on.
+
+Several implementations are provided - they belong in the
+``roundup.backends`` package.
+
+
+Application Example
+~~~~~~~~~~~~~~~~~~~
+
+Here is an example of how the hyperdatabase module would work in
+practice::
+
+    >>> import hyperdb
+    >>> db = hyperdb.Database("foo.db", "ping")
+    >>> db
+    <hyperdb.Database "foo.db" opened by "ping">
+    >>> hyperdb.Class(db, "status", name=hyperdb.String())
+    <hyperdb.Class "status">
+    >>> _.setkey("name")
+    >>> db.status.create(name="unread")
+    1
+    >>> db.status.create(name="in-progress")
+    2
+    >>> db.status.create(name="testing")
+    3
+    >>> db.status.create(name="resolved")
+    4
+    >>> db.status.count()
+    4
+    >>> db.status.list()
+    [1, 2, 3, 4]
+    >>> db.status.lookup("in-progress")
+    2
+    >>> db.status.retire(3)
+    >>> db.status.list()
+    [1, 2, 4]
+    >>> hyperdb.Class(db, "issue", title=hyperdb.String(), status=hyperdb.Link("status"))
+    <hyperdb.Class "issue">
+    >>> db.issue.create(title="spam", status=1)
+    1
+    >>> db.issue.create(title="eggs", status=2)
+    2
+    >>> db.issue.create(title="ham", status=4)
+    3
+    >>> db.issue.create(title="arguments", status=2)
+    4
+    >>> db.issue.create(title="abuse", status=1)
+    5
+    >>> hyperdb.Class(db, "user", username=hyperdb.Key(),
+    ... password=hyperdb.String())
+    <hyperdb.Class "user">
+    >>> db.issue.addprop(fixer=hyperdb.Link("user"))
+    >>> db.issue.getprops()
+    {"title": <hyperdb.String>, "status": <hyperdb.Link to "status">,
+     "user": <hyperdb.Link to "user">}
+    >>> db.issue.set(5, status=2)
+    >>> db.issue.get(5, "status")
+    2
+    >>> db.status.get(2, "name")
+    "in-progress"
+    >>> db.issue.get(5, "title")
+    "abuse"
+    >>> db.issue.find("status", db.status.lookup("in-progress"))
+    [2, 4, 5]
+    >>> db.issue.history(5)
+    [(<Date 2000-06-28.19:09:43>, "ping", "create", {"title": "abuse",
+    "status": 1}),
+     (<Date 2000-06-28.19:11:04>, "ping", "set", {"status": 2})]
+    >>> db.status.history(1)
+    [(<Date 2000-06-28.19:09:43>, "ping", "link", ("issue", 5, "status")),
+     (<Date 2000-06-28.19:11:04>, "ping", "unlink", ("issue", 5, "status"))]
+    >>> db.status.history(2)
+    [(<Date 2000-06-28.19:11:04>, "ping", "link", ("issue", 5, "status"))]
+
+
+For the purposes of journalling, when a Multilink property is set to a
+new list of items, the hyperdatabase compares the old list to the new
+list. The journal records "unlink" events for all the items that appear
+in the old list but not the new list, and "link" events for all the
+items that appear in the new list but not in the old list.
+
+
+Roundup Database
+----------------
+
+The Roundup database layer is implemented on top of the hyperdatabase
+and mediates calls to the database. Some of the classes in the Roundup
+database are considered issue classes. The Roundup database layer adds
+detectors and user items, and on issues it provides mail spools, nosy
+lists, and superseders.
+
+
+Reserved Classes
+~~~~~~~~~~~~~~~~
+
+Internal to this layer we reserve three special classes of items that
+are not issues.
+
+Users
+"""""
+
+Users are stored in the hyperdatabase as items of class "user".  The
+"user" class has the definition::
+
+    hyperdb.Class(db, "user", username=hyperdb.String(),
+                              password=hyperdb.String(),
+                              address=hyperdb.String())
+    db.user.setkey("username")
+
+Messages
+""""""""
+
+E-mail messages are represented by hyperdatabase items of class "msg".
+The actual text content of the messages is stored in separate files.
+(There's no advantage to be gained by stuffing them into the
+hyperdatabase, and if messages are stored in ordinary text files, they
+can be grepped from the command line.)  The text of a message is saved
+in a file named after the message item designator (e.g. "msg23") for the
+sake of the command interface (see below).  Attachments are stored
+separately and associated with "file" items. The "msg" class has the
+definition::
+
+    hyperdb.Class(db, "msg", author=hyperdb.Link("user"),
+                             recipients=hyperdb.Multilink("user"),
+                             date=hyperdb.Date(),
+                             summary=hyperdb.String(),
+                             files=hyperdb.Multilink("file"))
+
+The "author" property indicates the author of the message (a "user" item
+must exist in the hyperdatabase for any messages that are stored in the
+system). The "summary" property contains a summary of the message for
+display in a message index.
+
+
+Files
+"""""
+
+Submitted files are represented by hyperdatabase items of class "file".
+Like e-mail messages, the file content is stored in files outside the
+database, named after the file item designator (e.g. "file17"). The
+"file" class has the definition::
+
+    hyperdb.Class(db, "file", user=hyperdb.Link("user"),
+                              name=hyperdb.String(),
+                              type=hyperdb.String())
+
+The "user" property indicates the user who submitted the file, the
+"name" property holds the original name of the file, and the "type"
+property holds the MIME type of the file as received.
+
+
+Issue Classes
+~~~~~~~~~~~~~
+
+All issues have the following standard properties:
+
+=========== ==========================
+Property    Definition
+=========== ==========================
+title       hyperdb.String()
+messages    hyperdb.Multilink("msg")
+files       hyperdb.Multilink("file")
+nosy        hyperdb.Multilink("user")
+superseder  hyperdb.Multilink("issue")
+=========== ==========================
+
+Also, two Date properties named "creation" and "activity" are fabricated
+by the Roundup database layer. Two user Link properties, "creator" and
+"actor" are also fabricated. By "fabricated" we mean that no such
+properties are actually stored in the hyperdatabase, but when properties
+on issues are requested, the "creation"/"creator" and "activity"/"actor"
+properties are made available. The value of the "creation"/"creator"
+properties relate to issue creation, and the value of the "activity"/
+"actor" properties relate to the last editing of any property on the issue
+(equivalently, these are the dates on the first and last records in the
+issue's journal).
+
+
+Roundupdb Interface Specification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The interface to a Roundup database delegates most method calls to the
+hyperdatabase, except for the following changes and additional methods::
+
+    class Database:
+        def getuid(self):
+            """Return the id of the "user" item associated with the user
+            that owns this connection to the hyperdatabase."""
+
+    class Class:
+        # Overridden methods:
+
+        def create(self, **propvalues):
+        def set(self, **propvalues):
+        def retire(self, itemid):
+            """These operations trigger detectors and can be vetoed.
+            Attempts to modify the "creation", "creator", "activity"
+            properties or "actor" cause a KeyError.
+            """
+
+    class IssueClass(Class):
+        # Overridden methods:
+
+        def __init__(self, db, classname, **properties):
+            """The newly-created class automatically includes the
+            "messages", "files", "nosy", and "superseder" properties.
+            If the 'properties' dictionary attempts to specify any of
+            these properties or a "creation", "creator", "activity" or
+            "actor" property, a ValueError is raised."""
+
+        def get(self, itemid, propname):
+        def getprops(self):
+            """In addition to the actual properties on the item, these
+            methods provide the "creation", "creator", "activity" and
+            "actor" properties."""
+
+        # New methods:
+
+        def addmessage(self, itemid, summary, text):
+            """Add a message to an issue's mail spool.
+
+            A new "msg" item is constructed using the current date, the
+            user that owns the database connection as the author, and
+            the specified summary text.  The "files" and "recipients"
+            fields are left empty.  The given text is saved as the body
+            of the message and the item is appended to the "messages"
+            field of the specified issue.
+            """
+
+        def nosymessage(self, itemid, msgid):
+            """Send a message to the members of an issue's nosy list.
+
+            The message is sent only to users on the nosy list who are
+            not already on the "recipients" list for the message.  These
+            users are then added to the message's "recipients" list.
+            """
+
+
+Default Schema
+~~~~~~~~~~~~~~
+
+The default schema included with Roundup turns it into a typical
+software bug tracker.  The database is set up like this::
+
+    pri = Class(db, "priority", name=hyperdb.String(),
+                order=hyperdb.String())
+    pri.setkey("name")
+    pri.create(name="critical", order="1")
+    pri.create(name="urgent", order="2")
+    pri.create(name="bug", order="3")
+    pri.create(name="feature", order="4")
+    pri.create(name="wish", order="5")
+
+    stat = Class(db, "status", name=hyperdb.String(),
+                 order=hyperdb.String())
+    stat.setkey("name")
+    stat.create(name="unread", order="1")
+    stat.create(name="deferred", order="2")
+    stat.create(name="chatting", order="3")
+    stat.create(name="need-eg", order="4")
+    stat.create(name="in-progress", order="5")
+    stat.create(name="testing", order="6")
+    stat.create(name="done-cbb", order="7")
+    stat.create(name="resolved", order="8")
+
+    Class(db, "keyword", name=hyperdb.String())
+
+    Class(db, "issue", fixer=hyperdb.Multilink("user"),
+                       topic=hyperdb.Multilink("keyword"),
+                       priority=hyperdb.Link("priority"),
+                       status=hyperdb.Link("status"))
+
+(The "order" property hasn't been explained yet.  It gets used by the
+Web user interface for sorting.)
+
+The above isn't as pretty-looking as the schema specification in the
+first-stage submission, but it could be made just as easy with the
+addition of a convenience function like Choice for setting up the
+"priority" and "status" classes::
+
+    def Choice(name, *options):
+        cl = Class(db, name, name=hyperdb.String(),
+                   order=hyperdb.String())
+        for i in range(len(options)):
+            cl.create(name=option[i], order=i)
+        return hyperdb.Link(name)
+
+
+Detector Interface
+------------------
+
+Detectors are Python functions that are triggered on certain kinds of
+events.  The definitions of the functions live in Python modules placed
+in a directory set aside for this purpose.  Importing the Roundup
+database module also imports all the modules in this directory, and the
+``init()`` function of each module is called when a database is opened
+to provide it a chance to register its detectors.
+
+There are two kinds of detectors:
+
+1. an auditor is triggered just before modifying an item
+2. a reactor is triggered just after an item has been modified
+
+When the Roundup database is about to perform a ``create()``, ``set()``,
+``retire()``, or ``restore`` operation, it first calls any *auditors*
+that have been registered for that operation on that class. Any auditor
+may raise a *Reject* exception to abort the operation.
+
+If none of the auditors raises an exception, the database proceeds to
+carry out the operation.  After it's done, it then calls all of the
+*reactors* that have been registered for the operation.
+
+
+Detector Interface Specification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``audit()`` and ``react()`` methods register detectors on a given
+class of items::
+
+    class Class:
+        def audit(self, event, detector, priority=100):
+            """Register an auditor on this class.
+
+            'event' should be one of "create", "set", "retire", or
+            "restore". 'detector' should be a function accepting four
+            arguments. Detectors are called in priority order, execution
+            order is undefined for detectors with the same priority.
+            """
+
+        def react(self, event, detector, priority=100):
+            """Register a reactor on this class.
+
+            'event' should be one of "create", "set", "retire", or
+            "restore". 'detector' should be a function accepting four
+            arguments. Detectors are called in priority order, execution
+            order is undefined for detectors with the same priority.
+            """
+
+Auditors are called with the arguments::
+
+    audit(db, cl, itemid, newdata)
+
+where ``db`` is the database, ``cl`` is an instance of Class or
+IssueClass within the database, and ``newdata`` is a dictionary mapping
+property names to values.
+
+For a ``create()`` operation, the ``itemid`` argument is None and
+newdata contains all of the initial property values with which the item
+is about to be created.
+
+For a ``set()`` operation, newdata contains only the names and values of
+properties that are about to be changed.
+
+For a ``retire()`` or ``restore()`` operation, newdata is None.
+
+Reactors are called with the arguments::
+
+    react(db, cl, itemid, olddata)
+
+where ``db`` is the database, ``cl`` is an instance of Class or
+IssueClass within the database, and ``olddata`` is a dictionary mapping
+property names to values.
+
+For a ``create()`` operation, the ``itemid`` argument is the id of the
+newly-created item and ``olddata`` is None.
+
+For a ``set()`` operation, ``olddata`` contains the names and previous
+values of properties that were changed.
+
+For a ``retire()`` or ``restore()`` operation, ``itemid`` is the id of
+the retired or restored item and ``olddata`` is None.
+
+
+Detector Example
+~~~~~~~~~~~~~~~~
+
+Here is an example of detectors written for a hypothetical
+project-management application, where users can signal approval of a
+project by adding themselves to an "approvals" list, and a project
+proceeds when it has three approvals::
+
+    # Permit users only to add themselves to the "approvals" list.
+
+    def check_approvals(db, cl, id, newdata):
+        if newdata.has_key("approvals"):
+            if cl.get(id, "status") == db.status.lookup("approved"):
+                raise Reject, "You can't modify the approvals list " \
+                    "for a project that has already been approved."
+            old = cl.get(id, "approvals")
+            new = newdata["approvals"]
+            for uid in old:
+                if uid not in new and uid != db.getuid():
+                    raise Reject, "You can't remove other users from " \
+                        "the approvals list; you can only remove " \
+                        "yourself."
+            for uid in new:
+                if uid not in old and uid != db.getuid():
+                    raise Reject, "You can't add other users to the " \
+                        "approvals list; you can only add yourself."
+
+    # When three people have approved a project, change its status from
+    # "pending" to "approved".
+
+    def approve_project(db, cl, id, olddata):
+        if (olddata.has_key("approvals") and 
+            len(cl.get(id, "approvals")) == 3):
+            if cl.get(id, "status") == db.status.lookup("pending"):
+                cl.set(id, status=db.status.lookup("approved"))
+
+    def init(db):
+        db.project.audit("set", check_approval)
+        db.project.react("set", approve_project)
+
+Here is another example of a detector that can allow or prevent the
+creation of new items.  In this scenario, patches for a software project
+are submitted by sending in e-mail with an attached file, and we want to
+ensure that there are text/plain attachments on the message.  The
+maintainer of the package can then apply the patch by setting its status
+to "applied"::
+
+    # Only accept attempts to create new patches that come with patch
+    # files.
+
+    def check_new_patch(db, cl, id, newdata):
+        if not newdata["files"]:
+            raise Reject, "You can't submit a new patch without " \
+                          "attaching a patch file."
+        for fileid in newdata["files"]:
+            if db.file.get(fileid, "type") != "text/plain":
+                raise Reject, "Submitted patch files must be " \
+                              "text/plain."
+
+    # When the status is changed from "approved" to "applied", apply the
+    # patch.
+
+    def apply_patch(db, cl, id, olddata):
+        if (cl.get(id, "status") == db.status.lookup("applied") and 
+            olddata["status"] == db.status.lookup("approved")):
+            # ...apply the patch...
+
+    def init(db):
+        db.patch.audit("create", check_new_patch)
+        db.patch.react("set", apply_patch)
+
+
+Command Interface
+-----------------
+
+The command interface is a very simple and minimal interface, intended
+only for quick searches and checks from the shell prompt. (Anything more
+interesting can simply be written in Python using the Roundup database
+module.)
+
+
+Command Interface Specification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A single command, roundup, provides basic access to the hyperdatabase
+from the command line::
+
+    roundup-admin help
+    roundup-admin get [-list] designator[, designator,...] propname
+    roundup-admin set designator[, designator,...] propname=value ...
+    roundup-admin find [-list] classname propname=value ...
+
+See ``roundup-admin help commands`` for a complete list of commands.
+
+Property values are represented as strings in command arguments and in
+the printed results:
+
+- Strings are, well, strings.
+
+- Numbers are displayed the same as strings.
+
+- Booleans are displayed as 'Yes' or 'No'.
+
+- Date values are printed in the full date format in the local time
+  zone, and accepted in the full format or any of the partial formats
+  explained above.
+
+- Link values are printed as item designators.  When given as an
+  argument, item designators and key strings are both accepted.
+
+- Multilink values are printed as lists of item designators joined by
+  commas.  When given as an argument, item designators and key strings
+  are both accepted; an empty string, a single item, or a list of items
+  joined by commas is accepted.
+
+When multiple items are specified to the roundup get or roundup set
+commands, the specified properties are retrieved or set on all the
+listed items.
+
+When multiple results are returned by the roundup get or roundup find
+commands, they are printed one per line (default) or joined by commas
+(with the -list) option.
+
+
+Usage Example
+~~~~~~~~~~~~~
+
+To find all messages regarding in-progress issues that contain the word
+"spam", for example, you could execute the following command from the
+directory where the database dumps its files::
+
+    shell% for issue in `roundup find issue status=in-progress`; do
+    > grep -l spam `roundup get $issue messages`
+    > done
+    msg23
+    msg49
+    msg50
+    msg61
+    shell%
+
+Or, using the -list option, this can be written as a single command::
+
+    shell% grep -l spam `roundup get \
+        \`roundup find -list issue status=in-progress\` messages`
+    msg23
+    msg49
+    msg50
+    msg61
+    shell%
+    
+
+E-mail User Interface
+---------------------
+
+The Roundup system must be assigned an e-mail address at which to
+receive mail.  Messages should be piped to the Roundup mail-handling
+script by the mail delivery system (e.g. using an alias beginning with
+"|" for sendmail).
+
+
+Message Processing
+~~~~~~~~~~~~~~~~~~
+
+Incoming messages are examined for multiple parts. In a multipart/mixed
+message or part, each subpart is extracted and examined.  In a
+multipart/alternative message or part, we look for a text/plain subpart
+and ignore the other parts.  The text/plain subparts are assembled to
+form the textual body of the message, to be stored in the file
+associated with a "msg" class item. Any parts of other types are each
+stored in separate files and given "file" class items that are linked to
+the "msg" item.
+
+The "summary" property on message items is taken from the first
+non-quoting section in the message body. The message body is divided
+into sections by blank lines. Sections where the second and all
+subsequent lines begin with a ">" or "|" character are considered
+"quoting sections".  The first line of the first non-quoting section
+becomes the summary of the message.
+
+All of the addresses in the To: and Cc: headers of the incoming message
+are looked up among the user items, and the corresponding users are
+placed in the "recipients" property on the new "msg" item.  The address
+in the From: header similarly determines the "author" property of the
+new "msg" item. The default handling for addresses that don't have
+corresponding users is to create new users with no passwords and a
+username equal to the address.  (The web interface does not permit
+logins for users with no passwords.)  If we prefer to reject mail from
+outside sources, we can simply register an auditor on the "user" class
+that prevents the creation of user items with no passwords.
+
+The subject line of the incoming message is examined to determine
+whether the message is an attempt to create a new issue or to discuss an
+existing issue.  A designator enclosed in square brackets is sought as
+the first thing on the subject line (after skipping any "Fwd:" or "Re:"
+prefixes).
+
+If an issue designator (class name and id number) is found there, the
+newly created "msg" item is added to the "messages" property for that
+issue, and any new "file" items are added to the "files" property for
+the issue.
+
+If just an issue class name is found there, we attempt to create a new
+issue of that class with its "messages" property initialized to contain
+the new "msg" item and its "files" property initialized to contain any
+new "file" items.
+
+Both cases may trigger detectors (in the first case we are calling the
+set() method to add the message to the issue's spool; in the second case
+we are calling the create() method to create a new item).  If an auditor
+raises an exception, the original message is bounced back to the sender
+with the explanatory message given in the exception.
+
+
+Nosy Lists
+~~~~~~~~~~
+
+A standard detector is provided that watches for additions to the
+"messages" property.  When a new message is added, the detector sends it
+to all the users on the "nosy" list for the issue that are not already
+on the "recipients" list of the message.  Those users are then appended
+to the "recipients" property on the message, so multiple copies of a
+message are never sent to the same user.  The journal recorded by the
+hyperdatabase on the "recipients" property then provides a log of when
+the message was sent to whom.
+
+
+Setting Properties
+~~~~~~~~~~~~~~~~~~
+
+The e-mail interface also provides a simple way to set properties on
+issues.  At the end of the subject line, ``propname=value`` pairs can be
+specified in square brackets, using the same conventions as for the
+roundup ``set`` shell command.
+
+
+Web User Interface
+------------------
+
+The web interface is provided by a CGI script that can be run under any
+web server.  A simple web server can easily be built on the standard
+CGIHTTPServer module, and should also be included in the distribution
+for quick out-of-the-box deployment.
+
+The user interface is constructed from a number of template files
+containing mostly HTML.  Among the HTML tags in templates are
+interspersed some nonstandard tags, which we use as placeholders to be
+replaced by properties and their values.
+
+
+Views and View Specifiers
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are two main kinds of views: *index* views and *issue* views. An
+index view displays a list of issues of a particular class, optionally
+sorted and filtered as requested.  An issue view presents the properties
+of a particular issue for editing and displays the message spool for the
+issue.
+
+A view specifier is a string that specifies all the options needed to
+construct a particular view. It goes after the URL to the Roundup CGI
+script or the web server to form the complete URL to a view.  When the
+result of selecting a link or submitting a form takes the user to a new
+view, the Web browser should be redirected to a canonical location
+containing a complete view specifier so that the view can be bookmarked.
+
+
+Displaying Properties
+~~~~~~~~~~~~~~~~~~~~~
+
+Properties appear in the user interface in three contexts: in indices,
+in editors, and as search filters.  For each type of property, there are
+several display possibilities.  For example, in an index view, a string
+property may just be printed as a plain string, but in an editor view,
+that property should be displayed in an editable field.
+
+The display of a property is handled by functions in the
+``cgi.templating`` module.
+
+Displayer functions are triggered by ``tal:content`` or ``tal:replace``
+tag attributes in templates.  The value of the attribute provides an
+expression for calling the displayer function. For example, the
+occurrence of::
+
+    tal:content="context/status/plain"
+
+in a template triggers a call to::
+    
+    context['status'].plain()
+
+where the context would be an item of the "issue" class.  The displayer
+functions can accept extra arguments to further specify details about
+the widgets that should be generated.
+
+Some of the standard displayer functions include:
+
+========= ==============================================================
+Function  Description
+========= ==============================================================
+plain     display a String property directly;
+          display a Date property in a specified time zone with an
+          option to omit the time from the date stamp; for a Link or
+          Multilink property, display the key strings of the linked
+          items (or the ids if the linked class has no key property)
+field     display a property like the plain displayer above, but in a
+          text field to be edited
+menu      for a Link property, display a menu of the available choices
+========= ==============================================================
+
+See the `customisation`_ documentation for the complete list.
+
+
+Index Views
+~~~~~~~~~~~
+
+An index view contains two sections: a filter section and an index
+section. The filter section provides some widgets for selecting which
+issues appear in the index.  The index section is a table of issues.
+
+
+Index View Specifiers
+"""""""""""""""""""""
+
+An index view specifier looks like this (whitespace has been added for
+clarity)::
+
+    /issue?status=unread,in-progress,resolved&
+        topic=security,ui&
+        :group=priority&
+        :sort=-activity&
+        :filters=status,topic&
+        :columns=title,status,fixer
+
+
+The index view is determined by two parts of the specifier: the layout
+part and the filter part. The layout part consists of the query
+parameters that begin with colons, and it determines the way that the
+properties of selected items are displayed. The filter part consists of
+all the other query parameters, and it determines the criteria by which
+items are selected for display.
+
+The filter part is interactively manipulated with the form widgets
+displayed in the filter section.  The layout part is interactively
+manipulated by clicking on the column headings in the table.
+
+The filter part selects the union of the sets of issues with values
+matching any specified Link properties and the intersection of the sets
+of issues with values matching any specified Multilink properties.
+
+The example specifies an index of "issue" items. Only issues with a
+"status" of either "unread" or "in-progres" or "resolved" are displayed,
+and only issues with "topic" values including both "security" and "ui"
+are displayed.  The issues are grouped by priority, arranged in
+ascending order; and within groups, sorted by activity, arranged in
+descending order.  The filter section shows filters for the "status" and
+"topic" properties, and the table includes columns for the "title",
+"status", and "fixer" properties.
+
+Associated with each issue class is a default layout specifier.  The
+layout specifier in the above example is the default layout to be
+provided with the default bug-tracker schema described above in section
+4.4.
+
+Index Section
+"""""""""""""
+
+The template for an index section describes one row of the index table.
+Fragments protected by a ``tal:condition="request/show/<property>"`` are
+included or omitted depending on whether the view specifier requests a
+column for a particular property. The table cells are filled by the
+``tal:content="context/<property>"`` directive, which displays the value
+of the property.
+
+Here's a simple example of an index template::
+
+    <tr>
+      <td tal:condition="request/show/title"
+          tal:content="contex/title"></td>
+      <td tal:condition="request/show/status"
+          tal:content="contex/status"></td>
+      <td tal:condition="request/show/fixer"
+          tal:content="contex/fixer"></td>
+    </tr>
+
+Sorting
+"""""""
+
+String and Date values are sorted in the natural way. Link properties
+are sorted according to the value of the "order" property on the linked
+items if it is present; or otherwise on the key string of the linked
+items; or finally on the item ids.  Multilink properties are sorted
+according to how many links are present.
+
+Issue Views
+~~~~~~~~~~~
+
+An issue view contains an editor section and a spool section. At the top
+of an issue view, links to superseding and superseded issues are always
+displayed.
+
+Issue View Specifiers
+"""""""""""""""""""""
+
+An issue view specifier is simply the issue's designator::
+
+    /patch23
+
+
+Editor Section
+""""""""""""""
+
+The editor section is generated from a template containing
+``tal:content="context/<property>/<widget>"`` directives to insert the
+appropriate widgets for editing properties.
+
+Here's an example of a basic editor template::
+
+    <table>
+    <tr>
+        <td colspan=2
+            tal:content="python:context.title.field(size='60')"></td>
+    </tr>
+    <tr>
+        <td tal:content="context/fixer/field"></td>
+        <td tal:content="context/status/menu"></td>
+    </tr>
+    <tr>
+        <td tal:content="context/nosy/field"></td>
+        <td tal:content="context/priority/menu"></td>
+    </tr>
+    <tr>
+        <td colspan=2>
+          <textarea name=":note" rows=5 cols=60></textarea>
+        </td>
+    </tr>
+    </table>
+
+As shown in the example, the editor template can also include a ":note"
+field, which is a text area for entering a note to go along with a
+change.
+
+When a change is submitted, the system automatically generates a message
+describing the changed properties. The message displays all of the
+property values on the issue and indicates which ones have changed. An
+example of such a message might be this::
+
+    title: Polly Parrot is dead
+    priority: critical
+    status: unread -> in-progress
+    fixer: (none)
+    keywords: parrot,plumage,perch,nailed,dead
+
+If a note is given in the ":note" field, the note is appended to the
+description.  The message is then added to the issue's message spool
+(thus triggering the standard detector to react by sending out this
+message to the nosy list).
+
+
+Spool Section
+"""""""""""""
+
+The spool section lists messages in the issue's "messages" property.
+The index of messages displays the "date", "author", and "summary"
+properties on the message items, and selecting a message takes you to
+its content.
+
+Access Control
+--------------
+
+At each point that requires an action to be performed, the security
+mechanisms are asked if the current user has permission. This permission
+is defined as a Permission.
+
+Individual assignment of Permission to user is unwieldy. The concept of
+a Role, which encompasses several Permissions and may be assigned to
+many Users, is quite well developed in many projects. Roundup will take
+this path, and allow the multiple assignment of Roles to Users, and
+multiple Permissions to Roles. These definitions are not persistent -
+they're defined when the application initialises.
+
+There will be three levels of Permission. The Class level permissions
+define logical permissions associated with all items of a particular
+class (or all classes). The Item level permissions define logical
+permissions associated with specific items by way of their user-linked
+properties. The Property level permissions define logical permissions
+associated with a specific property of an item.
+
+
+Access Control Interface Specification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The security module defines::
+
+    class Permission:
+        ''' Defines a Permission with the attributes
+            - name
+            - description
+            - klass (optional)
+            - properties (optional)
+            - check function (optional)
+
+            The klass may be unset, indicating that this permission is
+            not locked to a particular hyperdb class. There may be
+            multiple Permissions for the same name for different
+            classes.
+
+            If property names are set, permission is restricted to those
+            properties only.
+
+            If check function is set, permission is granted only when
+            the function returns value interpreted as boolean true.
+            The function is called with arguments db, userid, itemid.
+        '''
+
+    class Role:
+        ''' Defines a Role with the attributes
+            - name
+            - description
+            - permissions
+        '''
+
+    class Security:
+        def __init__(self, db):
+            ''' Initialise the permission and role stores, and add in
+                the base roles (for admin user).
+            '''
+
+        def getPermission(self, permission, classname=None, properties=None,
+                check=None):
+            ''' Find the Permission exactly matching the name, class,
+                properties list and check function.
+
+                Raise ValueError if there is no exact match.
+            '''
+
+        def hasPermission(self, permission, userid, classname=None,
+                property=None, itemid=None):
+            ''' Look through all the Roles, and hence Permissions, and
+                see if "permission" exists given the constraints of
+                classname, property and itemid.
+
+                If classname is specified (and only classname) then the
+                search will match if there is *any* Permission for that
+                classname, even if the Permission has additional
+                constraints.
+
+                If property is specified, the Permission matched must have
+                either no properties listed or the property must appear in
+                the list.
+
+                If itemid is specified, the Permission matched must have
+                either no check function defined or the check function,
+                when invoked, must return a True value.
+
+                Note that this functionality is actually implemented by the
+                Permission.test() method.
+            '''
+
+        def addPermission(self, **propspec):
+            ''' Create a new Permission with the properties defined in
+                'propspec'. See the Permission class for the possible
+                keyword args.
+            '''
+
+        def addRole(self, **propspec):
+            ''' Create a new Role with the properties defined in
+                'propspec'
+            '''
+
+        def addPermissionToRole(self, rolename, permission):
+            ''' Add the permission to the role's permission list.
+
+                'rolename' is the name of the role to add permission to.
+            '''
+
+Modules such as ``cgi/client.py`` and ``mailgw.py`` define their own
+permissions like so (this example is ``cgi/client.py``)::
+
+    def initialiseSecurity(security):
+        ''' Create some Permissions and Roles on the security object
+
+            This function is directly invoked by
+            security.Security.__init__() as a part of the Security
+            object instantiation.
+        '''
+        p = security.addPermission(name="Web Registration",
+            description="Anonymous users may register through the web")
+        security.addToRole('Anonymous', p)
+
+Detectors may also define roles in their init() function::
+
+    def init(db):
+        # register an auditor that checks that a user has the "May
+        # Resolve" Permission before allowing them to set an issue
+        # status to "resolved"
+        db.issue.audit('set', checkresolvedok)
+        p = db.security.addPermission(name="May Resolve", klass="issue")
+        security.addToRole('Manager', p)
+
+The tracker dbinit module then has in ``open()``::
+
+    # open the database - it must be modified to init the Security class
+    # from security.py as db.security
+    db = Database(config, name)
+
+    # add some extra permissions and associate them with roles
+    ei = db.security.addPermission(name="Edit", klass="issue",
+                    description="User is allowed to edit issues")
+    db.security.addPermissionToRole('User', ei)
+    ai = db.security.addPermission(name="View", klass="issue",
+                    description="User is allowed to access issues")
+    db.security.addPermissionToRole('User', ai)
+
+In the dbinit ``init()``::
+
+    # create the two default users
+    user.create(username="admin", password=Password(adminpw),
+                address=config.ADMIN_EMAIL, roles='Admin')
+    user.create(username="anonymous", roles='Anonymous')
+
+Then in the code that matters, calls to ``hasPermission`` and
+``hasItemPermission`` are made to determine if the user has permission
+to perform some action::
+
+    if db.security.hasPermission('issue', 'Edit', userid):
+        # all ok
+
+    if db.security.hasItemPermission('issue', itemid,
+                                     assignedto=userid):
+        # all ok
+
+Code in the core will make use of these methods, as should code in
+auditors in custom templates. The HTML templating may access the access
+controls through the *user* attribute of the *request* variable. It
+exposes a ``hasPermission()`` method::
+
+  tal:condition="python:request.user.hasPermission('Edit', 'issue')"
+
+or, if the *context* is *issue*, then the following is the same::
+
+  tal:condition="python:request.user.hasPermission('Edit')"
+
+
+Authentication of Users
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Users must be authenticated correctly for the above controls to work.
+This is not done in the current mail gateway at all. Use of digital
+signing of messages could alleviate this problem.
+
+The exact mechanism of registering the digital signature should be
+flexible, with perhaps a level of trust. Users who supply their
+signature through their first message into the tracker should be at a
+lower level of trust to those who supply their signature to an admin for
+submission to their user details.
+
+
+Anonymous Users
+~~~~~~~~~~~~~~~
+
+The "anonymous" user must always exist, and defines the access
+permissions for anonymous users. Unknown users accessing Roundup through
+the web or email interfaces will be logged in as the "anonymous" user.
+
+
+Use Cases
+~~~~~~~~~
+
+public - end users can submit bugs, request new features, request
+    support
+    The Users would be given the default "User" Role which gives "View"
+    and "Edit" Permission to the "issue" class.
+developer - developers can fix bugs, implement new features, provide
+    support
+    A new Role "Developer" is created with the Permission "Fixer" which
+    is checked for in custom auditors that see whether the issue is
+    being resolved with a particular resolution ("fixed", "implemented",
+    "supported") and allows that resolution only if the permission is
+    available.
+manager - approvers/managers can approve new features and signoff bug
+    fixes
+    A new Role "Manager" is created with the Permission "Signoff" which
+    is checked for in custom auditors that see whether the issue status
+    is being changed similar to the developer example. admin -
+    administrators can add users and set user's roles The existing Role
+    "Admin" has the Permissions "Edit" for all classes (including
+    "user") and "Web Roles" which allow the desired actions.
+system - automated request handlers running various report/escalation
+    scripts
+    A combination of existing and new Roles, Permissions and auditors
+    could be used here.
+privacy - issues that are only visible to some users
+    A new property is added to the issue which marks the user or group
+    of users who are allowed to view and edit the issue. An auditor will
+    check for edit access, and the template user object can check for
+    view access.
+
+
+Deployment Scenarios
+--------------------
+
+The design described above should be general enough to permit the use of
+Roundup for bug tracking, managing projects, managing patches, or
+holding discussions.  By using items of multiple types, one could deploy
+a system that maintains requirement specifications, catalogs bugs, and
+manages submitted patches, where patches could be linked to the bugs and
+requirements they address.
+
+
+Acknowledgements
+----------------
+
+My thanks are due to Christy Heyl for reviewing and contributing
+suggestions to this paper and motivating me to get it done, and to Jesse
+Vincent, Mark Miller, Christopher Simons, Jeff Dunmall, Wayne Gramlich,
+and Dean Tribble for their assistance with the first-round submission.
+
+
+Changes to this document
+------------------------
+
+- Added Boolean and Number types
+- Added section Hyperdatabase Implementations
+- "Item" has been renamed to "Issue" to account for the more specific
+  nature of the Class.
+- New Templating
+- Access Controls
+- Added "actor" property
+
+------------------
+
+Back to `Table of Contents`_
+
+.. _`Table of Contents`: index.html
+.. _customisation: customizing.html
+

Added: tracker/vendor/roundup/current/doc/developers.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/developers.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,477 @@
+==================
+Developing Roundup
+==================
+
+:Version: $Revision: 1.14 $
+
+.. note::
+   The intended audience of this document is the developers of the core
+   Roundup code. If you just wish to alter some behaviour of your Roundup
+   installation, see `customising roundup`_.
+
+.. contents::
+
+Getting Started
+---------------
+
+Anyone wishing to help in the development of Roundup must read `Roundup's
+Design Document`_ and the `implementation notes`_.
+
+All development is coordinated through two resources:
+
+- roundup-dev mailing list at
+  http://lists.sourceforge.net/mailman/listinfo/roundup-devel
+- Sourceforge's issue trackers at
+  https://sourceforge.net/tracker/?group_id=31577
+
+Small Changes
+-------------
+
+Most small changes can be submitted through the Feature tracker, with patches
+attached that give context diffs of the affected source.
+
+
+CVS Access
+----------
+
+To get CVS access, contact richard at users.sourceforge.net.
+
+CVS stuff:
+
+1. to tag a release (eg. the pre-release of 0.5.0)::
+
+    cvs tag release-0-5-0-pr1
+
+1. to make a branch (eg. branching for code freeze/release)::
+
+    cvs co -d maint-0-5 -r release-0-5-0-pr1 roundup
+    cd maint-0-5 
+    cvs tag -b maint-0-5
+
+2. to check out a branch (eg. the maintenance branch for 0.5.x)::
+
+    cvs co -d maint-0-5 -r maint-0-5
+
+3. to merge changes from the maintenance branch to the trunk, in the
+   directory containing the HEAD checkout::
+
+    cvs up -j maint-0-5
+
+   though this is highly discouraged, as it generally creates a whole swag
+   of conflicts :(
+
+Standard tag names:
+
+*release-maj-min-patch[-sub]*
+  Release of the major.minor.patch release, possibly a beta or pre-release,
+  in which case *sub* will be one of "b*N*" or "pr*N*".
+*maint-maj-min*
+  Maintenance branch for the major.minor release. Patch releases are tagged in
+  this branch.
+
+Typically, release happen like this:
+
+1. work progresses in the HEAD branch until milestones are met,
+2. a series of beta releases are tagged in the HEAD until the code is
+   stable enough to freeze,
+3. the pre-release is tagged in the HEAD, with the resultant code branched
+   to the maintenance branch for that release,
+4. bugs in the release are patched in the maintenance branch, and the final
+   and patch releases are tagged there, and
+5. further major work happens in the HEAD.
+
+Project Rules
+-------------
+
+Mostly the project follows Guido's Style (though naming tends to be a little
+relaxed sometimes). In short:
+
+- 80 column width code
+- 4-space indentations
+- All modules must have a CVS Id line near the top
+
+Other project rules:
+
+- New functionality must be documented, even briefly (so at least we know
+  where there's missing documentation) and changes to tracker configuration
+  must be logged in the upgrading document.
+- subscribe to roundup-checkins to receive checkin notifications from the
+  other developers with CVS access
+- discuss any changes with the other developers on roundup-dev. If nothing
+  else, this makes sure there's no rude shocks
+- write unit tests for changes you make (where possible), and ensure that
+  all unit tests run before committing changes
+- run pychecker over changed code
+
+The administrators of the project reserve the right to boot developers who
+consistently check in code which is either broken or takes the codebase in
+directions that have not been agreed to.
+
+
+Debugging Aids
+--------------
+
+Try turning on logging of DEBUG level messages. This may be done a number
+of ways, depending on what it is you're testing:
+
+1. If you're testing the database unit tests, then set the environment
+   variable ``LOGGING_LEVEL=DEBUG``. This may be done like so:
+
+    LOGGING_LEVEL=DEBUG python run_tests.py
+
+   This variable replaces the older HYPERDBDEBUG environment var.
+
+2. If you're testing a particular tracker, then set the logging level in
+   your tracker's ``config.ini``.
+
+
+Internationalization Notes
+--------------------------
+
+How stuff works:
+
+1. Strings that may require translation (messages in human language)
+   are marked in the source code.  This step is discussed in
+   `Marking Strings for Translation`_ section.
+
+2. These strings are all extracted into Message Template File
+   ``locale/roundup.pot`` (_`POT` file).  See `Extracting Translatable
+   Messages`_ below.
+
+3. Language teams use POT file to make Message Files for national
+   languages (_`PO` files).  All PO files for Roundup are kept in
+   the ``locale`` directory.  Names of these files are target
+   locale names, usually just 2-letter language codes.  `Translating
+   Messages`_ section of this chapter gives useful hints for
+   message translators.
+
+4. Translated Message Files are compiled into binary form (_`MO` files)
+   and stored in ``locale`` directory (but not kept in the `Roundup
+   CVS`_ repository, as they may be easily made from PO files).
+   See `Compiling Message Catalogs`_ section.
+
+5. Roundup installer creates runtime locale structure on the file
+   system, putting MO files in their appropriate places.
+
+6. Runtime internationalization (_`I18N`) services use these MO files
+   to translate program messages into language selected by current
+   Roundup user.  Roundup command line interface uses locale name
+   set in OS environment variable ``LANGUAGE``, ``LC_ALL``,
+   ``LC_MESSAGES``, or ``LANG`` (in that order).  Roundup Web User
+   Interface uses language selected by currently authenticated user.
+
+Additional details may be found in `GNU gettext`_ and Python `gettext
+module`_ documentation.
+
+`Roundup source distribution`_ includes POT and PO files for message
+translators, and also pre-built MO files to facilitate installations
+from source.  Roundup binary distribution includes MO files only.
+
+.. _GNU gettext:
+
+GNU gettext package
+^^^^^^^^^^^^^^^^^^^
+
+This chapter is full of references to GNU `gettext package`_.
+GNU gettext is a "must have" for nearly all steps of internationalizing
+any program, and it's manual is definetely a recommended reading
+for people involved in `I18N`_.
+
+There are GNU gettext ports to all major OS platforms.
+Windows binaries are available from `GNU mirror sites`_.
+
+Roundup does not use GNU gettext at runtime, but it's tools
+are used for `extracting translatable messages`_, `compiling
+message catalogs`_ and, optionally, for `translating messages`_.
+
+Note that ``gettext`` package in some OS distributions means just
+runtime tools and libraries.  In such cases gettext development tools
+are usually distributed in separate package named ``gettext-devel``.
+
+Marking Strings for Translation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Strings that need translation must be marked in the source code.
+Following subsections explain how this is done in different cases.
+
+If translatable string is used as a format string, it is recommended
+to always use *named* format specifiers::
+
+  _('Index of %(classname)s') % locals()
+
+This helps translators to better understand the context of the
+message and, with Python formatting, remove format specifier altogether
+(which is sometimes useful, especially in singular cases of `Plural Forms`_).
+
+When there is more than one format specifier in the translatable
+format string, named format specifiers **must** be used almost always,
+because translation may require different order of items.
+
+It is better to *not* mark for translation strings that are not
+locale-dependent, as this makes it more difficult to keep track
+of translation completeness.  For example, string ``</ol></body></html>``
+(in ``index()`` method of the request handler in ``roundup_server``
+script) has no human readable parts at all, and needs no translations.
+Such strings are left untranslated in PO files, and are reported
+as such by PO status checkers (e.g. ``msgfmt --statistics``).
+
+Command Line Interfaces
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Scripts and routines run from the command line use "static" language
+defined by environment variables recognized by ``gettext`` module
+from Python library (``LANGUAGE``, ``LC_ALL``, ``LC_MESSAGES``, and
+``LANG``).  Primarilly, these are ``roundup-admin`` script and
+``admin.py`` module, but also help texts and startup error messages
+in other scripts and their supporting modules.
+
+For these interfaces, Python ``gettext`` engine must be initialized
+to use Roundup message catalogs.  This is normally done by including
+the following line in the module imports::
+
+  from i18n import _, ngettext
+
+Simple translations are automatically marked by calls to builtin
+message translation function ``_()``::
+
+  print _("This message is translated")
+
+Translations for messages whose grammatical depends on a number
+must be done by ``ngettext()`` function::
+
+  print ngettext("Nuked %i file", "Nuked %i files", number_of_files_nuked)
+
+Deferred Translations
+~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes translatable strings appear in the source code in untranslated
+form [#note_admin.py]_ and must be translated elsewhere.
+Example::
+
+  for meal in ("spam", "egg", "beacon"):
+      print _(meal)
+
+In such cases, strings must be marked for translation without actual
+call to the translating function.  To mark these strings, we use Python
+feature of automatic concatenation of adjacent strings and different
+types of string quotes::
+
+  strings_to_translate = (
+      ''"This string will be translated",
+      ""'me too',
+      ''r"\raw string",
+      ''"""
+      multiline string"""
+  )
+
+.. [#note_admin.py] In current Roundup sources, this feature is
+   extensively used in the ``admin`` module using method docstrings
+   as help messages.
+
+Web User Interface
+~~~~~~~~~~~~~~~~~~
+
+For Web User Interface, translation services are provided by Client
+object.  Action classes have methods ``_()`` and ``gettext()``,
+delegating translation to the Client instance.  In HTML templates,
+translator object is available as context variable ``i18n``.
+
+HTML templates have special markup for translatable strings.
+The syntax for this markup is defined on `ZPTInternationalizationSupport`_
+page.  Roundup translation service currently ignores values for
+``i18n:domain``, ``i18n:source`` and ``i18n:target``.
+
+Template markup examples:
+
+* simplest case::
+
+    <div i18n:translate="">
+     Say
+     no
+     more!
+    </div>
+
+  this will result in msgid ``"Say no more!"``, with all leading and
+  trailing whitespace stripped, and inner blanks replaced with single
+  space character.
+
+* using variable slots::
+
+    <div i18n:translate="">
+     And now...<br/>
+     No.<span tal:replace="number" i18n:name="slideNo" /><br/>
+     THE LARCH
+    </div>
+
+  Msgid will be: ``"And now...<br /> No.${slideNo}<br /> THE LARCH"``.
+  Template rendering will use context variable ``number`` (you may use
+  any expression) to put instead of ``${slideNo}`` in translation.
+
+* attribute translation::
+
+    <button name="btn_wink" value=" Wink " i18n:attributes="value" />
+
+  will translate the caption (and return value) for the "wink" button.
+
+* explicit msgids.  Sometimes it may be useful to specify msgid
+  for the element translation explicitely, like this::
+
+    <span i18n:translate="know what i mean?">this text is ignored</span>
+
+  When rendered, element contents will be replaced by translation
+  of the string specified in ``i18n:translate`` attribute.
+
+* ``i18n`` in `TALES`_.  You may translate strings in `TALES`_ python
+  expressions::
+
+    <span tal:replace="python: i18n.gettext('Oh, wicked.')" />
+
+* plural forms.  There is no markup for plural forms in `TAL`_ i18n.
+  You must use python expression for that::
+
+    <span tal:replace="python: i18n.ngettext(
+      'Oh but it\'s only %i shilling.',
+      'Oh but it\'s only %i shillings.',
+      fine) % fine"
+    />
+
+Extracting Translatable Messages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The most common tool for message extraction is ``xgettext`` utility
+from `GNU gettext package`_.  Unfortunately, this utility has no means
+of `Deferred Translations`_ in Python sources.  There is ``xpot`` tool
+from Francois Pinard free `PO utilities`_ that allows to mark strings
+for deferred translations, but it does not handle `plural forms`_.
+
+Roundup overcomes these limitations by using both of these utilities.
+This means that you need both `GNU gettext`_ tools and `PO utilities`_
+to build the Message Template File yourself.
+
+Latest Message Template File is kept in `Roundup CVS`_ and distributed
+with `Roundup Source`_.  If you wish to rebuild the template yourself,
+make sure that you have both ``xpot`` and ``xgettext`` installed and
+just run ``gmake`` (or ``make``, if you are on a `GNU`_ system like
+`linux`_ or `cygwin`_) in the ``locale`` directory.
+
+For on-site i18n, Roundup provides command-line utility::
+
+  roundup-gettext <tracker_home>
+
+extracting translatable messages from tracker's html templates.
+This utility creates message template file ``messages.pot`` in
+``locale`` subdirectory of the tracker home directory.  Translated
+messages may be put in *locale*.po files (where *locale* is selected
+locale name) in the same directory, e.g.: ``locale/ru.po``.
+These message catalogs are searched prior to system-wide translations
+kept in the ``share`` directory.
+
+Translating Messages
+^^^^^^^^^^^^^^^^^^^^
+
+Gettext Message File (`PO`_ file) is a plain text file, that can be created
+by simple copying ``roundup.pot`` to new .po file, like this::
+
+  $ cp roundup.pot ru.po
+
+The name of PO file is target locale name, usually just 2-letter language
+code (``ru`` for Russian in the above example).  Alternatively, PO file
+may be initialized by ``msginit`` utility from `GNU gettext`_ tools::
+
+  $ msginit -i roundup.pot
+
+``msginit`` will check your current locale, and initialize the header
+entry, setting language name, rules for `plural forms`_ and, if available,
+translator's name and email address.  The name for PO file is also chosen
+based on current locale.
+
+Next, you will need to edit this file, filling all ``msgstr`` lines with
+translations of the above ``msgid`` entries.  PO file is a plain text
+file that can be edited with any text editor.  However, there are several
+tools that may help you with this process:
+
+ - ``po-mode`` for `emacs`_.  One of `GNU gettext`_ tools.  Very handy,
+   definitely recommended if you are comfortable with emacs.  Cannot
+   handle `plural forms`_ per se, but allows to edit them in simple
+   text mode.
+
+ - `po filetype plugin`_ for `vim`_.  Does not do as much as ``po-mode``,
+   but helps in finding untranslated and fuzzy strings, and checking
+   code references.  Please contact `alexander smishlajev`_ if you
+   prefer this, as i have patched this plugin a bit.  I have also
+   informed the original plugin author about these changes, but got
+   no reply so far.
+
+ - `poEdit`_ by Vaclav Slavik.  Nice cross-platform GUI editor.
+   Unfortunately, it does not handle `plural forms`_.  Even worse,
+   it deletes all messages with plural forms when the file is saved.
+   Still, it may be useful to initially translate most of the messages
+   and add plural form messages later.
+
+ - `KBabel`_.  Being part of `KDE`_, it works in X windows only.
+    At the first glance looks pretty hairy, with all bells and whistles.
+    Haven't had much experience with it, though.
+
+Compiling Message Catalogs
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Message catalogs (`PO`_ files) must be compiled into binary form
+(`MO`_ files) before they can be used in the application.  This
+compilation is handled by ``msgfmt`` utility from `GNU gettext`_
+tools.  ``GNUmakefile`` in the ``locale`` directory automatically
+compiles all existing message catalogs after updating them from
+Roundup source files.  If you wish to rebuild an individual `MO`_
+file without making everything else, you may, for example::
+
+  $ msgfmt --statistics -o ru.mo ru.po
+
+This way, message translators can check their `PO`_ files without
+extracting strings from source.  (Note: String extraction requires
+additional utility that is not part of `GNU gettext`_.  See `Extracting
+Translatable Messages`_.)
+
+At run time, Roundup automatically compiles message catalogs whenever
+`PO`_ file is changed.
+
+-----------------
+
+Back to `Table of Contents`_
+
+.. _`Table of Contents`: index.html
+.. _`Customising Roundup`: customizing.html
+.. _`Roundup's Design Document`: spec.html
+.. _`implementation notes`: implementation.html
+
+
+.. _External hyperlink targets:
+
+.. _alexander smishlajev:
+.. _als: http://sourceforge.net/users/a1s/
+.. _cygwin: http://www.cygwin.com/
+.. _emacs: http://www.gnu.org/software/emacs/
+.. _gettext package: http://www.gnu.org/software/gettext/
+.. _gettext module: http://docs.python.org/lib/module-gettext.html
+.. _GNU: http://www.gnu.org/
+.. _GNU mirror sites: http://www.gnu.org/prep/ftp.html
+.. _KBabel: http://i18n.kde.org/tools/kbabel/
+.. _KDE: http://www.kde.org/
+.. _linux: http://www.linux.org/
+.. _Plural Forms:
+    http://www.gnu.org/software/gettext/manual/html_node/gettext_150.html
+.. _po filetype plugin:
+    http://vim.sourceforge.net/scripts/script.php?script_id=695
+.. _PO utilities: http://po-utils.progiciels-bpi.ca/
+.. _poEdit: http://poedit.sourceforge.net/
+.. _Roundup CVS: http://sourceforge.net/cvs/?group_id=31577
+.. _Roundup Source:
+.. _Roundup source distribution:
+.. _Roundup binary distribution:
+    http://sourceforge.net/project/showfiles.php?group_id=31577
+.. _TAL:
+.. _Template Attribute Language:
+   http://dev.zope.org/Wikis/DevSite/Projects/ZPT/TAL%20Specification%201.4
+.. _TALES:
+.. _Template Attribute Language Expression Syntax:
+   http://dev.zope.org/Wikis/DevSite/Projects/ZPT/TALES%20Specification%201.3
+.. _vim: http://www.vim.org/
+.. _ZPTInternationalizationSupport: http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/ZPTInternationalizationSupport

Added: tracker/vendor/roundup/current/doc/features.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/features.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,109 @@
+================
+Roundup Features
+================
+
+Roundup is a simple-to-use and -install issue-tracking system with
+web, e-mail and command-line interfaces. It is based on the winning design
+from Ka-Ping Yee in the Software Carpentry "Track" design competition.
+
+*simple to install*
+ - installation (including web interface) takes about 30 minutes
+ - instant-gratification ``python demo.py`` :)
+ - two templates included in the distribution for you to base your tracker on
+ - play with the demo, customise it and then use *it* as the template for
+   your production tracker
+ - requires *no* additional support software - python (2.3+) is
+   enough to get you going
+ - easy to set up higher-performance storage backends like sqlite_,
+   metakit_, mysql_ and postgresql_
+
+*simple to use*
+ - accessible through the web, email, command-line or Python programs
+ - may be used to track bugs, features, user feedback, sales opportunities,
+   milestones, ...
+ - automatically keeps a full history of changes to issues with
+   configurable verbosity and easy access to information about who created
+   or last modified *any* item in the database
+ - issues have their own mini mailing list (nosy list)
+ - users may sign themselves up, there may be automatic signup for
+   incoming email and users may handle their own password reset requests
+
+*highly configurable*
+ - web interface HTML is fully editable
+ - database schema is also fully editable (only the "user" class is required)
+   with a full set of data types (including dates and many-to-many relations)
+   across all storages available
+ - customised automatic auditors and reactors may be written that perform
+   actions before and after changes are made to entries in the database,
+   or may veto the creation or modification of items int he database
+ - samples are provided for all manner of configuration changes and
+   customisations
+
+*fast, scalable*
+ - with the sqlite, metakit, mysql and postgresql backends, roundup is
+   also fast and scalable, easily handling thousands of issues and users
+   with decent response times
+ - database indexes are automatically added for those backends that
+   support them (sqlite, metakit, mysql and postgresql)
+ - indexed text searching giving fast responses to searches across all
+   messages and indexed string properties
+ - support for the Xapian full-text indexing engine for large trackers
+
+*documented*
+ - documentation exists for installation, upgrading, maintenance, users and
+   customisation
+
+*web interface*
+ - fully editable interfaces for listing and display of items
+ - extendable to include wizards, parent/meta bug displays, ...
+ - differentiates between anonymous, known and admin users
+ - may be set up to require login, and may also only allow admin users
+   to register new users
+ - authentication of user registration and user-driven password resetting
+   using email and one time keys
+ - may be run through CGI as a normal cgi script, as a stand-alone
+   web server, or through Zope
+ - searching may be performed using many constraints, including a full-text
+   search of messages attached to issues
+ - file attachments (added through the web or email) are served up with the
+   correct content-type and filename
+ - email change messages generated by roundup appear to be sent by the
+   person who made the change, but responses will go back through the nosy
+   list by default
+ - flexible access control built around Permissions and Roles with assigned
+   Permissions
+ - generates valid HTML4 or XHTML
+ - detects concurrent user changes
+ - saving and editing of user-defined queries which may optionally be
+   shared with other users
+
+*e-mail interface*
+ - may be set up using sendmail-like delivery alias, POP polling or mailbox
+   polling
+ - may auto-register users who send in mail and aren't known to roundup
+ - nosy list configuration controls how people are added and when messages
+   are sent to the list
+ - auto-filing of "unformatted" messages into a particular class
+ - e-mail attachments are handled sanely, being attached to the issue they're
+   intended for, and forwarded on to the nosy list
+ - sane handling of content-type and content-encoding of messages (text/plain
+   preferred in all situations)
+ - email packages that display threading will show issue messages correctly
+   threaded
+ - users may send in messages from multiple addresses and be associated
+   with the same roundup username
+ - built-in security features like TLS and APOP
+
+*command-line*
+ - may be used to interactively manage roundup databases
+ - may be scripted using standard shell scripting
+ - roundup's API may also be used by other Python programs - a sample is
+   provided that runs once a day and emails people their assigned issues
+ - a variety of sample shell scripts are provided (weekly reports, issue
+   generation, ...)
+
+.. _sqlite: http://www.hwaci.com/sw/sqlite/
+.. _metakit: http://www.equi4.com/metakit/
+.. _mysql: http://sourceforge.net/projects/mysql-python
+.. _postgresql: http://initd.org/software/initd/psycopg
+

Added: tracker/vendor/roundup/current/doc/glossary.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/glossary.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,37 @@
+================
+Roundup Glossary
+================
+
+:Version: $Revision: 1.5 $
+
+.. contents::
+
+
+class
+   a definition of the properties and behaviour of a set of items
+db (or hyperdb)
+   a collection of items
+designator
+   a combined class + itemid reference to any item in the hyperdb
+itemid
+   a numeric reference to a particular item of one class
+item
+   a collection of data that forms one entry in the hyperdb.
+property
+   one element of data that makes up an item. In Roundup, item
+   properties may be changed as needed - even after the tracker
+   has been initialised and used in production.
+schema
+   the definition of all the classes that make up an tracker
+tracker
+   the schema and hyperdb that forms one issue tracker
+tracker home
+   the physical location on disk of a tracker
+
+
+-----------------
+
+Back to `Table of Contents`_
+
+.. _`Table of Contents`: index.html
+

Added: tracker/vendor/roundup/current/doc/images/edit.png
==============================================================================
Binary file. No diff available.

Added: tracker/vendor/roundup/current/doc/images/hyperdb.png
==============================================================================
Binary file. No diff available.

Added: tracker/vendor/roundup/current/doc/images/logo-acl-medium.png
==============================================================================
Binary file. No diff available.

Added: tracker/vendor/roundup/current/doc/images/logo-codesourcery-medium.png
==============================================================================
Binary file. No diff available.

Added: tracker/vendor/roundup/current/doc/images/logo-software-carpentry-standard.png
==============================================================================
Binary file. No diff available.

Added: tracker/vendor/roundup/current/doc/images/roundup-1.png
==============================================================================
Binary file. No diff available.

Added: tracker/vendor/roundup/current/doc/images/roundup.png
==============================================================================
Binary file. No diff available.

Added: tracker/vendor/roundup/current/doc/implementation.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/implementation.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,55 @@
+====================
+Implementation notes
+====================
+
+:Version: $Revision: 1.6 $
+
+[see also the roundup package docstring]
+
+There have been some modifications to the spec. I've marked these in the
+source with 'XXX' comments when I remember to.
+
+In short:
+ Class.find() - may match multiple properties, uses keyword args.
+
+ Class.filter() - isn't in the spec and it's very useful to have at the
+    Class level.
+
+ CGI interface index view specifier layout part - lose the '+' from the
+    sorting arguments (it's a reserved URL character ;). Just made no
+    prefix mean ascending and '-' prefix descending.
+
+ ItemClass - renamed to IssueClass to better match it only having one
+    hypderdb class "issue". Allowing > 1 hyperdb class breaks the
+    "superseder" multilink (since it can only link to one thing, and
+    we'd want bugs to link to support and vice-versa).
+
+ template - the call="link()" is handled by special-case mechanisms in
+    my top-level CGI handler. In a nutshell, the handler looks for a
+    method on itself called 'index%s' or 'item%s' where %s is a class.
+    Most items pass on to the templating mechanism, but the file class
+    _always_ does downloading. It'll probably stay this way too...
+
+ template - call="link(property)" may be used to link "the current item"
+    (from an index) - the link text is the property specified.
+
+ template - added functions that I found very useful: List, History and
+    Submit.
+
+ template - items must specify the message lists, history, etc. Having
+    them by default was sometimes not wanted.
+
+ template - index view determines its default columns from the
+    template's ``tal:condition="request/show/<property>"`` directives.
+
+ template - menu() and field() look awfully similar now .... ;)
+
+ roundup_admin.py - the command-line tool has a lot more commands at its
+    disposal
+
+-----------------
+
+Back to `Table of Contents`_
+
+.. _`Table of Contents`: index.html
+

Added: tracker/vendor/roundup/current/doc/index.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/index.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,170 @@
+=======================================================
+Roundup: an Issue-Tracking System for Knowledge Workers
+=======================================================
+
+Contents
+========
+
+- Features__
+- Installation__ and Upgrading__ existing installs
+- `Frequently Asked Questions`__
+- `User Guide`__
+- `Configuring and Customising Roundup`__
+- `Administering Roundup Trackers`__
+- `Roundup's Design`__ (original__)
+- `Developing Roundup`__
+- `Roundup Tracker Templates`__
+- Contact_
+- Acknowledgements_
+- License_
+
+__ features.html
+__ installation.html
+__ upgrading.html
+__ FAQ.html
+__ user_guide.html
+__ customizing.html
+__ admin_guide.html
+__ design.html
+__ spec.html
+__ developers.html
+__ tracker_templates.html
+
+Contact
+=======
+
+For general support enquiries about usage, a mailing list is available:
+
+    roundup-users at sourceforge.net
+
+If you've got a great idea for roundup, or have found a bug, please
+submit an issue to the tracker at: 
+
+    http://sourceforge.net/tracker/?group_id=31577
+
+For discussions about developing or enhancing roundup:
+
+    roundup-devel at sourceforge.net
+
+The admin for this project is Richard Jones:
+
+    richard at users.sourceforge.net
+
+but he should only be contacted directly when none of the
+above avenues of contact are suitable.
+
+
+Acknowledgements
+================
+
+Go Ping, you rock! Also, go Common Ground, ekit.com and Bizar Software for
+letting me implement this system on their time.
+
+Thanks also to the many people on the mailing list, in the sourceforge
+project and those who just report bugs:
+Thomas Arendsen Hein,
+Anthony Baxter,
+Marlon van den Berg,
+Bo Berglund,
+Stéphane Bidoul,
+Cameron Blackwood,
+Jeff Blaine,
+Duncan Booth,
+Seb Brezel,
+J Alan Brogan,
+Titus Brown,
+Steve Byan,
+Godefroid Chapelle,
+Roch'e Compaan,
+Wil Cooley,
+Joe Cooper,
+Kelley Dagley,
+Paul F. Dubois,
+Andrew Eland,
+Jeff Epler,
+Tom Epperly,
+Tamer Fahmy,
+Vickenty Fesunov,
+Hernan Martinez Foffani,
+Stuart D. Gathman,
+Ajit George,
+Frank Gibbons,
+Johannes Gijsbers,
+Gus Gollings,
+Dan Grassi,
+Robin Green,
+Jason Grout,
+Charles Groves,
+Engelbert Gruber,
+Bruce Guenter,
+Thomas Arendsen Hein,
+Juergen Hermann,
+Uwe Hoffmann,
+Tobias Hunger,
+Simon Hyde,
+Paul Jimenez,
+Christophe Kalt,
+Brian Kelley,
+James Kew,
+Sheila King,
+Michael Klatt,
+Bastian Kleineidam,
+Axel Kollmorgen,
+Detlef Lannert,
+Andrey Lebedev,
+Henrik Levkowetz,
+David Linke,
+Fredrik Lundh,
+Georges Martin,
+Gordon McMillan,
+John F Meinel Jr,
+Stefan Niederhauser,
+Truls E. Næss,
+Patrick Ohly,
+Luke Opperman,
+Eddie Parker,
+Will Partain,
+Ewout Prangsma,
+Marcus Priesch,
+Bernhard Reiter,
+Roy Rapoport,
+John P. Rouillard,
+Ollie Rutherfurd,
+Toby Sargeant,
+Giuseppe Scelsi,
+Ralf Schlatterbeck,
+Gregor Schmid,
+Florian Schulze,
+Klamer Schutte,
+Dougal Scott,
+Stefan Seefeld,
+Jouni K Seppänen,
+Jeffrey P Shell,
+Dan Shidlovsky,
+Joel Shprentz,
+Terrel Shumway,
+Emil Sit,
+Alexander Smishlajev,
+Nathaniel Smith,
+Maciej Starzyk,
+Mitchell Surface,
+Mike Thompson,
+Michael Twomey,
+Karl Ulbrich,
+Martin Uzak,
+Darryl VanDorp,
+J Vickroy,
+Timothy J. Warren,
+William (Wilk),
+Tue Wennerberg,
+Matt Wilbert,
+Chris Withers,
+Milan Zamazal.
+
+
+
+License
+=======
+
+See COPYING.txt in the software distribution for the licensing terms.
+

Added: tracker/vendor/roundup/current/doc/installation.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/installation.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,891 @@
+==================
+Installing Roundup
+==================
+
+:Version: 1.76
+
+.. contents::
+   :depth: 2
+
+
+Overview
+========
+
+Broken out separately, there are several conceptual pieces to a
+Roundup installation:
+
+Roundup trackers
+ Trackers consist of issues (be they bug reports or otherwise), tracker
+ configuration file(s), web HTML files etc. Roundup trackers are initialised
+ with a "Template" which defines the fields usable/assignable on a
+ per-issue basis.  Descriptions of the provided templates are given in
+ `choosing your template`_.
+
+Roundup support code
+ Installed into your Python install's lib directory.
+
+Roundup scripts
+ These include the email gateway, the roundup
+ HTTP server, the roundup administration command-line interface, etc.
+
+
+Prerequisites
+=============
+
+Roundup requires Python 2.3 or newer with a functioning anydbm
+module. Download the latest version from http://www.python.org/.
+It is highly recommended that users install the latest patch version
+of python as these contain many fixes to serious bugs.
+
+Some variants of Linux will need an additional "python dev" package
+installed for Roundup installation to work. Debian and derivatives, are
+known to require this.
+
+If you're on windows, you will either need to be using the ActiveState python
+distribution (at http://www.activestate.com/Products/ActivePython/), or you'll
+have to install the win32all package separately (get it from
+http://starship.python.net/crew/mhammond/win32/).
+
+
+Optional Components
+===================
+
+You may optionally install and use:
+
+An RDBMS
+  Sqlite, MySQL and Postgresql are all supported by Roundup and will be
+  used if available. One of these is recommended if you are anticipating a
+  large user base (see `choosing your backend`_ below).
+
+Xapian full-text indexer
+  The Xapian_ full-text indexer is also supported and will be used by
+  default if it is available. This is strongly recommended if you are
+  anticipating a large number of issues (> 5000).
+
+  You may install Xapian at any time, even after a tracker has been
+  installed and used. You will need to run the "roundup-admin reindex"
+  command if the tracker has existing data.
+
+  Roundup requires Xapian *newer* than 0.9.2 - it may be necessary for
+  you to install a snapshot. Snapshot "0.9.2_svn6532" has been tried
+  successfully.
+
+.. _Xapian: http://www.xapian.org/
+
+
+Getting Roundup
+===============
+
+.. note::
+    Some systems, such as Debian and NetBSD, already have Roundup
+    installed. Try running the command "roundup-admin" with no arguments,
+    and if it runs you may skip the `Basic Installation Steps`_
+    below and go straight to `configuring your first tracker`_.
+
+Download the latest version from http://roundup.sf.net/.
+
+If you're using WinZIP's "classic" interface, make sure the "Use
+folder names" check box is checked before you extract the files.
+
+
+For The Really Impatient
+========================
+
+If you just want to give Roundup a whirl Right Now, then simply run
+``python demo.py``. If you used the Windows installer, you should run the
+``roundup-demo`` program instead. Users of other binary distributions or
+pre-installed Roundup will need to download the source to use it.
+
+This will set up a simple demo tracker on your machine. [1]_
+When it's done, it'll print out a URL to point your web browser at
+so you may start playing. Three users will be set up:
+
+1. anonymous - the "default" user with permission to do very little
+2. demo (password "demo") - a normal user who may create issues
+3. admin (password "admin") - an administrative user who has complete
+   access to the tracker
+
+.. [1] Demo tracker is set up to be accessed by localhost browser.
+       If you run demo on a server host, please stop the demo when
+       it has shown startup notice, open file ``demo/config.ini`` with
+       your editor, change host name in the ``web`` option in section
+       ``[tracker]``, save the file, then re-run the demo program.
+
+Installation
+============
+
+Set aside 15-30 minutes. There's several steps to follow in your
+installation:
+
+1. `basic installation steps`_ if Roundup is not installed on your system
+2. `configuring your first tracker`_ that all installers must follow
+3. then optionally `configure a web interface`_
+4. and optionally `configure an email interface`_
+5. `UNIX environment steps`_ to take if you're installing on a shared
+   UNIX machine and want to restrict local access to roundup
+6. `additional language codecs`_
+
+For information about how Roundup installs, see the `administration
+guide`_.
+
+
+Basic Installation Steps
+------------------------
+
+To install the Roundup support code into your Python tree and
+Roundup scripts into /usr/bin (substitute that path for whatever is
+appropriate on your system). You need to have write permissions
+for these locations, eg. being root on unix::
+
+    python setup.py install
+
+If you would like to place the Roundup scripts in a directory other
+than ``/usr/bin``, then specify the preferred location with
+``--install-script``. For example, to install them in
+``/opt/roundup/bin``::
+
+    python setup.py install --install-scripts=/opt/roundup/bin
+
+You can also use the ``--prefix`` option to use a completely different
+base directory, if you do not want to use administrator rights. If you
+choose to do this, you may have to change Python's search path (sys.path)
+yourself.
+
+
+Configuring your first tracker
+------------------------------
+
+1. To create a Roundup tracker (necessary to do before you can
+   use the software in any real fashion), you need to set up a "tracker
+   home":
+
+   a. (Optional) If you intend to keep your roundup trackers
+      under one top level directory which does not exist yet,
+      you should create that directory now.  Example::
+
+         mkdir /opt/roundup/trackers
+
+   b. Either add the Roundup script location to your ``PATH``
+      environment variable or specify the full path to
+      the command in the next step.
+
+   c. Install a new tracker with the command ``roundup-admin install``.
+      You will be asked a series of questions.  Descriptions of the provided
+      templates can be found in `choosing your template`_ below.  Descriptions
+      of the available backends can be found in `choosing your backend`_
+      below.  The questions will be something like (you may have more
+      templates or backends available)::
+
+          Enter tracker home: /opt/roundup/trackers/support
+          Templates: classic
+          Select template [classic]: classic
+          Back ends: anydbm, mysql, sqlite
+          Select backend [anydbm]: anydbm
+
+      Note: "Back ends" selection list depends on availability of
+      third-party database modules.  Standard python distribution
+      includes anydbm module only.
+
+      The "support" part of the tracker name can be anything you want - it
+      is going to be used as the directory that the tracker information
+      will be stored in.
+
+      You will now be directed to edit the tracker configuration and
+      initial schema.  At a minimum, you must set "main :: admin_email"
+      (that's the "admin_email" option in the "main" section) "mail ::
+      host", "tracker :: web" and "mail :: domain".  If you get stuck,
+      and get configuration file errors, then see the `tracker
+      configuration`_ section of the `customisation documentation`_.
+
+      If you just want to get set up to test things quickly (and follow
+      the instructions in step 3 below), you can even just set the
+      "tracker :: web" variable to::
+
+         web = http://localhost:8080/support/
+
+      The URL *must* end in a '/', or your web interface *will not work*.
+      See `Customising Roundup`_ for details on configuration and schema
+      changes. You may change any of the configuration after
+      you've initialised the tracker - it's just better to have valid values
+      for this stuff now.
+
+   d. Initialise the tracker database with ``roundup-admin initialise``.
+      You will need to supply an admin password at this step. You will be
+      prompted::
+
+          Admin Password:
+                 Confirm:
+
+      Note: running this command will *destroy any existing data in the
+      database*. In the case of MySQL and PostgreSQL, any exsting database
+      will be dropped and re-created.
+
+      Once this is done, the tracker has been created.
+
+2. At this point, your tracker is set up, but doesn't have a nice user
+   interface. To set that up, we need to `configure a web interface`_ and
+   optionally `configure an email interface`_. If you want to try your
+   new tracker out, assuming "tracker :: web" is set to
+   ``'http://localhost:8080/support/'``, run::
+
+     roundup-server support=/opt/roundup/trackers/support
+
+   then direct your web browser at:
+
+     http://localhost:8080/support/
+
+   and you should see the tracker interface.
+
+
+Choosing Your Template
+----------------------
+
+Classic Template
+~~~~~~~~~~~~~~~~
+
+The classic template is the one defined in the `Roundup Specification`_. It
+holds issues which have priorities and statuses. Each issue may also have a
+set of messages which are disseminated to the issue's list of nosy users.
+
+Minimal Template
+~~~~~~~~~~~~~~~~
+
+The minimal template has the minimum setup required for a tracker
+installation. That is, it has the configuration files, defines a user database
+and the basic HTML interface to that. It's a completely clean slate for you to
+create your tracker on.
+
+
+Choosing Your Backend
+---------------------
+
+The actual storage of Roundup tracker information is handled by backends.
+There's several to choose from, each with benefits and limitations:
+
+========== =========== ===== ==============================
+Name       Speed       Users   Support
+========== =========== ===== ==============================
+anydbm     Slowest     Few   Always available
+sqlite     Fastest(*)  Few   Needs install (PySQLite_)
+metakit    Fastest(*)  Few   Needs install (metakit_)
+postgresql Fast        Many  Needs install/admin (psycopg_)
+mysql      Fast        Many  Needs install/admin (MySQLdb_)
+========== =========== ===== ==============================
+
+**sqlite** and **metakit**
+  These use the embedded database engines PySQLite_ and metakit_ to provide
+  very fast backends. They are not suitable for trackers which will have
+  many simultaneous users, but require much less installation and
+  maintenance effort than more scalable postgresql and mysql backends.
+  If you are choosing from these two, please select sqlite.
+**postgresql**
+  Backend for popular RDBMS PostgreSQL. You must read doc/postgresql.txt for
+  additional installation steps and requirements. You must also configure
+  the ``rdbms`` section of your tracker's ``config.ini``
+**mysql**
+  Backend for popular RDBMS MySQL. You must read doc/mysql.txt for additional
+  installation steps and requirements. You must also configure the ``rdbms``
+  section of your tracker's ``config.ini``
+
+You may defer your decision by setting your tracker up with the anydbm
+backend (which is guaranteed to be available) and switching to one of the
+other backends at any time using the instructions in the `administration
+guide`_.
+
+Regardless of which backend you choose, Roundup will attempt to initialise
+a new database for you when you run the roundup-admin "initialise" command.
+In the case of MySQL and PostgreSQL you will need to have the appropriate
+privileges to create databases.
+
+
+Configure a Web Interface
+-------------------------
+
+There are three web interfaces to choose from:
+
+1. `web server cgi-bin`_
+2. `stand-alone web server`_
+3. `Zope product - ZRoundup`_
+4. `Apache HTTP Server with mod_python`_
+
+You may need to give the web server user permission to access the tracker home
+- see the `UNIX environment steps`_ for information. You may also need to
+configure your system in some way - see `platform-specific notes`_.
+
+
+Web Server cgi-bin
+~~~~~~~~~~~~~~~~~~
+
+A benefit of using the cgi-bin approach is that it's the easiest way to
+restrict access to your tracker to only use HTTPS. Access will be slower
+than through the `stand-alone web server`_ though.
+
+If your Python isn't install as "python" then you'll need to edit
+the ``roundup.cgi`` script to fix the first line.
+
+If you're using IIS on a Windows platform, you'll need to run this command
+for the cgi to work (it turns on the PATH_INFO cgi variable)::
+
+    adsutil.vbs set w3svc/AllowPathInfoForScriptMappings TRUE
+
+The ``adsutil.vbs`` file can be found in either ``c:\inetpub\adminscripts`` 
+or ``c:\winnt\system32\inetsrv\adminsamples\`` or
+``c:\winnt\system32\inetsrv\adminscripts\`` depending on your installation.
+
+More information about ISS setup may be found at:
+
+   http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B276494
+
+Copy the ``cgi-bin/roundup.cgi`` file to your web server's ``cgi-bin``
+directory. You will need to configure it to tell it where your tracker home
+is. You can do this either:
+
+Through an environment variable
+  Set the variable TRACKER_HOMES to be a colon (":") separated list of
+  name=home pairs (if you're using apache, the SetEnv directive can do this)
+
+Directly in the ``roundup.cgi`` file itself
+  Add your instance to the TRACKER_HOMES variable as ``'name': 'home'``
+
+The "name" part of the configuration will appear in the URL and identifies the
+tracker (so you may have more than one tracker per cgi-bin script). Make sure
+there are no spaces or other illegal characters in it (to be safe, stick to
+letters and numbers). The "name" forms part of the URL that appears in the
+tracker config "tracker :: web" variable, so make sure they match. The "home"
+part of the configuration is the tracker home directory.
+
+If you're using Apache, you can use an additional trick to hide the
+``.cgi`` extension of the cgi script. Place the ``roundup.cgi`` script
+wherever you want it to be, renamed it to just ``roundup``, and add a
+couple lines to your Apache configuration::
+ 
+ <Location /path/to/roundup>
+   SetHandler cgi-script
+ </Location>
+
+
+Stand-alone Web Server
+~~~~~~~~~~~~~~~~~~~~~~
+
+This approach will give you the fastest of the three web interfaces. You may
+investigate using ProxyPass or similar configuration in apache to have your
+tracker accessed through the same URL as other systems.
+
+The stand-alone web server is started with the command ``roundup-server``. It
+has several options - display them with ``roundup-server -h``.
+
+The tracker home configuration is similar to the cgi-bin - you may either edit
+the script to change the TRACKER_HOMES variable or you may supply the
+name=home values on the command-line after all the other options.
+
+To make the server run in the background, use the "-d" option, specifying the
+name of a file to write the server process id (pid) to.
+
+
+Zope Product - ZRoundup
+~~~~~~~~~~~~~~~~~~~~~~~
+
+ZRoundup installs as a regular Zope product. Copy the ZRoundup directory to
+your Products directory either in INSTANCE_HOME/Products or the Zope
+code tree lib/python/Products.
+
+When you next (re)start up Zope, you will be able to add a ZRoundup object
+that interfaces to your new tracker.
+
+Apache HTTP Server with mod_python
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`Mod_python`_ is an `Apache`_ module that embeds the Python interpreter
+within the server.  Running Roundup this way is much faster than all
+above options and, like `web server cgi-bin`_, allows to use HTTPS
+protocol.  The drawback is that this setup is more complicated.
+
+The following instructions were tested on apache 2.0 with mod_python 3.1.
+If you are using older versions, your mileage may vary.
+
+Mod_python uses OS threads.  If your apache was built without threads
+(quite commonly), you must load the threading library to run mod_python.
+This is done by setting ``LD_PRELOAD`` to your threading library path
+in apache ``envvars`` file.  Example for gentoo linux (``envvars`` file
+is located in ``/usr/lib/apache2/build/``)::
+
+  LD_PRELOAD=/lib/libpthread.so.0
+  export LD_PRELOAD
+
+Example for FreeBSD (``envvars`` is in ``/usr/local/sbin/``)::
+
+  LD_PRELOAD=/usr/lib/libc_r.so
+  export LD_PRELOAD
+
+Next, you have to add Roundup trackers configuration to apache config.
+Roundup apache interface uses two options specified with ``PythonOption``
+directives:
+
+  TrackerHome:
+    defines the tracker home directory - the directory that was specified
+    when you did ``roundup-admin init``.  This option is required.
+
+  TrackerLaguage:
+    defines web user interface language.  mod_python applications do not
+    receive OS environment variables in the same way as command-line
+    programs, so the language cannot be selected by setting commonly
+    used variables like ``LANG`` or ``LC_ALL``.  ``TrackerLanguage``
+    value has the same syntax as values of these environment variables.
+    This option may be omitted.
+
+  TrackerDebug:
+    run the tracker in debug mode.  Setting this option to ``yes`` or
+    ``true`` has the same effect as running ``roundup-server -t debug``:
+    the database schema and used html templates are rebuilt for each
+    HTTP request.  Values ``no`` or ``false`` mean that all html
+    templates for the tracker are compiled and the database schema is
+    checked once at startup.  This is the default behaviour.
+
+  TrackerTiming:
+    has nearly the same effect as environment variable ``CGI_SHOW_TIMING``
+    for standalone roundup server.  The difference is that setting this
+    option to ``no`` or ``false`` disables timings display.  Value
+    ``comment`` writes request handling times in html comment, and
+    any other non-empty value makes timing report visible.  By default,
+    timing display is disabled.
+
+In the following example we have two trackers set up in
+``/var/db/roundup/support`` and ``var/db/roundup/devel`` and accessed
+as ``https://my.host/roundup/support/`` and ``https://my.host/roundup/devel/``
+respectively.  Having them share same parent directory allows us to
+reduce the number of configuration directives.  Support tracker has
+russian user interface.  The other tracker (devel) has english user
+interface (default).
+
+Static files from ``html`` directory are served by apache itself - this
+is quickier and generally more robust than doing that from python.
+Everything else is aliased to dummy (non-existing) ``py`` file,
+which is handled by mod_python and our roundup module.
+
+Example mod_python configuration::
+
+    #################################################
+    # Roundup Issue tracker
+    #################################################
+    # enable Python optimizations (like 'python -O')
+    PythonOptimize On
+    # let apache handle static files from 'html' directories
+    AliasMatch /roundup/(.+)/@@file/(.*) /var/db/roundup/$1/html/$2
+    # everything else is handled by roundup web UI
+    AliasMatch /roundup/([^/]+)/(?!@@file/)(.*) /var/db/roundup/$1/dummy.py/$2
+    # roundup requires a slash after tracker name - add it if missing
+    RedirectMatch permanent /roundup/([^/]+)$ /roundup/$1/
+    # common settings for all roundup trackers
+    <Directory /var/db/roundup/*>
+      Order allow,deny
+      Allow from all
+      AllowOverride None
+      Options None
+      AddHandler python-program .py
+      PythonHandler roundup.cgi.apache
+      # uncomment the following line to see tracebacks in the browser
+      # (note that *some* tracebacks will be displayed anyway)
+      #PythonDebug On
+    </Directory>
+    # roundup tracker homes
+    <Directory /var/db/roundup/support>
+      PythonOption TrackerHome /var/db/roundup/support
+      PythonOption TrackerLanguage ru
+    </Directory>
+    <Directory /var/db/roundup/devel>
+      PythonOption TrackerHome /var/db/roundup/devel
+    </Directory>
+
+
+Configure an Email Interface
+----------------------------
+
+If you don't want to use the email component of Roundup, then remove the
+"``nosyreaction.py``" module from your tracker "``detectors``" directory.
+
+See `platform-specific notes`_ for steps that may be needed on your system.
+
+There are three supported ways to get emailed issues into the
+Roundup tracker.  You should pick ONE of the following, all
+of which will continue my example setup from above:
+
+As a mail alias pipe process 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Set up a mail alias called "issue_tracker" as (include the quote marks):
+"``|/usr/bin/python /usr/bin/roundup-mailgw <tracker_home>``"
+(substitute ``/usr/bin`` for wherever roundup-mailgw is installed).
+
+In some installations (e.g. RedHat 6.2 I think) you'll need to set up smrsh so
+sendmail will accept the pipe command. In that case, symlink
+``/etc/smrsh/roundup-mailgw`` to "``/usr/bin/roundup-mailgw``" and change
+the command to::
+
+    |roundup-mailgw /opt/roundup/trackers/support
+ 
+To test the mail gateway on unix systems, try::
+
+    echo test |mail -s '[issue] test' support at YOUR_DOMAIN_HERE
+
+As a custom router/transport using a pipe process (Exim4 specific)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following configuration snippets for `Exim 4`_ configuration
+implement a custom router & transport to accomplish mail delivery to
+roundup-mailgw. A configuration for Exim3 is similar but not
+included, since Exim3 is considered obsolete.
+
+.. _Exim 4: http://www.exim.org/
+
+This configuration is similar to the previous section, in that it uses
+a pipe process. However, there are advantages to using a custom
+router/transport process, if you are using Exim.
+
+* This avoids privilege escalation, since otherwise the pipe process
+  will run as the mail user, typically mail. The transport can be
+  configured to run as the user appropriate for the task at hand. In the
+  transport described in this section, Exim4 runs as the unprivileged
+  user ``roundup``.
+
+* Separate configuration is not required for each tracker
+  instance. When a email arrives at the server, Exim passes it through
+  the defined routers. The roundup_router looks for a match with one of
+  the roundup directories, and if there is one it is passed to the
+  roundup_transport, which uses the pipe process described in the
+  previous section (`As a mail alias pipe process`_).
+
+The matching is done in the line::
+
+  require_files = /usr/bin/roundup-mailgw:ROUNDUP_HOME/$local_part/schema.py
+
+The following configuration has been tested on Debian Sarge with
+Exim4. 
+
+.. note::
+  Note that the Debian Exim4 packages don't allow pipes in alias files
+  by default, so the method described in the section `As a mail alias
+  pipe process`_ will not work with the default configuration. However,
+  the method described in this section does. See the discussion in
+  ``/usr/share/doc/exim4-config/README.system_aliases`` on any Debian
+  system with Exim4 installed.
+
+  For more Debian-specific information, see suggested addition to
+  README.Debian in
+  http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=343283, which will
+  hopefully be merged into the Debian package eventually.
+
+This config makes a few assumptions:
+
+* That the mail address corresponding to the tracker instance has the
+  same name as the directory of the tracker instance, i.e. the mail
+  interface address corresponding to a Roundup instance called
+  ``/var/lib/roundup/trackers/mytracker`` is ``mytracker at your.host``.
+
+* That (at least) all the db subdirectories of all the tracker
+  instances (ie. ``/var/lib/roundup/trackers/*/db``) are owned by the same
+  user, in this case, 'roundup'.
+
+* That if the ``schema.py`` file exists, then the tracker is ready for
+  use. Another option is to use the ``config.ini`` file, but this recently
+  changed (in 0.8) from ``config.py``.
+
+Macros for Roundup router/transport. Should be placed in the macros
+section of the Exim4 config::
+
+  # Home dir for your Roundup installation
+  ROUNDUP_HOME=/var/lib/roundup/trackers
+
+  # User and group for Roundup.
+  ROUNDUP_USER=roundup
+  ROUNDUP_GROUP=roundup
+
+Custom router for Roundup. This will (probably) work if placed at the
+beginning of the router section of the Exim4 config::
+
+  roundup_router:
+      driver = accept
+      # The config file config.ini seems like a more natural choice, but the
+      # file config.py was replaced by config.ini in 0.8, and schema.py needs
+      # to be present too.
+      require_files = /usr/bin/roundup-mailgw:ROUNDUP_HOME/$local_part/schema.py
+      transport = roundup_transport
+
+Custom transport for Roundup. This will (probably) work if placed at
+the beginning of the router section of the Exim4 config::
+
+  roundup_transport:
+      driver = pipe
+      command = /usr/bin/python /usr/bin/roundup-mailgw ROUNDUP_HOME/$local_part/
+      current_directory = ROUNDUP_HOME
+      home_directory = ROUNDUP_HOME
+      user = ROUNDUP_USER
+      group = ROUNDUP_GROUP
+
+As a regular job using a mailbox source
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Set ``roundup-mailgw`` up to run every 10 minutes or so. For example
+(substitute ``/usr/bin`` for wherever roundup-mailgw is installed)::
+
+  0,10,20,30,40,50 * * * * /usr/bin/roundup-mailgw /opt/roundup/trackers/support mailbox <mail_spool_file>
+
+Where the ``mail_spool_file`` argument is the location of the roundup submission
+user's mail spool. On most systems, the spool for a user "issue_tracker"
+will be "``/var/mail/issue_tracker``".
+
+As a regular job using a POP source
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To retrieve from a POP mailbox, use a *cron* entry similar to the mailbox
+one (substitute ``/usr/bin`` for wherever roundup-mailgw is
+installed)::
+
+  0,10,20,30,40,50 * * * * /usr/bin/roundup-mailgw /opt/roundup/trackers/support pop <pop_spec>
+
+where pop_spec is "``username:password at server``" that specifies the roundup
+submission user's POP account name, password and server.
+
+On windows, you would set up the command using the windows scheduler.
+
+As a regular job using an IMAP source
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To retrieve from an IMAP mailbox, use a *cron* entry similar to the
+POP one (substitute ``/usr/bin`` for wherever roundup-mailgw is
+installed)::
+
+  0,10,20,30,40,50 * * * * /usr/bin/roundup-mailgw /opt/roundup/trackers/support imap <imap_spec>
+
+where imap_spec is "``username:password at server``" that specifies the roundup
+submission user's IMAP account name, password and server. You may
+optionally include a mailbox to use other than the default ``INBOX`` with
+"``imap username:password at server mailbox``".
+
+If you have a secure (ie. HTTPS) IMAP server then you may use ``imaps``
+in place of ``imap`` in the command to use a secure connection.
+
+As with the POP job, on windows, you would set up the command using the
+windows scheduler.
+
+
+UNIX Environment Steps
+----------------------
+
+Each tracker ideally should have its own UNIX group, so create
+a UNIX group (edit ``/etc/group`` or your appropriate NIS map if
+you're using NIS).  To continue with my examples so far, I would
+create the UNIX group 'support', although the name of the UNIX
+group does not have to be the same as the tracker name.  To this
+'support' group I then add all of the UNIX usernames who will be
+working with this Roundup tracker.  In addition to 'real' users,
+the Roundup email gateway will need to have permissions to this
+area as well, so add the user your mail service runs as to the
+group (typically "mail" or "daemon").  The UNIX group might then
+look like::
+
+     support:*:1002:jblaine,samh,geezer,mail
+
+If you intend to use the web interface (as most people do), you
+should also add the username your web server runs as to the group.
+My group now looks like this::
+
+     support:*:1002:jblaine,samh,geezer,mail,apache
+
+The tracker "db" directory should be chmod'ed g+sw so that the group can
+write to the database, and any new files created in the database will be owned
+by the group.
+
+If you're using the mysql or postgresql backend then you'll need to ensure
+that the tracker user has appropriate permissions to create/modify the
+database. If you're using roundup.cgi, the apache user needs permissions
+to modify the database.  Alternatively, explicitly specify a database login
+in ``rdbms`` -> ``user`` and ``password`` in ``config.ini``.
+
+An alternative to the above is to create a new user who has the sole
+responsibility of running roundup. This user:
+
+1. runs the CGI interface daemon
+2. runs regular polls for email
+3. runs regular checks (using cron) to ensure the daemon is up
+4. optionally has no login password so that nobody but the "root" user
+   may actually login and play with the roundup setup.
+
+
+Additional Language Codecs
+--------------------------
+
+If you intend to send messages to Roundup that use Chinese, Japanese or
+Korean encodings the you'll need to obtain CJKCodecs from
+http://cjkpython.berlios.de/
+
+
+
+Maintenance
+===========
+
+Read the separate `administration guide`_ for information about how to
+perform common maintenance tasks with Roundup.
+
+
+Upgrading
+=========
+
+Read the separate `upgrading document`_, which describes the steps needed to
+upgrade existing tracker trackers for each version of Roundup that is
+released.
+
+
+Further Reading
+===============
+
+If you intend to use Roundup with anything other than the default
+templates, if you would like to hack on Roundup, or if you would
+like implementation details, you should read `Customising Roundup`_.
+
+
+Running Multiple Trackers
+=========================
+
+Things to think about before you jump off the deep end and install
+multiple trackers, which involve additional URLs, user databases, email
+addresses, databases to back up, etc.
+
+1. Do you want a tracker per product you sell/support? You can just add
+   a new property to your issues called Product, and filter by that. See
+   the customisation example `adding a new field to the classic schema`_.
+2. Do you want to track internal software development issues and customer
+   support issues separately? You can just set up an additional "issue"
+   class called "cust_issues" in the same tracker, mimicing the normal
+   "issue" class, but with different properties. See the customisation
+   example `tracking different types of issues`_.
+
+
+Platform-Specific Notes
+=======================
+
+Windows command-line tools
+--------------------------
+
+To make the command-line tools accessible in Windows, you need to update
+the "Path" environment variable in the Registry via a dialog box.
+
+On Windows 2000 and later:
+
+1) Press the "Start" button.
+2) Choose "Settings"
+3) Choose "Control Panel"
+4) Choose "System"
+5) Choose "Advanced"
+6) Choose "Environmental Variables"
+7) Add: "<dir>\Scripts" to the "Path" environmental variable.
+
+Where <dir> in 7) is the root directory (e.g., ``C:\Python22\Scripts``)
+of your Python installation.
+
+I understand that in XP, 2) above is not needed as "Control
+Panel" is directly accessible from "Start".
+
+I do not believe this is possible to do in previous versions of Windows.
+
+
+Windows Server
+--------------
+
+To have the Roundup web server start up when your machine boots up, set the
+following up in Scheduled Tasks (note, the following is for a cygwin setup):
+
+Run
+ ``c:\cygwin\bin\bash.exe -c "roundup-server TheProject=/opt/roundup/trackers/support"``
+Start In
+ ``C:\cygwin\opt\roundup\bin``
+Schedule
+ At System Startup
+
+To have the Roundup mail gateway run periodically to poll a POP email address,
+set the following up in Scheduled Tasks:
+
+Run
+ ``c:\cygwin\bin\bash.exe -c "roundup-mailgw /opt/roundup/trackers/support pop roundup:roundup at mail-server"``
+Start In
+ ``C:\cygwin\opt\roundup\bin``
+Schedule
+ Every 10 minutes from 5:00AM for 24 hours every day
+ Stop the task if it runs for 8 minutes
+
+
+Sendmail smrsh
+--------------
+
+If you use Sendmail's ``smrsh`` mechanism, you will need to tell
+smrsh that roundup-mailgw is a valid/trusted mail handler
+before it will work.
+
+This is usually done via the following 2 steps:
+
+1. make a symlink in ``/etc/smrsh`` called ``roundup-mailgw``
+   which points to the full path of your actual ``roundup-mailgw``
+   script.
+
+2. change your alias to ``"|roundup-mailgw <tracker_home>"``
+
+
+Linux
+-----
+
+Make sure you read the instructions under `UNIX environment steps`_.
+
+
+Solaris
+-------
+
+You'll need to build Python.
+
+Make sure you read the instructions under `UNIX environment steps`_.
+
+
+Problems? Testing your Python...
+================================
+
+.. note::
+   The ``run_tests.py`` script is packaged in Roundup's source distribution
+   - users of the Windows installer, other binary distributions or
+   pre-installed Roundup will need to download the source to use it.
+
+Once you've unpacked roundup's source, run ``python run_tests.py`` in the
+source directory and make sure there are no errors. If there are errors,
+please let us know!
+
+If the above fails, you may be using the wrong version of python. Try
+``python2 run_tests.py``. If that works, you will need to substitute
+``python2`` for ``python`` in all further commands you use in relation to
+Roundup -- from installation and scripts.
+
+
+-------------------------------------------------------------------------------
+
+Back to `Table of Contents`_
+
+Next: `User Guide`_
+
+.. _`table of contents`: index.html
+.. _`user guide`: user_guide.html
+.. _`roundup specification`: spec.html
+.. _`tracker configuration`: customizing.html#tracker-configuration
+.. _`customisation documentation`: customizing.html
+.. _`Adding a new field to the classic schema`:
+   customizing.html#adding-a-new-field-to-the-classic-schema
+.. _`Tracking different types of issues`:
+   customizing.html#tracking-different-types-of-issues
+.. _`customising roundup`: customizing.html
+.. _`upgrading document`: upgrading.html
+.. _`administration guide`: admin_guide.html
+
+
+.. _External hyperlink targets:
+
+.. _apache: http://httpd.apache.org/
+.. _metakit: http://www.equi4.com/metakit/
+.. _mod_python: http://www.modpython.org/
+.. _MySQLdb: http://sourceforge.net/projects/mysql-python
+.. _Psycopg: http://initd.org/software/initd/psycopg
+.. _pysqlite: http://pysqlite.org/

Added: tracker/vendor/roundup/current/doc/mysql.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/mysql.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,66 @@
+=============
+MySQL Backend
+=============
+
+:version: $Revision: 1.12 $
+
+This notes detail the MySQL backend for the Roundup issue tracker.
+
+
+Prerequisites
+=============
+
+To use MySQL as the backend for storing roundup data, you also need 
+to install:
+
+1. MySQL RDBMS 4.0.16 or higher - http://www.mysql.com. Your MySQL
+   installation MUST support InnoDB tables (or Berkeley DB (BDB) tables
+   if you have no other choice). If you're running < 4.0.16 (but not <4.0)
+   then you'll need to use BDB to pass all unit tests. Edit the
+   ``roundup/backends/back_mysql.py`` file to enable DBD instead of InnoDB.
+2. Python MySQL interface - http://sourceforge.net/projects/mysql-python
+
+.. note::
+   The InnoDB implementation has a bug__ that Roundup tickles. See
+
+__ http://bugs.mysql.com/bug.php?id=1810
+
+
+Running the MySQL tests
+=======================
+
+Roundup tests expect an empty MySQL database. Two alternate ways to provide 
+this:
+
+1. If you have root permissions on the MySQL server, you can create 
+   the necessary database entries using the follwing SQL sequence. Use
+   ``mysql`` on the command line to enter::
+
+       CREATE DATABASE rounduptest;
+       USE rounduptest;
+       GRANT ALL PRIVILEGES ON rounduptest.* TO rounduptest at localhost
+            IDENTIFIED BY 'rounduptest';
+       FLUSH PRIVILEGES;
+
+2. If your administrator has provided you with database connection info, 
+   you can modify MYSQL_* constants in the file test/test_db.py with 
+   the correct values.
+
+The MySQL database should not contain any tables. Tests will not 
+drop the database with existing data.
+
+
+Showing MySQL who's boss
+========================
+
+If things ever get to the point where that test database is totally hosed,
+just::
+
+  $ su -
+  # /etc/init.d/mysql stop
+  # rm -rf /var/lib/mysql/rounduptest
+  # /etc/init.d/mysql start
+
+and all will be better (note that on some systems, ``mysql`` is spelt
+``mysqld``).
+

Added: tracker/vendor/roundup/current/doc/original_overview.html
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/original_overview.html	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,962 @@
+<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html><head>
+<title>Roundup: an Issue-Tracking System for Knowledge Workers</title>
+<link rev=made href="mailto:ping at lfw.org">
+</head><body>
+
+<table width="100%">
+<tr>
+
+<td align="left">
+<a href="http://www.software-carpentry.com">
+<img src="images/logo-software-carpentry-standard.png" alt="[Software Carpentry logo]" border="0">
+</a>
+</td>
+
+<td align="right">
+<table>
+<tr><td>
+<a href="http://www.acl.lanl.gov">
+<img src="images/logo-acl-medium.png" alt="[ACL Logo]" border="0">
+</a>
+</td></tr>
+<tr><td><hr></td></tr>
+<tr><td>
+<a href="http://www.codesourcery.com">
+<img src="images/logo-codesourcery-medium.png" alt="[CodeSourcery Logo]" border="0">
+</a>
+</td></tr>
+</table>
+</td>
+
+</tr>
+
+<tr>
+
+<td colspan="2"><em>
+Copyright (c) 2000 Ka-Ping Yee.  This material may
+be distributed only subject to the terms and conditions set forth in
+the Software Carpentry Open Publication License, which is available at:
+<center>
+<a href="http://www.software-carpentry.com/openpub-license.html">http://www.software-carpentry.com/openpub-license.html</a>
+</center>
+</em></td>
+
+</tr>
+</table>
+
+<p><hr><p>
+
+
+<h1 align=center>Roundup</h1>
+<h3 align=center>An Issue-Tracking System for Knowledge Workers</h3>
+<h4 align=center>Ka-Ping Yee</h4>
+<h4 align=center><a href="http://www.lfw.org/">lfw discorporated</a><br>
+<a href="mailto:ping at lfw.org">ping at lfw.org</a></h4>
+
+<!-- the following line will start a comment in lynx -soft_dquotes mode -->
+<p style="><!--">
+
+<p><hr>
+<h2>Contents</h2>
+
+<ul>
+<li><a href="#overview">Overview</a>
+<li><a href="#background">Background</a>
+    <ul>
+    <li><a href="#principles">Guiding Principles</a>
+    </ul>
+<li><a href="#data">Data Model</a>
+    <ul>
+    <li><a href="#hyperdb">The Hyperdatabase</a>
+    <li><a href="#rationale">Rationale</a>
+    <li><a href="#roundupdb">Roundup's Hyperdatabase</a>
+    <li><a href="#schema">The Default Schema</a>
+    </ul>
+<li><a href="#ui">User Interface</a>
+    <ul>
+    <li><a href="#discuss">Submission and Discussion (Nosy Lists)</a>
+    <li><a href="#edit">Editing (Templated UI)</a>
+    <li><a href="#browse">Browsing and Searching</a>
+    </ul>
+<li><a href="#devplan">Development Plan</a>
+<li><a href="#issues">Open Issues</a>
+<li><a href="#summary">Summary</a>
+<li><a href="#ack">Acknowledgements</a>
+</ul>
+
+<!-- this comment will end the comment started in lynx -soft_dquotes mode -->
+
+<p><hr>
+<h2><a name="overview">Overview</a></h2>
+
+<p>We propose an issue-tracking system called
+<em>Roundup</em>, which will manage a number of issues
+(with properties such as "description", "priority", and so on)
+and provide the ability to
+(a) submit new issues,
+(b) find and edit existing issues,
+and
+(c) discuss issues with other participants.
+The system will facilitate communication
+among the participants by managing discussions and
+notifying interested parties when issues are edited.
+
+<p>This design draws on experience from 
+<a href="http://www.lfw.org/ping/roundup.html">an existing
+implementation</a> which we will refer to
+as "the Roundup prototype".
+The graphical interface we have in mind will resemble
+<a href="http://www.lfw.org/ping/roundup-1.png">
+the main display of the prototype</a>.
+
+<p align=center>
+<a href="images/roundup-1.png">
+<img src="images/roundup.png" width=358 height=205 border=0 alt=""></a>
+
+<p><hr>
+<h2><a name="background">Background</a></h2>
+
+<p>A typical software project requires the management of
+many tasks, usually distributed among several collaborators.
+In fact, any project team
+could use a tool for sorting out and discussing all the
+relevant issues.  A common approach is to set up some kind
+of "to-do" list that people can share.
+
+<p>However, to address the overall problem we need much more
+than just a shared to-do list; we need to
+manage a growing body of knowledge and experience to help a
+team collaborate effectively on a project.  The issue-tracking
+tool becomes a nexus for communication: the Grand Central
+Station of the group intelligence.
+
+<p>The primary focus of this design is to help
+developers work together well, not to provide a customer
+service interface to the developers.  This is not to say that
+the design is to be made unsuitable for customers to use.
+Rather, it is assumed that many of the same qualities
+that are good for supporting development (see below)
+are also good for non-developers using the system.
+Additional niceties
+for providing a safe or simplified interface to clients are
+intentionally deferred for later consideration.
+
+<p>A good issue-tracking system should have at least the
+following properties:
+
+<p><table align=right width="40%" bgcolor="#808080"
+cellspacing=0 cellpadding=0 border=0><tr><td
+><table bgcolor="#e8e8e8" width="100%"
+cellspacing=0 cellpadding=5 border=0><tr><td
+><p><font color="#808080"><small>
+With a nod to the time-honoured computer science tradition
+of "filling in the fourth quadrant", we note that
+there are really four kinds of information flow
+going on here.  The three mentioned qualities
+really address the first three quadrants of this 2-by-2 matrix,
+respectively:
+
+<ol>
+<li>User push: a user submits information to the system.
+<li>User pull: a user queries for information from the system.
+<li>System push: the system sends information out to users.
+<li>System pull: the system solicits information from users.
+</ol>
+
+An example of the fourth kind of flow is voting.
+Voting isn't described in this design,
+but it should be noted as a potential enhancement.
+</small></font></td></tr></table></td></tr></table>
+
+<ol>
+<li><strong>Low barrier to participation.</strong>
+The usefulness of the tool depends entirely on the
+information people contribute to it.  It must be made
+as easy as possible to submit new issues and contribute
+information about existing issues.<p>
+
+<li><strong>Straightforward navigation.</strong>
+It should be easy for users to extract information they need
+from the system to direct their decisions and tasks.
+They should be able to get a decent overview of
+things as well as finding specific information when
+they know what they're after.<p>
+
+<li><strong>Controlled information flow.</strong>
+The users must have control over how much information and
+what information they get.  A common flaw of some issue-tracking
+systems is that they inundate users with so much useless
+e-mail that people avoid the system altogether.
+</ol>
+<br clear=all>
+
+<p><br>
+<h3><a name="principles">Guiding Principles</a></h3>
+
+<p><strong>Simplicity.</strong> It is a strong requirement
+that the tool be accessible and understandable.  It should
+be fairly obvious what different parts of the interface do,
+and the inner mechanisms should operate in ways that most
+users can easily predict.
+
+<p><strong>Efficiency.</strong>
+We aim to optimize for minimum effort to do the most common
+operations, and best use of resources like screen real estate
+to maximize the amount of information that we summarize and present.
+
+<p><strong>Generality.</strong> We try to avoid making
+unnecessary assumptions that would restrict the applicability
+of the tool.  For example, there is no reason why one might
+not also want to use this tool to manage a design process,
+non-software projects, or organizational decisions.
+
+<p><strong>Persistence.</strong> We
+prefer hiding or reclassifying information to deleting it.
+This helps support the collection of statistics later.
+If records are never destroyed, there is little danger
+in providing access to a larger community, and logging yields
+accountability, which may encourage better behaviour.
+
+<p><hr>
+<p><table align=right width="40%" bgcolor="#808080"
+cellspacing=0 cellpadding=0 border=0><tr><td
+><table bgcolor="#e8e8e8" width="100%"
+cellspacing=0 cellpadding=5 border=0><tr><td
+><font color="#808080"><small>
+Okay, enough ranting.  Let's get down to business.
+</small></font></td></tr></table></td></tr></table>
+<h2><a name="data">Data Model</a></h2>
+
+<p>Roundup stores a number of <em>items</em>, each of
+which can have several properties and an associated discussion.
+The properties can be used to classify or search for items.
+The discussion is a sequence of e-mail messages.
+Each item is identified by a unique number, and has
+an activity log which
+records the time and content of edits made on its properties.
+The log stays fairly small since the design intentionally
+provides only small data types as item properties, and
+encourages anything large to be attached to
+e-mail where it becomes part of the discussion.
+The next section explains how items are organized.
+
+<h3><a name="hyperdb">The Hyperdatabase</a></h3>
+
+<p><table align=right width="40%" bgcolor="#808080"
+cellspacing=0 cellpadding=0 border=0><tr><td
+><table bgcolor="#e8e8e8" width="100%"
+cellspacing=0 cellpadding=5 border=0><tr><td
+><font color="#808080"><small>
+In my opinion, forcing
+items into fixed categories is one of the most
+serious problems with the Roundup prototype.
+The hyperdatabase is an <em>experimental</em> attempt to
+address the problem of information organization,
+whose scope goes beyond just Roundup.
+</small></font></td></tr></table></td></tr></table>
+
+Often when classifying information we are
+asked to select exactly one of a number of categories
+or to fit it into a rigid hierarchy.  Yet things
+only sometimes fall into one category; often,
+a piece of information may be related to several concepts.
+
+For example, forcing each item into a single topic
+category is not just suboptimal but counterproductive:
+seekers of that
+item may expect to find it in a different category
+and conclude that the item is not present in the
+database -- which has them <em>worse</em> off
+than if the items were not categorized at all.
+
+<p>Some systems try to alleviate this problem by
+allowing nodes to appear at multiple locations
+in a tree, as with "aliases" or "symbolic links" in
+a filesystem, for example.  This does help somewhat,
+but we want to be even more flexible
+by allowing the
+organization of nodes into sets that may freely
+intersect.  Rather than putting each node at exactly
+one place in an overall "grand scheme", a node can
+belong to as many sets as are appropriate.
+
+If we choose to represent the sets themselves as nodes
+and set membership as a link between nodes,
+we're now ready to present the definition of a
+hyperdatabase.
+
+<p><table align=right width="40%" bgcolor="#808080"
+cellpadding=0 cellspacing=0 border=0><tr><td
+><table bgcolor="#e8e8e8" width="100%"
+cellspacing=0 cellpadding=5 border=0><tr><td
+><font color="#808080"><small>
+Perhaps it's too pretentious a name?
+You could say this is just like an object database.
+The hyperdatabase is hardly much of an invention; the
+intent is merely to emphasize querying on links
+rather than properties.
+(I haven't heard of this being done with
+object databases before, but plead ignorance if
+there's already a good name for this idea.)
+</small></font></td></tr></table></td></tr></table>
+A <em>hyperdatabase</em> is a collection of <em>nodes</em>
+that may be hyperlinked to
+each other (hence the name "hyperdatabase").
+Each node carries a collection of key-value pairs,
+where some of the values may be links to other nodes.
+Any node may have an arbitrary number of outgoing and
+incoming links.  Hyperdatabases are able to efficiently
+answer queries such as "what nodes link to this node?"
+and "what nodes does this node link to?"
+
+<h3><a name="rationale">Rationale</a></h3>
+
+<p>There are several reasons for building our
+own kind of database for Roundup rather than using an existing one.
+
+Requiring the installation of a full-blown third-party
+SQL database system would probably deter many potential
+users from attempting to set up Roundup;
+yet a real relational database would be too
+complicated to implement on our own.
+
+On the other hand, a hyperdatabase can be implemented fairly easily
+using one of the Python DBM modules, so we can
+take the "batteries-included" approach and provide it
+as part of the system.  It's easier to build and understand
+than a true relational database (in accordance with our guiding
+principle of <em>simplicity</em>), but provides
+most of the query functionality we want.
+
+<p>A hyperdatabase is well suited for finding the intersection
+of a number of sets in which items belong.  We expect that
+most of the queries people want to do will be of this
+form, rather than complicated SQL queries.  For example, a
+typical request might be
+"show me all critical items related to security".
+The ability to store arbitrary key-value pairs and links
+on nodes gives it more flexibility than an RDBMS.
+
+Users are not going to be making thousands of queries
+per second, so it makes sense to optimize for simplicity
+and flexibility rather than performance.
+
+<p align=center><img src="images/hyperdb.png" width=433 height=352 alt=""></a>
+
+
+<h3><a name="roundupdb">Roundup's Hyperdatabase</a></h3>
+
+<p>For our application, we store each item as a node in a
+hyperdatabase.  The item's properties are stored
+as key-value pairs on its node.
+Four types of properties are allowed:
+<em>string</em>, <em>date</em>,
+<em>choice</em>, and <em>reference</em>.
+
+<p>The <em>string</em> type is for short, free-form strings.
+String properties are not intended to contain large
+amounts of text, and it is recommended that they be presented
+as one-line fields to encourage brevity.
+
+<p>The <em>date</em> type is for calendar dates and times.
+
+<p>The <em>choice</em> type denotes a single selection
+from a number of options.  A <em>choice</em> property
+entails a link from the node possessing the property to
+the node representing the chosen option.
+
+<p>The <em>reference</em> type is for a list of links to any
+number of other nodes in the in the database.  A <em>reference</em>
+property, for example, can be used to refer to related items
+or topic categories relevant to an item.
+
+<p>For Roundup, all items have five properties
+that are not customizable:
+
+<ul>
+<li>a <em>string</em> property named <strong>description</strong>
+<li>a <em>reference</em> property named <strong>superseder</strong>
+<li>a <em>reference</em> property named <strong>nosy</strong>
+<li>a <em>date</em> property named <strong>creation</strong>
+<li>a <em>date</em> property named <strong>activity</strong>
+</ul>
+
+<p>The <strong>description</strong> property is a short
+one-line description of the item.
+The detailed description can go in the
+first e-mail message of the item's discussion spool.
+
+<p>The <strong>superseder</strong> property is used to 
+support the splitting, joining, or replacing of items.
+When several items need to be
+joined into a single item, all the old items
+link to the new item in their <strong>superseder</strong>
+property.
+When an item needs to be split apart, the item
+references all the new items in its <strong>superseder</strong>
+propety.
+We can easily list all active items just by checking
+for an empty <strong>superseder</strong> property, and trace
+the path of an item's origins by querying the hyperdatabase
+for links.
+
+<p>The <strong>nosy</strong> property contains a list of
+the people who are interested in an item.  This
+mechanism is explained in
+<a href="#discuss">the section on Nosy Lists</a>.
+
+<p>The <strong>creation</strong> property records the
+item's creation time.  The <strong>activity</strong>
+property records the last time that the item was edited or
+a mail message was added to its discussion spool.  These two
+properties are managed by Roundup and are not available to
+be edited like other properties.
+
+<p>Users of the system are also represented by nodes in the
+hyperdatabase, containing properties
+like the user's e-mail address, login name, and password.
+
+<h3><a name="schema">The Default Schema</a></h3>
+
+<p><table align=right width="40%" bgcolor="#808080"
+cellpadding=0 cellspacing=0 border=0><tr><td
+><table bgcolor="#e8e8e8" width="100%"
+cellspacing=0 cellpadding=5 border=0><tr><td
+><font color="#808080"><small>
+Roundup could be distributed with a few
+suggested schemas for different purposes.
+One possible enhancement to the
+software-development schema is
+a <em>reference</em> property
+named <strong>implements</strong> for connecting
+development items to design requirements which
+they satisfy, which should
+be enough to provide basic support for
+<a href="http://software-carpentry.codesourcery.com/lists/sc-discuss/msg00046.html">traceability</a>.
+Clearly there is also potential for adding
+properties for related source files, check-ins,
+test results, regression tests for resolved items,
+and so on, though these have not yet been
+sufficiently well thought out to specify here.
+</small></font></td></tr></table></td></tr></table>
+<p>It is hoped that the hyperdatabase together with the
+specializations mentioned above for Roundup will be
+applicable in a variety of situations
+(in accordance with our guiding principle of <em>generality</em>).
+
+<p>To address the problem at hand, we need
+a specific schema for items applied particularly to software development.
+Again, we are trying to keep the schema simple: too many
+options make it tougher for someone to make a good choice.
+The schema is written here in the same form that it would
+appear in a configuration file.
+<br clear=all>
+
+<pre>
+    fixer = Reference()             # people who will fix the problem
+
+    topic = Reference()             # relevant topic keywords
+
+    priority = Choice("critical",   # panic: work is stopped!
+                      "urgent",     # important, but not deadly
+                      "bug",        # lost work or incorrect results
+                      "feature",    # want missing functionality
+                      "wish")       # avoidable bugs, missing conveniences
+
+    status = Choice("unread",       # submitted but no action yet
+                    "deferred",     # intentionally set aside
+                    "chatting",     # under review or seeking clarification
+                    "need-eg",      # need a reproducible example of a bug
+                    "in-progress",  # understood; development in progress
+                    "testing",      # we think it's done; others, please test
+                    "done-cbb",     # okay for now, but could be better
+                    "resolved")     # fix has been released
+</pre>
+
+<p>The <strong>fixer</strong> property assigns
+responsibility for an item to a person or a list of people.
+The <strong>topic</strong> property places the
+item in an arbitrary number of relevant topic sets (see
+<a href="#browse">the section on Browsing and Searching</a>).
+
+<p>As previously mentioned, each item gets an activity log.
+Whenever a property on an item is changed, the log
+records the time of the change, the user making the change,
+and the old and new values of the property.  This permits
+the later gathering of statistics (for example, the average time
+from submission to resolution).
+
+<p>We do not specify or enforce a state transition graph,
+since making the system rigid in that fashion is probably more
+trouble than it's worth.
+Experience has shown that there are probably
+two convenient automatic state transitions:
+
+<ul>
+<li>from <strong>unread</strong> to <strong>chatting</strong>
+when e-mail is written about an item
+<li>from <strong>testing</strong> to <strong>resolved</strong>
+when a new release of the software is made
+</ul>
+
+Beyond these, in accordance with our principle of <em>generality</em>,
+we allow access to the hyperdatabase
+API so that scripts can automate transitions themselves or
+be triggered by changes in the database.
+
+<p><hr>
+<h2><a name="ui">User Interface</a></h2>
+
+<p>Roundup provides its services through two main interfaces:
+e-mail and the Web.
+This division is chosen to optimize the most common tasks.
+
+<p>E-mail is best suited for
+the submission of new items since most people are most comfortable
+with composing long messages in their own favourite e-mail client.
+E-mail also permits them to mention URLs or attach files relevant
+to their submission.  Indeed, in many cases people are already
+used to making requests by sending e-mail to a mailing list
+of people; they can do exactly the same thing to use Roundup
+without even thinking about it.
+Similarly, people are already
+familiar with holding discussions in e-mail, and plenty of
+valuable usage conventions and software tools already exist for that medium.
+
+<p>The Web, on the other hand, is best suited for summarizing
+and seeking information, because it can present an interactive
+overview of items.  Since the Web has forms, it's also
+the best place to edit items.
+
+<h3><a name="discuss">Submission and Discussion</a></h3>
+
+<p><table align=right width="40%" bgcolor="#808080" cellpadding=0 border=0
+><tr><td><table bgcolor="#e8e8e8" width="100%" cellspacing=0 cellpadding=5
+border=0><tr><td><font color="#808080"><small>
+Nosy lists have actually been tried in practice,
+and their emergent properties have
+turned out to be very effective.
+They are one of the key strengths of the Roundup prototype,
+and often cause me to wonder if all mailing lists ought to work this way.
+Roundup could even replace Hypermail.
+</small></font></td></tr></table></td></tr></table>
+
+<p>The system needs an address for receiving mail
+and an address that forwards mail to all participants.
+Each item has its own list
+of interested parties, known as its <em>nosy list</em>.
+Here's how nosy lists work:
+
+<p><ol type="a">
+<li>New items are always submitted by sending an e-mail message
+to Roundup.  The "Subject:" field becomes the description
+of the new item.
+The message is saved in the mail spool of the new item,
+and copied to the list of all participants
+so everyone knows that a new item has been added.
+The new item's nosy list initially contains the submitter.
+
+<li>All e-mail messages sent by Roundup have their "Reply-To:"
+field set to Roundup's address, and have the item's
+number in the "Subject:" field.  Thus, any replies to the
+initial announcement and subsequent threads are all received
+by Roundup.  Roundup notes the item number in the "Subject:"
+field of each incoming message and appends the message
+to the appropriate spool.
+
+<li>Any incoming e-mail tagged with an item number is copied
+to all the people on the item's nosy list,
+and any users found in the "From:", "To:", or "Cc:" fields
+are automatically added to the nosy list.  Whenever a user
+edits an item's properties in the Web interface, they are
+also added to the nosy list.
+</ol>
+
+<p>The effect
+is like each item having its own little mailing list,
+except that no one ever has to worry about subscribing to
+anything.  Indicating interest in an issue is sufficient, and if you
+want to bring someone new into the conversation, all you need to do
+is Cc: a message to them.  It turns out that no one ever has to worry
+about unsubscribing, either: the nosy lists are so specific in scope
+that the conversation tends to die down by itself when the issue is
+resolved or people no longer find it sufficiently important.
+
+<p>Each nosy list is like an asynchronous chat room,
+lasting only a short time (typically five or ten messages)
+and involving a small group of people.
+However, that
+group is the <em>right</em> group of people:
+only those who express interest in an item in some way
+ever end up on
+the list, so no one gets spammed with mail they
+don't care about, and no one who <em>wants</em>
+to see mail about a particular item needs to be left
+out, for they can easily join in, and just as easily
+look at the mail spool on an item to catch up on any
+messages they might have missed.
+
+<p>We can take this a step further and
+permit users to monitor particular topics or
+classifications of items
+by allowing other kinds of nodes to
+also have their own nosy lists.
+For example, a manager could be on the
+nosy list of the priority value node for "critical", or a
+developer could be on the nosy list of the
+topic value node for "security".
+The recipients are then
+determined by the union of the nosy lists on the
+item and all the nodes it links to.
+
+<p>Using many small, specific mailing lists results
+in much more effective communication than one big list.
+Taking away the effort of subscribing and unsubscribing
+gives these lists the "feel" of being cheap and
+disposable.
+
+The transparent capture of the mail spool attached to each
+issue also yields a nice knowledge repository over time.
+
+
+<h3><a name="edit">Editing</a></h3>
+
+<p>
+<img src="images/edit.png" align=right width=171 height=471 alt="">
+Since Roundup is intended to support arbitrary user-defined
+schema for item properties, the editing interface must be
+automatically generated from the schema.  The configuration for
+Roundup will include a template describing how to lay out the
+properties to present a UI for inspecting and editing items.
+For example:
+
+<pre>
+    &lt;table width="100%"&gt;
+    &lt;tr&gt;&lt;td align=right&gt;Description:&lt;/td&gt;
+        &lt;td&gt;&lt;?property description size=70&gt;&lt;/td&gt;&lt;/tr&gt;
+    &lt;tr&gt;&lt;td align=right&gt;Status:&lt;/td&gt;
+        &lt;td&gt;&lt;?property status&gt;&lt;/td&gt;&lt;/tr&gt;
+    &lt;/table&gt;
+</pre>
+
+<p>To display the editing form for an item, Roundup substitutes
+an HTML form widget for each <tt>&lt;?property </tt>...<tt>&gt;</tt>
+tag, and transfers attributes
+(such as <tt>size=70</tt> in the above example)
+from the processing tag to the form widget's tag.
+Each type has its own appropriate editing widget:
+<ul>
+<li><em>string</em> properties appear as text fields
+<li><em>date</em> properties appear as text fields
+<li><em>choice</em> properties appear as selection lists
+<li><em>reference</em> properties appear as multiple-selection lists
+with a text field for adding a new option
+</ul>
+
+<p>We foresee the use of custom date fields for things like deadlines,
+so input fields for <em>date</em> properties should support some
+simple way of specifying relative dates (such as "three weeks from now").
+
+<p>The <strong>superseder</strong> property is a special case:
+although it is more efficient to store a <strong>superseder</strong>
+property in the superseded item, it makes more sense to provide
+a "supersedes" edit field on the superseding item.  So we need
+a special widget on items for this purpose (perhaps something
+as simple as a text field containing a comma-separated list of
+item numbers will do).  Links in the <strong>superseder</strong> property
+should appear on both the superseding and superseded items to
+facilitate navigating an item's pedigree.
+
+<p>After the editing widgets, the item inspection page shows
+a "note" text box and then a display of the messages in the
+discussion spool, like the Roundup prototype.  This field
+lets you enter a note explaining your change when you edit the
+item, and the note is included in the notification message that
+goes out to tell the interested parties on the nosy list of
+your edits.
+
+<h3><a name="browse">Browsing and Searching</a></h3>
+
+<p>The ideal we would like to achieve is to make searching as
+much like browsing as possible: the user simply clicks about
+on things that seem interesting, and the information narrows
+down comfortably until the goal is in sight.  This is preferable
+to trying to digest a screen filled with widgets and buttons
+or entering a search expression in some arcane algebraic syntax.
+
+<p><table align=right width="40%" bgcolor="#808080" cellpadding=0 border=0
+><tr><td><table bgcolor="#e8e8e8" width="100%" cellspacing=0 cellpadding=5
+border=0><tr><td><font color="#808080"><small>
+Though the generation of each page amounts to a database query,
+so that the underlying mechanism is still a series of queries and
+responses, the user interface never separates the query from
+the response, so the <em>experience</em> is one of stepwise
+refinement.
+</small></font></td></tr></table></td></tr></table>
+While a one-shot search may be appropriate when you're
+looking for a single item and you know exactly what you want, it's
+not very helpful when you want an overview of
+things ("Gee, there are a lot more high-priority items than
+there were last week!") or trying to do comparisons ("I have
+some time today, so who is busiest and could most use some help?")
+<br clear=all>
+
+<p>The browsing interface presents filtering
+functionality for each of the properties in the schema.  As with
+editing, the interface is generated from a template
+describing how to lay out the properties.
+Each type of property has its own appropriate filtering widget:
+<ul>
+<li><em>string</em> properties appear as text fields supporting
+case-insensitive substring match
+<li><em>date</em> properties appear as a text field with an
+option to choose dates after or before the specified date
+<li><em>choice</em> properties appear as a group of
+selectable options
+(the filter selects the <em>union</em> of the sets of items
+associated with the active options)
+<li><em>reference</em> properties appear as a group of
+selectable options
+(the filter selects the <em>intersection</em> of the sets of items
+associated with the active options)
+</ul>
+
+<p>For a <em>reference</em> property like <strong>topic</strong>,
+one possibility is to show, as hyperlinks, the keywords whose
+sets have non-empty intersections with the currently displayed set of
+items.  Sorting the keywords by popularity seems
+reasonable.  Clicking on a keyword then narrows both the list of items
+and the list of keywords.  This gives some of the feel of walking
+around a directory tree -- but without the restriction of having
+to select keywords in a particular hierarchical order, and without
+the need to travel all the way to the leaves of the tree before
+any items are visible.
+
+<p>Below the filtering form is a listing of items, with their
+properties displayed in a table.  Rows in the table can also be
+generated from a template, as with the editing interface.
+This listing is the central overview of the system, and it
+should aim to maximize the density of
+useful information in accordance with our guiding principle of
+<em>efficiency</em>.
+For example, 
+<a href="http://www.lfw.org/ping/bugzilla-4.gif">Bugzilla
+initially displays seven or eight items of the index</a>, but only
+after the user has 
+<a href="http://www.lfw.org/ping/bugzilla-1.gif">waded</a>
+through
+<a href="http://www.lfw.org/ping/bugzilla-2.gif">three</a>
+bewildering
+<a href="http://www.lfw.org/ping/bugzilla-3.gif">screens</a> of
+form widgets.
+<a href="http://www.lfw.org/ping/jitterbug-1.gif">Jitterbug can't
+even fit any items at all in the first screenful</a>, as it's
+taken up by artwork and adminstrative debris.  In contrast,
+<a href="http://www.lfw.org/ping/roundup-1.gif">in the
+Roundup prototype,
+25 high-priority issues are immediately visible</a>, with
+most of the screen space devoted to their descriptions.  
+Colour indicates
+the status of each item to help the eye sift through the index quickly.
+
+<p>In both Jitterbug and Bugzilla, items are sorted by default by ID,
+a meaningless field.  Sorting by ID puts the issues in order by
+ascending submission date, which banishes recent issues far away
+at the bottom of the list.
+The Roundup prototype sorts items
+in sections by priority, and then within sections by the date
+of last activity.  This reveals at a glance where discussion is
+most active, and provides an easy way for anyone to move an issue
+up in the list.
+
+<p>The page produced by a given set of browsing options constitutes
+a <em>view</em>.  The options should all be part of the query
+parameters in the URL so that views may be bookmarked.  A view
+specifies:
+
+<ul>
+<li>search strings for string properties
+<li>date ranges for date properties
+<li>acceptable values for choice properties
+<li>required values for reference properties
+<li>one or more sort keys
+<li>a list of properties for which to display filtering widgets
+</ul>
+
+<p>On each sort key there is the option to use sections -- that is,
+instead of making the property's value a column of the table, each
+possible value for the property
+is displayed at the top of a section and all the items having
+that value for that property are grouped underneath.  This avoids
+wasting screen space with redundant information.
+
+<p>We propose that our default view should be:
+
+<ul>
+<li>all options on for <strong>priority</strong> and <strong>fixer</strong>
+<li>all options on except "resolved" for <strong>status</strong>
+<li>no options on for <strong>topic</strong>
+<li>primary sort by <strong>priority</strong> in sections
+<li>secondary sort by decreasing <strong>activity</strong> date
+</ul>
+
+<p>The starting URL for Roundup should immediately present the listing of
+items generated by this default view, with no
+preceding query screen.
+
+<p><hr>
+<h2><a name="devplan">Development Plan</a></h2>
+
+<p>The hyperdatabase is clearly a separable component which
+can be developed and tested independently to an API specification.
+
+<p>As soon as the API to the hyperdatabase is nailed down,
+the implementation of the Roundup database layer
+on top of the hyperdatabase can begin.
+(This refers to the data types and five fixed properties
+specific to Roundup.)  This layer can also be tested separately.
+
+<p>When the interface to the Roundup hyperdatabase is ready,
+development can begin on the user interface.  The mail handler
+and the Web interface can be developed in parallel and mostly
+independently of each other.
+
+<p>The mail handler can be set up for testing fairly easily:
+mail messages on its standard input can be synthesized;
+its output is outgoing mail, which can be
+captured by replacing the implementation of the
+"send mail" function; and its side effects appear in the
+hyperdatabase, which has a Python API.
+
+<p>The Web interface is not easily testable in its entirety,
+though the most important components of it can be unit tested,
+such as the component that translates a view specification
+into a list of items for display, and
+the component that performs replacements on templates
+to produce an editing or filtering interface.
+
+<p><hr>
+<h2><a name="issues">Open Issues</a></h2>
+
+<p>The description of the hyperdatabase above avoids some
+issues regarding node typing that need to be better specified.
+It is conceivable that eventually Roundup
+could support multiple kinds of items with their own schemas.
+
+<p>To permit integration with external tools, it is probably
+a good idea to provide a command-line tool that exposes the
+hyperdatabase API.  This tool will be left for a later phase
+of development and so isn't specified in detail here.
+
+<p>Generating the user interface from a template is like
+applying an XSL stylesheet to XML, and if there's a standard
+Python module for performing these transformations, we could
+use XML instead.
+
+<p>More thinking is needed to determine the best filtering
+interface for <em>reference</em> properties.
+The proposed interface works well for topic keywords, but
+it isn't clear what to do when there are too many keywords
+to display them all.
+
+<p>There has been a variety of reactions to the hyperdatabase
+from reviewers: some like it, some are neutral, and some
+would prefer a "standard" RDBMS solution.
+For those in the latter camp, note
+that it's still possible to build the Roundup database layer
+around an RDBMS if we really need to.  The rest of the design, in
+particular the "nosy list" mechanism, remains intact.
+
+<p>The possibility of malice by registered users has been disregarded.
+The system is intended to be used by a co-operative group.
+
+<p>This design tries to address as many as possible of the
+suggested requirements mentioned on
+<a href="http://software-carpentry.codesourcery.com/sc_track">the contest page</a>:
+
+<ul>
+<li>configuring states: Edit the schema.
+<li>setting state transition rules: We don't enforce any rules.
+<li>assigning responsibility: Set the <strong>fixer</strong> property.
+<li>splitting and joining: Use the <strong>superseder</strong> property.
+<li>hiding information: Add
+a property and a pre-defined view that filters on it.
+<li>secure protocols: Naturally HTTPS would be nice, though it's largely
+a webserver configuration issue; secure e-mail is not addressed.
+<li>archiving old issues: Tag them with a property.
+<li>identifying repeated issues: Use the <strong>superseder</strong> property.
+<li>connecting state changes to external operations: We provide an
+API to the database and the notification mechanism so it can be scripted.
+<li>non-Latin alphabets: Unicode in Python 1.6 will handle
+this for string properties, and we can leverage existing standards for
+internationalizing e-mail messages.
+<li>images and other binaries: Attach them to e-mail messages.
+<li>inspecting item state: Use the editing interface.
+<li>translation between system-dependent formats: This is not addressed.
+<li>performing searches: Use the browsing and filtering interface.
+<li>collecting statistics: Information is gathered in the activity log,
+though tools to summarize it are not described here.
+</ul>
+
+<p><hr>
+<h2><a name="summary">Summary</a></h2>
+
+<p>Roundup is an issue-tracking system that also functions as
+a communications center and a knowledge repository.  It combines
+the strengths of e-mail and the Web to try to provide the best
+possible user interaction.
+
+<ul>
+<li>The submission and discussion of items by e-mail, permitting
+participants to use an easy and familiar tool, achieves our goal
+of <em>low barrier to participation</em>.
+<li>The generic link-based structuring of data and use of
+incremental filtering rather than one-shot querying makes for
+<em>straightforward navigation</em>.
+<li>The use of <em>nosy lists</em> (a powerful replacement for
+e-mail discussion lists) to manage communication on
+a fine-grained level provides <em>controlled information flow</em>.
+</ul>
+
+<p>The use of a "hyperdatabase" as the core model for
+the knowledge repository gives us the flexibility to extend
+Roundup and apply it to a variety of domains by
+providing new item schemas and user-interface templates.
+
+<p>Roundup is self-contained and easy to set up, requiring
+only a webserver and a mailbox.  No one needs to be root to
+configure the webserver or to install database software.
+
+<p>This design is based on an existing deployed
+prototype which has proven its strengths and revealed its
+weaknesses in heavy day-to-day use by a real development team.
+
+<p><hr>
+<h2><a name="ack">Acknowledgements</a></h2>
+
+<p>My thanks are due to 
+Christina Heyl, Jesse Vincent, Mark Miller, Christopher Simons,
+Jeff Dunmall, Wayne Gramlich, and Dean Tribble
+for reviewing this paper and contributing their suggestions.
+
+<p><hr><p>
+
+<center>
+<table>
+<tr>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/index.html"><b>[Home]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/faq.html"><b>[FAQ]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/license.html"><b>[License]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/contest-rules.html"><b>[Rules]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/biblio.html"><b>[Resources]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/lists/"><b>[Archives]</b></a>&nbsp;&nbsp;&nbsp;</td>
+</tr>
+</table>
+</center>
+
+<p><hr>
+<center>
+Last modified 2001/04/06 11:50:59.9063 US/Mountain
+</center>
+</body></html>

Added: tracker/vendor/roundup/current/doc/overview.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/overview.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,603 @@
+=======================================================
+Roundup: an Issue-Tracking System for Knowledge Workers
+=======================================================
+
+:Authors: Ka-Ping Yee (original_), Richard Jones (implementation)
+
+.. _original: original_overview.html
+
+.. contents::
+
+
+Introduction
+============
+
+Roundup is an issue-tracking system called which will manage a
+number of issues (with properties such as "description", "priority",
+and so on) and provides the ability to:
+
+(a) submit new issues,
+(b) find and edit existing issues, and
+(c) discuss issues with other participants.
+
+Roundup facilitates communication among the participants by managing
+discussions and notifying interested parties when issues are edited.
+
+
+Background
+----------
+
+A typical software project requires the management of
+many tasks, usually distributed among several collaborators.
+In fact, any project team
+could use a tool for sorting out and discussing all the
+relevant issues.  A common approach is to set up some kind
+of "to-do" list that people can share.
+
+However, to address the overall problem we need much more
+than just a shared to-do list; we need to
+manage a growing body of knowledge and experience to help a
+team collaborate effectively on a project.  The issue-tracking
+tool becomes a nexus for communication: the Grand Central
+Station of the group intelligence.
+
+The primary focus of this design is to help
+developers work together well, not to provide a customer
+service interface to the developers.  This is not to say that
+the design is to be made unsuitable for customers to use.
+Rather, it is assumed that many of the same qualities
+that are good for supporting development (see below)
+are also good for non-developers using the system.
+Additional niceties
+for providing a safe or simplified interface to clients are
+intentionally deferred for later consideration.
+
+A good issue-tracking system should have at least the
+following properties:
+
+**Low barrier to participation**
+  The usefulness of the tool depends entirely on the
+  information people contribute to it.  It must be made
+  as easy as possible to submit new issues and contribute
+  information about existing issues.
+
+**Straightforward navigation**
+  It should be easy for users to extract information they need
+  from the system to direct their decisions and tasks.
+  They should be able to get a decent overview of
+  things as well as finding specific information when
+  they know what they're after.
+
+**Controlled information flow**
+  The users must have control over how much information and
+  what information they get.  A common flaw of some issue-tracking
+  systems is that they inundate users with so much useless
+  e-mail that people avoid the system altogether.
+
+With a nod to the time-honoured computer science tradition
+of "filling in the fourth quadrant", we note that
+there are really four kinds of information flow
+going on here.  The three mentioned qualities
+really address the first three quadrants of this 2-by-2 matrix,
+respectively:
+
+1. User push: a user submits information to the system.
+2. User pull: a user queries for information from the system.
+3. System push: the system sends information out to users.
+4. System pull: the system solicits information from users.
+
+An example of the fourth kind of flow is voting.
+Voting isn't described in this design,
+but it should be noted as a potential enhancement.
+
+
+Guiding Principles
+------------------
+
+**Simplicity**
+  It is a strong requirement
+  that the tool be accessible and understandable.  It should
+  be fairly obvious what different parts of the interface do,
+  and the inner mechanisms should operate in ways that most
+  users can easily predict.
+
+**Efficiency**
+  We aim to optimize for minimum effort to do the most common
+  operations, and best use of resources like screen real estate
+  to maximize the amount of information that we summarize and present.
+
+**Generality**
+  We try to avoid making
+  unnecessary assumptions that would restrict the applicability
+  of the tool.  For example, there is no reason why one might
+  not also want to use this tool to manage a design process,
+  non-software projects, or organizational decisions.
+
+**Persistence** We
+  prefer hiding or reclassifying information to deleting it.
+  This helps support the collection of statistics later.
+  If records are never destroyed, there is little danger
+  in providing access to a larger community, and logging yields
+  accountability, which may encourage better behaviour.
+
+
+Data Model
+==========
+
+Roundup stores a number of *items*, each of
+which can have several properties and an associated discussion.
+The properties can be used to classify or search for items.
+The discussion is a sequence of e-mail messages.
+Each item is identified by a unique number, and has
+an activity log which
+records the time and content of edits made on its properties.
+The log stays fairly small since the design intentionally
+provides only small data types as item properties, and
+encourages anything large to be attached to
+e-mail where it becomes part of the discussion.
+The next section explains how items are organized.
+
+
+The Hyperdatabase
+-----------------
+
+Often when classifying information we are
+asked to select exactly one of a number of categories
+or to fit it into a rigid hierarchy.  Yet things
+only sometimes fall into one category; often,
+a piece of information may be related to several concepts.
+
+For example, forcing each item into a single topic
+category is not just suboptimal but counterproductive:
+seekers of that
+item may expect to find it in a different category
+and conclude that the item is not present in the
+database -- which has them *worse* off
+than if the items were not categorized at all.
+
+Some systems try to alleviate this problem by
+allowing items to appear at multiple locations
+in a tree, as with "aliases" or "symbolic links" in
+a filesystem, for example.  This does help somewhat,
+but we want to be even more flexible
+by allowing the
+organization of items into sets that may freely
+intersect.  Rather than putting each item at exactly
+one place in an overall "grand scheme", a item can
+belong to as many sets as are appropriate.
+
+If we choose to represent the sets themselves as items
+and set membership as a link between items,
+we're now ready to present the definition of a
+hyperdatabase.
+
+A *hyperdatabase* is a collection of *items*
+that may be hyperlinked to
+each other (hence the name "hyperdatabase").
+Each item carries a collection of key-value pairs,
+where some of the values may be links to other items.
+Any item may have an arbitrary number of outgoing and
+incoming links.  Hyperdatabases are able to efficiently
+answer queries such as "what items link to this item?"
+and "what items does this item link to?"
+
+Rationale
+---------
+
+There are several reasons for building our
+own kind of database for Roundup rather than using an existing one.
+
+Requiring the installation of a full-blown third-party
+SQL database system would probably deter many potential
+users from attempting to set up Roundup;
+yet a real relational database would be too
+complicated to implement on our own.
+
+On the other hand, a hyperdatabase can be implemented fairly easily
+using one of the Python DBM modules, so we can
+take the "batteries-included" approach and provide it
+as part of the system.  It's easier to build and understand
+than a true relational database (in accordance with our guiding
+principle of *simplicity*), but provides
+most of the query functionality we want.
+
+A hyperdatabase is well suited for finding the intersection
+of a number of sets in which items belong.  We expect that
+most of the queries people want to do will be of this
+form, rather than complicated SQL queries.  For example, a
+typical request might be
+"show me all critical items related to security".
+The ability to store arbitrary key-value pairs and links
+on items gives it more flexibility than an RDBMS.
+
+Users are not going to be making thousands of queries
+per second, so it makes sense to optimize for simplicity
+and flexibility rather than performance.
+
+.. img: images/hyperdb.png
+
+
+Roundup's Hyperdatabase
+-----------------------
+
+For our application, we store each item as a item in a
+hyperdatabase.  The item's properties are stored
+as key-value pairs on its item.
+Several types of properties are allowed:
+*string*, *number*, *boolean*, *date*, *interval, *link*,
+and *multlink*. Another type, *password*, is a special type
+of string and it's only used internally to Roundup.
+
+The *string* type is for short, free-form strings.
+String properties are not intended to contain large
+amounts of text, and it is recommended that they be presented
+as one-line fields to encourage brevity. A *number* is a special
+type of string that represents a numeric value. A *boolean* is
+further constrained to be a *true* or *false* value.
+
+The *date* type is for calendar dates and times. An *interval*
+is the time between two dates.
+
+The *link* type denotes a single selection from a number of
+options.  A *link* property entails a link from the item
+possessing the property to the item representing the chosen option.
+
+The *multilink* type is for a list of links to any
+number of other items in the in the database.  A *multilink*
+property, for example, can be used to refer to related items
+or topic categories relevant to an item.
+
+For Roundup, all items have four properties that are not customizable:
+
+1. a *date* property named **creation**
+2. a *link* property named **creator**
+3. a *date* property named **activity**
+
+These properties represent the date of the creation of the item, who
+created it, and when the last change was made.
+
+Further, all *issue* items have an additional four properties:
+
+1. a *string* property named **title**
+2. a *multilink* property named **nosy**
+3. a *multilink* property named **messages**
+4. a *multilink* property named **files**
+5. a *multilink* property named **superseder**
+
+The **title** property is a short one-line description of the item.
+The detailed description can go in the first e-mail message of the
+item's messages spool.
+
+The **nosy** property contains a list of
+the people who are interested in an item.  This
+mechanism is explained in the section on `Submission and Discussion`_.
+
+Each message added to the item goes in the **messages** spool - any
+attached files go in the **files** spool.
+
+The **superseder** property is used to 
+support the splitting, joining, or replacing of items.
+When several items need to be
+joined into a single item, all the old items
+link to the new item in their **superseder**
+property.
+When an item needs to be split apart, the item
+references all the new items in its **superseder**
+propety.
+We can easily list all active items just by checking
+for an empty **superseder** property, and trace
+the path of an item's origins by querying the hyperdatabase
+for links.
+
+Users of the system are also represented by items in the
+hyperdatabase, containing properties
+like the user's e-mail address, login name, and password.
+
+The Default Schema
+------------------
+
+It is hoped that the hyperdatabase together with the
+specializations mentioned above for Roundup will be
+applicable in a variety of situations
+(in accordance with our guiding principle of *generality*).
+
+To address the problem at hand, we need
+a specific schema for items applied particularly to software development.
+Again, we are trying to keep the schema simple: too many
+options make it tougher for someone to make a good choice::
+
+    # IssueClass automatically gets these properties:
+    #   title = String()
+    #   messages = Multilink("msg")
+    #   files = Multilink("file")
+    #   nosy = Multilink("user")
+    #   superseder = Multilink("issue")
+    #   (it also gets the Class properties creation, activity and creator)
+    issue = IssueClass(db, "issue", 
+                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    priority=Link("priority"), status=Link("status"))
+
+The **assignedto** property assigns
+responsibility for an item to a person or a list of people.
+The **topic** property places the
+item in an arbitrary number of relevant topic sets (see
+the section on `Browsing and Searching`_).
+
+The **prority** and **status** values are initially:
+
+=========== =====================================
+Priority    Description
+=========== =====================================
+"critical"  panic: work is stopped!
+"urgent"    important, but not deadly
+"bug"       lost work or incorrect results
+"feature"   want missing functionality
+"wish"      avoidable bugs, missing conveniences
+=========== =====================================
+
+============= =====================================
+Status        Description
+============= =====================================
+"unread"      submitted but no action yet
+"deferred"    intentionally set aside
+"chatting"    under review or seeking clarification
+"need-eg"     need a reproducible example of a bug
+"in-progress" understood; development in progress
+"testing"     we think it's done; others, please test
+"done-cbb"    okay for now, but could be better
+"resolved"    fix has been released
+============= =====================================
+
+As previously mentioned, each item gets an activity log.
+Whenever a property on an item is changed, the log
+records the time of the change, the user making the change,
+and the old and new values of the property.  This permits
+the later gathering of statistics (for example, the average time
+from submission to resolution).
+
+We do not specify or enforce a state transition graph,
+since making the system rigid in that fashion is probably more
+trouble than it's worth.
+Experience has shown that there are probably
+two convenient automatic state transitions:
+
+1. from **unread** to **chatting** when e-mail is written about an item
+2. from **testing** to **resolved** when a new release of the software is made
+
+Beyond these, in accordance with our principle of *generality*,
+we allow access to the hyperdatabase
+API so that scripts can automate transitions themselves or
+be triggered by changes in the database.
+
+
+User Interface
+==============
+
+Roundup provides its services through two main interfaces:
+e-mail and the Web.
+This division is chosen to optimize the most common tasks.
+
+E-mail is best suited for
+the submission of new items since most people are most comfortable
+with composing long messages in their own favourite e-mail client.
+E-mail also permits them to mention URLs or attach files relevant
+to their submission.  Indeed, in many cases people are already
+used to making requests by sending e-mail to a mailing list
+of people; they can do exactly the same thing to use Roundup
+without even thinking about it.
+Similarly, people are already
+familiar with holding discussions in e-mail, and plenty of
+valuable usage conventions and software tools already exist for that medium.
+
+The Web, on the other hand, is best suited for summarizing
+and seeking information, because it can present an interactive
+overview of items.  Since the Web has forms, it's also
+the best place to edit items.
+
+
+Submission and Discussion
+-------------------------
+
+The system needs an address for receiving mail
+and an address that forwards mail to all participants.
+Each item has its own list
+of interested parties, known as its *nosy list*.
+Here's how nosy lists work:
+
+1. New items are always submitted by sending an e-mail message
+   to Roundup.  The "Subject:" field becomes the description
+   of the new item.
+   The message is saved in the mail spool of the new item,
+   and copied to the list of all participants
+   so everyone knows that a new item has been added.
+   The new item's nosy list initially contains the submitter.
+
+2. All e-mail messages sent by Roundup have their "Reply-To:"
+   field set to Roundup's address, and have the item's
+   number in the "Subject:" field.  Thus, any replies to the
+   initial announcement and subsequent threads are all received
+   by Roundup.  Roundup notes the item number in the "Subject:"
+   field of each incoming message and appends the message
+   to the appropriate spool.
+
+3. Any incoming e-mail tagged with an item number is copied
+   to all the people on the item's nosy list,
+   and any users found in the "From:", "To:", or "Cc:" fields
+   are automatically added to the nosy list.  Whenever a user
+   edits an item's properties in the Web interface, they are
+   also added to the nosy list.
+
+The effect is like each item having its own little mailing list,
+except that no one ever has to worry about subscribing to
+anything.  Indicating interest in an issue is sufficient, and if you
+want to bring someone new into the conversation, all you need to do
+is "Cc:" a message to them.  It turns out that no one ever has to worry
+about unsubscribing, either: the nosy lists are so specific in scope
+that the conversation tends to die down by itself when the issue is
+resolved or people no longer find it sufficiently important.
+
+Each nosy list is like an asynchronous chat room,
+lasting only a short time (typically five or ten messages)
+and involving a small group of people.  However, that
+group is the *right* group of people:
+only those who express interest in an item in some way
+ever end up on the list, so no one gets spammed with mail they
+don't care about, and no one who *wants*
+to see mail about a particular item needs to be left
+out, for they can easily join in, and just as easily
+look at the mail spool on an item to catch up on any
+messages they might have missed.
+
+We can take this a step further and
+permit users to monitor particular topics or classifications of items
+by allowing other kinds of items to also have their own nosy lists.
+For example, a manager could be on the
+nosy list of the priority value item for "critical", or a
+developer could be on the nosy list of the topic value item for "security".
+The recipients are then determined by the union of the nosy lists on the
+item and all the items it links to.
+
+Using many small, specific mailing lists results
+in much more effective communication than one big list.
+Taking away the effort of subscribing and unsubscribing
+gives these lists the "feel" of being cheap and
+disposable.
+
+The transparent capture of the mail spool attached to each
+issue also yields a nice knowledge repository over time.
+
+
+Editing
+-------
+
+Since Roundup is intended to support arbitrary user-defined
+schema for item properties, the editing interface must be
+automatically generated from the schema.  The configuration for
+Roundup will include a template describing how to lay out the
+properties to present a UI for inspecting and editing items.
+For example::
+
+ <tr>
+  <th class="required">Priority</th>
+  <td tal:content="structure context/priority/menu">priority</td>
+  <th>Status</th>
+  <td tal:content="structure context/status/menu">status</td>
+ </tr>
+
+To display the editing form for an item, Roundup inserts
+an HTML form widget where it encounters an expression like
+``tal:content="structure context/priority/menu"``.
+Each type has its own appropriate editing widget:
+
+- *string* and *number* properties appear as text fields
+- *boolean* properties appear as a yes/no selection
+- *date* and *interval* properties appear as text fields
+- *link* properties appear as selection lists
+- *multilink* properties appear as multiple-selection lists
+    or text fields with pop-up widgets for larger selections.
+
+We foresee the use of custom date fields for things like deadlines,
+so input fields for *date* properties support a
+simple way of specifying relative dates (such as "3w" for
+"three weeks from now").
+
+The **superseder** property is a special case:
+although it is more efficient to store a **superseder**
+property in the superseded item, it makes more sense to provide
+a "supersedes" edit field on the superseding item.  We use
+a special widget on items for this purpose (a text field containing
+a comma-separated list of items).  Links in the **superseder** property
+appear on both the superseding and superseded items to
+facilitate navigating an item's pedigree.
+
+After the editing widgets, the item inspection page shows
+a "note" text box and then a display of the messages in the
+discussion spool.  This field
+lets you enter a note explaining your change when you edit the
+item, and the note is included in the notification message that
+goes out to tell the interested parties on the nosy list of
+your edits.
+
+Browsing and Searching
+----------------------
+
+The ideal we would like to achieve is to make searching as
+much like browsing as possible: the user simply clicks about
+on things that seem interesting, and the information narrows
+down comfortably until the goal is in sight.  This is preferable
+to trying to digest a screen filled with widgets and buttons
+or entering a search expression in some arcane algebraic syntax.
+
+While a one-shot search may be appropriate when you're
+looking for a single item and you know exactly what you want, it's
+not very helpful when you want an overview of
+things ("Gee, there are a lot more high-priority items than
+there were last week!") or trying to do comparisons ("I have
+some time today, so who is busiest and could most use some help?")
+
+The browsing interface presents filtering
+functionality for each of the properties in the schema.  As with
+editing, the interface is generated from a template
+describing how to lay out the properties.
+Each type of property has its own appropriate filtering widget:
+
+- *string* properties appear as text fields supporting
+  case-insensitive substring match
+- *date* properties appear as a text field which accepts a date
+  range with start, end or both
+- *link* properties appear as a group of selectable options
+  (the filter selects the *union* of the sets of items
+  associated with the active options)
+- *multilink* properties appear as a group of selectable options
+  (the filter selects the *intersection* of the sets of items
+  associated with the active options)
+
+For a *multilink* property like **topic**,
+one possibility is to show, as hyperlinks, the keywords whose
+sets have non-empty intersections with the currently displayed set of
+items.  Sorting the keywords by popularity seems
+reasonable.  Clicking on a keyword then narrows both the list of items
+and the list of keywords.  This gives some of the feel of walking
+around a directory tree -- but without the restriction of having
+to select keywords in a particular hierarchical order, and without
+the need to travel all the way to the leaves of the tree before
+any items are visible.
+
+Below the filtering form is a listing of items, with their
+properties displayed in a table.  Rows in the table are 
+generated from a template, as with the editing interface.
+This listing is the central overview of the system, and it
+should aim to maximize the density of
+useful information in accordance with our guiding principle of
+*efficiency*.  Colour may be used to indicate
+the status of each item to help the eye sift through the index quickly.
+
+Roundup sorts items
+in groups by priority, and then within groups by the date
+of last activity.  This reveals at a glance where discussion is
+most active, and provides an easy way for anyone to move an issue
+up in the list.
+
+The page produced by a given set of browsing options constitutes
+an *index*.  The options should all be part of the query
+parameters in the URL so that views may be bookmarked.  An index
+specifies:
+
+- search strings for string properties
+- date ranges for date properties
+- acceptable values for choice properties
+- required values for reference properties
+- a sorting key
+- a grouping key
+- a list of properties for which to display filtering widgets
+
+Our default index is:
+
+- all **status** values except "resolved"
+- show **priority** and **fixer**
+- grouping by **priority** in sections
+- sorting by decreasing **activity** date
+
+The starting URL for Roundup immediately presents the listing of
+items generated by this default index, with no preceding query screen.
+

Added: tracker/vendor/roundup/current/doc/postgresql.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/postgresql.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,40 @@
+==========================
+PostgreSQL/psycopg Backend
+==========================
+
+This are notes about PostqreSQL backend based on the psycopg adapter for
+Roundup issue tracker.
+
+Prerequisites
+=============
+
+To use PostgreSQL as backend for storing roundup data, you should
+additionally install:
+
+1. PostgreSQL 7.x - http://www.postgresql.org/
+
+2. The psycopg python interface to PostgreSQL:
+   http://initd.org/software/initd/psycopg
+
+Some advice on setting up the postgresql backend may be found at:
+
+  http://www.magma.com.ni/wiki/index.cgi?TipsRoundupPostgres
+
+
+Running the PostgreSQL unit tests
+=================================
+
+The user that you're running the tests as will need to be able to access
+the postgresql database on the local machine and create and drop
+databases. Edit the ``test/test_postgresql.py`` database connection info if
+you wish to test against a different database.
+
+The test database will be called "rounduptest".
+
+
+Credit
+======
+
+The postgresql backend was originally submitted by Federico Di Gregorio
+<fog at initd.org>
+

Added: tracker/vendor/roundup/current/doc/roundup-admin.1
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/roundup-admin.1	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,26 @@
+.TH ROUNDUP-ADMIN 1 "24 January 2003"
+.SH NAME
+roundup-admin \- administrate roundup trackers
+.SH SYNOPSIS
+\fBroundup-admin\fP [\fIoptions\fP] \fI<command>\fP \fI<arguments>\fP
+.SH OPTIONS
+.TP
+\fB-i\fP \fIinstance home\fP
+specify the issue tracker "home directory" to administer
+.TP
+\fB-u\fP
+the user[:password] to use for commands
+.TP
+\fB-c\fP
+when outputting lists of data, just comma-separate them
+.SH FURTHER HELP
+ roundup-admin -h
+ roundup-admin help                       -- this help
+ roundup-admin help <command>             -- command-specific help
+ roundup-admin help all                   -- all available help
+.SH AUTHOR
+This manpage was written by Bastian Kleineidam
+<calvin at debian.org> for the Debian distribution of roundup.
+
+The main author of roundup is Richard Jones
+<richard at users.sourceforge.net>.

Added: tracker/vendor/roundup/current/doc/roundup-demo.1
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/roundup-demo.1	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,30 @@
+.TH ROUNDUP-SERVER 1 "27 July 2004"
+.SH NAME
+roundup-demo \- create a roundup "demo" tracker and launch its web interface
+.SH SYNOPSIS
+\fBroundup-demo\fP [\fIbackend\fP [\fBnuke\fP]]
+.SH OPTIONS
+.TP
+\fBnuke\fP
+Create a fresh demo tracker (deleting the existing one if any). If the
+additional \fIbackend\fP argument is specified, the new demo tracker will
+use the backend named (one of "anydbm", "sqlite", "metakit", "mysql" or
+"postgresql"; subject to availability on your system).
+.TH DESCRIPTION
+This command creates a fresh demo tracker for you to experiment with. The
+email features of Roundup will be turned off (so the nosy feature won't
+send email). It does this by removing the \fInosyreaction.py\fP module
+from the demo tracker's \fIdetectors\fP directory.
+
+If you wish, you may modify the demo tracker by editing its configuration
+files and HTML templates. See the \fIcustomisation\fP manual for
+information about how to do that.
+
+Once you've fiddled with the demo tracker, you may use it as a template for
+creating your real, live tracker. Simply run the \fIroundup-admin\fP
+command to install the tracker from inside the demo tracker home directory,
+and it will be listed as an available template for installation. No data
+will be copied over.
+.SH AUTHOR
+This manpage was written by Richard Jones
+<richard at users.sourceforge.net>.

Added: tracker/vendor/roundup/current/doc/roundup-favicon.ico
==============================================================================
Binary file. No diff available.

Added: tracker/vendor/roundup/current/doc/roundup-mailgw.1
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/roundup-mailgw.1	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,59 @@
+.TH ROUNDUP-MAILGW 1 "24 January 2003"
+.SH NAME
+roundup-mailgw \- mail gateway for roundup
+.SH SYNOPSIS
+\fBroundup-mailgw\fP \fI<instance home>\fP [\fImethod\fP]
+.SH OPTIONS
+.TP
+\fB-C\fP \fIhyperdb class\fP
+specify a tracker class - one of msg (the default), issue, file, user - to
+manipulate with -S options
+.TP
+\fB-S\fP \fIproperty=value[;property=value] pairs\fP
+specify the values to set on the class specified by -C using the same
+format as the Subject line property manipulations
+.SH DESCRIPTION
+The roundup mail gateway may be called in one of three ways:
+.IP \(bu
+with an instance home as the only argument,
+.IP \(bu
+with both an instance home and a mail spool file, or
+.IP \(bu
+with both an instance home and a pop server account.
+.PP
+\fBPIPE\fP
+.br
+In the first case, the mail gateway reads a single message from the
+standard input and submits the message to the roundup.mailgw module.
+
+\fBUNIX mailbox\fP
+.br
+In the second case, the gateway reads all messages from the mail spool
+file and submits each in turn to the roundup.mailgw module. The file is
+emptied once all messages have been successfully handled. The file is
+specified as:
+ \fImailbox /path/to/mailbox\fP
+
+\fBPOP\fP
+.br
+In the third case, the gateway reads all messages from the POP server
+specified and submits each in turn to the roundup.mailgw module. The
+server is specified as:
+ \fIpop username:password at server\fP
+.br
+The username and password may be omitted:
+ \fIpop username at server\fP
+ \fIpop server\fP
+.br
+are both valid. The username and/or password will be prompted for if
+not supplied on the command-line.
+
+\fBAPOP\fP
+Same as POP, but using Authenticated POP:
+ \fIapop username:password at server\fP
+.SH AUTHOR
+This manpage was written by Bastian Kleineidam
+<calvin at debian.org> for the Debian distribution of roundup.
+
+The main author of roundup is Richard Jones
+<richard at users.sourceforge.net>.

Added: tracker/vendor/roundup/current/doc/roundup-server.1
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/roundup-server.1	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,43 @@
+.TH ROUNDUP-SERVER 1 "27 July 2004"
+.SH NAME
+roundup-server \- start roundup web server
+.SH SYNOPSIS
+\fBroundup-server\fP [\fIoptions\fP] [\fBname=\fP\fItracker home\fP]*
+.SH OPTIONS
+.TP
+\fB-C\fP \fIfile\fP
+Use options read from the configuration file (see below).
+.TP
+\fB-n\fP \fIhostname\fP
+Sets the host name.
+.TP
+\fB-p\fP \fIport\fP
+Sets the port to listen on.
+.TP
+\fB-d\fP \fIfile\fP
+Daemonize, and write the server's PID to the nominated file.
+.TP
+\fB-l\fP \fIfile\fP
+Sets a filename to log to (instead of stdout). This is required if the -d
+option is used.
+.TP
+\fB-h\fP
+print help
+.TP
+\fBname=\fP\fItracker home\fP
+Sets the tracker home(s) to use. The name is how the tracker is
+identified in the URL (it's the first part of the URL path). The
+tracker home is the directory that was identified when you did
+"roundup-admin init". You may specify any number of these name=home
+pairs on the command-line. For convenience, you may edit the
+TRACKER_HOMES variable in the roundup-server file instead.
+Make sure the name part doesn't include any url-unsafe characters like
+spaces, as these confuse the cookie handling in browsers like IE.
+.SH CONFIGURATION FILE
+See the "admin_guide" in the Roundup "doc" directory.
+.SH AUTHOR
+This manpage was written by Bastian Kleineidam
+<calvin at debian.org> for the Debian distribution of roundup.
+
+The main author of roundup is Richard Jones
+<richard at users.sourceforge.net>.

Added: tracker/vendor/roundup/current/doc/roundup-server.ini.example
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/roundup-server.ini.example	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,16 @@
+; This is a sample configuration file for roundup-server. See the
+; admin_guide for information about its contents.
+[server]
+port = 8080
+;hostname = 
+;user = 
+;group = 
+;log_ip = yes
+;pidfile = 
+;logfile = 
+
+
+; Add one of these per tracker being served
+[tracker_url_component]
+home = /path/to/tracker
+

Added: tracker/vendor/roundup/current/doc/spec.html
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/spec.html	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,1546 @@
+<html>
+<head>
+<title>Software Carpentry Track: Roundup</title>
+</head>
+<body bgcolor=white>
+
+<table width="100%">
+<tr>
+
+<td align="left">
+<a href="http://www.software-carpentry.com"><img
+src="images/logo-software-carpentry-standard.png" alt="[Software Carpentry logo]" border="0"></a>
+</td>
+
+<td align="right">
+<table>
+<tr><td>
+<a href="http://www.acl.lanl.gov"><img src="images//logo-acl-medium.png" alt="[ACL Logo]" border="0"></a>
+</td></tr>
+<tr><td><hr></td></tr>
+<tr><td>
+<a href="http://www.codesourcery.com"><img
+src="images/logo-codesourcery-medium.png" alt="[CodeSourcery Logo]" border="0"></a>
+</td></tr>
+</table>
+</td>
+
+</tr>
+</table>
+
+<hr><p>
+
+<h1 align=center>Roundup</h1>
+<h3 align=center>An Issue-Tracking System for Knowledge Workers</h3>
+<h4 align=center><a href="http://www.lfw.org/ping/">Ka-Ping Yee</a><br>
+<a href="mailto:ping at lfw.org">ping at lfw.org</a></h4>
+<h3 align=center>Implementation Guide</h3>
+
+<h2>Contents</h2>
+
+<ol>
+<li>Introduction
+<li>The Layer Cake
+<li>Hyperdatabase
+    <ol>
+    <li>Dates and Date Arithmetic
+    <li>Items and Classes
+    <li>Identifiers and Designators
+    <li>Property Names and Types
+    <li>Interface Specification
+    <li>Application Example
+    </ol>
+<li>Roundup Database
+    <ol>
+    <li>Reserved Classes
+        <ol>
+        <li>Users
+        <li>Messages
+        <li>Files
+        </ol>
+    <li>Item Classes
+    <li>Interface Specification
+    <li>Default Schema
+    </ol>
+<li>Detector Interface
+    <ol>
+    <li>Interface Specification
+    <li>Detector Example
+    </ol>
+<li>Command Interface
+    <ol>
+    <li>Interface Specification
+    <li>Usage Example
+    </ol>
+<li>E-mail User Interface
+    <ol>
+    <li>Message Processing
+    <li>Nosy Lists
+    <li>Setting Properties
+    <li>Workflow Example
+    </ol>
+<li>Web User Interface
+    <ol>
+    <li>Views and View Specifiers
+    <li>Displaying Properties
+    <li>Index Views
+        <ol>
+        <li>Index View Specifiers
+        <li>Filter Section
+        <li>Index Section
+        <li>Sorting
+        </ol>
+    <li>Item Views
+        <ol>
+        <li>Item View Specifiers
+        <li>Editor Section
+        <li>Spool Section
+        </ol>
+    </ol>
+<li>Deployment Scenarios
+<li>Acknowledgements
+</ol>
+
+<p><hr>
+<h2>1. Introduction</h2>
+
+<p>This document presents a description of the components
+of the Roundup system and specifies their interfaces and
+behaviour in sufficient detail to guide an implementation.
+For the philosophy and rationale behind the Roundup design,
+see the first-round Software Carpentry submission for Roundup.
+This document fleshes out that design as well as specifying
+interfaces so that the components can be developed separately.
+
+<p><hr>
+<h2>2. The Layer Cake</h2>
+
+<p>Lots of software design documents come with a picture of
+a cake.  Everybody seems to like them.  I also like cakes
+(i think they are tasty).  So i, too, shall include
+a picture of a cake here.
+
+<p align=center><table cellspacing=0 cellpadding=10 border=0 align=center>
+<tr>
+<td bgcolor="#e8e8e8" align=center>
+<p><font face="helvetica, arial"><small>
+E-mail Client
+</small></font>
+</td>
+<td bgcolor="#e0e0e0" align="center">
+<p><font face="helvetica, arial"><small>
+Web Browser
+</small></font>
+</td>
+<td bgcolor="#e8e8e8" align=center>
+<p><font face="helvetica, arial"><small>
+Detector Scripts
+</small></font>
+</td>
+<td bgcolor="#e0e0e0" align="center">
+<p><font face="helvetica, arial"><small>
+Shell
+</small></font>
+</td>
+<tr>
+<td bgcolor="#d0d0f0" align=center>
+<p><font face="helvetica, arial"><small>
+E-mail User Interface
+</small></font>
+</td>
+<td bgcolor="#f0d0d0" align=center>
+<p><font face="helvetica, arial"><small>
+Web User Interface
+</small></font>
+</td>
+<td bgcolor="#d0f0d0" align=center>
+<p><font face="helvetica, arial"><small>
+Detector Interface
+</small></font>
+</td>
+<td bgcolor="#f0d0f0" align=center>
+<p><font face="helvetica, arial"><small>
+Command Interface
+</small></font>
+</td>
+<tr>
+<td bgcolor="#f0f0d0" colspan=4 align=center>
+<p><font face="helvetica, arial"><small>
+Roundup Database Layer
+</small></font>
+</td>
+<tr>
+<td bgcolor="#d0f0f0" colspan=4 align=center>
+<p><font face="helvetica, arial"><small>
+Hyperdatabase Layer
+</small></font>
+</td>
+<tr>
+<td bgcolor="#e8e8e8" colspan=4 align=center>
+<p><font face="helvetica, arial"><small>
+Storage Layer
+</small></font>
+</td>
+</table>
+
+<p>The colourful parts of the cake are part of our system;
+the faint grey parts of the cake are external components.
+
+<p>I will now proceed to forgo all table manners and
+eat from the bottom of the cake to the top.  You may want
+to stand back a bit so you don't get covered in crumbs.
+
+<p><hr>
+<h2>3. Hyperdatabase</h2>
+
+<p>The lowest-level component to be implemented is the hyperdatabase.
+The hyperdatabase is intended to be
+a flexible data store that can hold configurable data in
+records which we call <em>items</em>.
+
+<p>The hyperdatabase is implemented on top of the storage layer,
+an external module for storing its data.  The storage layer could
+be a third-party RDBMS; for a "batteries-included" distribution,
+implementing the hyperdatabase on the standard <tt>bsddb</tt>
+module is suggested.
+
+<h3>3.1. Dates and Date Arithmetic</h3>
+
+<p>Before we get into the hyperdatabase itself, we need a
+way of handling dates.  The hyperdatabase module provides
+Timestamp objects for
+representing date-and-time stamps and Interval objects for
+representing date-and-time intervals.
+
+<p>As strings, date-and-time stamps are specified with
+the date in international standard format
+(<em>yyyy</em>-<em>mm</em>-<em>dd</em>)
+joined to the time (<em>hh</em>:<em>mm</em>:<em>ss</em>)
+by a period (".").  Dates in
+this form can be easily compared and are fairly readable
+when printed.  An example of a valid stamp is
+"<strong>2000-06-24.13:03:59</strong>".
+We'll call this the "full date format".  When Timestamp objects are
+printed as strings, they appear in the full date format with
+the time always given in GMT.  The full date format is always
+exactly 19 characters long.
+
+<p>For user input, some partial forms are also permitted:
+the whole time or just the seconds may be omitted; and the whole date
+may be omitted or just the year may be omitted.  If the time is given,
+the time is interpreted in the user's local time zone.
+The <tt>Date</tt> constructor takes care of these conversions.
+In the following examples, suppose that <em>yyyy</em> is the current year,
+<em>mm</em> is the current month, and <em>dd</em> is the current
+day of the month; and suppose that the user is on Eastern Standard Time.
+
+<ul>
+<li>"<strong>2000-04-17</strong>" means &lt;Date 2000-04-17.00:00:00&gt;
+<li>"<strong>01-25</strong>" means &lt;Date <em>yyyy</em>-01-25.00:00:00&gt;
+<li>"<strong>2000-04-17.03:45</strong>" means &lt;Date 2000-04-17.08:45:00&gt;
+<li>"<strong>08-13.22:13</strong>" means &lt;Date <em>yyyy</em>-08-14.03:13:00&gt;
+<li>"<strong>11-07.09:32:43</strong>" means &lt;Date <em>yyyy</em>-11-07.14:32:43&gt;
+<li>"<strong>14:25</strong>" means
+&lt;Date <em>yyyy</em>-<em>mm</em>-<em>dd</em>.19:25:00&gt;
+<li>"<strong>8:47:11</strong>" means
+&lt;Date <em>yyyy</em>-<em>mm</em>-<em>dd</em>.13:47:11&gt;
+<li>the special date "<strong>.</strong>" means "right now"
+</ul>
+
+<p>Date intervals are specified using the suffixes
+"y", "m", and "d".  The suffix "w" (for "week") means 7 days.
+Time intervals are specified in hh:mm:ss format (the seconds
+may be omitted, but the hours and minutes may not).
+
+<ul>
+<li>"<strong>3y</strong>" means three years
+<li>"<strong>2y 1m</strong>" means two years and one month
+<li>"<strong>1m 25d</strong>" means one month and 25 days
+<li>"<strong>2w 3d</strong>" means two weeks and three days
+<li>"<strong>1d 2:50</strong>" means one day, two hours, and 50 minutes
+<li>"<strong>14:00</strong>" means 14 hours
+<li>"<strong>0:04:33</strong>" means four minutes and 33 seconds
+</ul>
+
+<p>The Date class should understand simple date expressions of the form 
+<em>stamp</em> + <em>interval</em> and <em>stamp</em> - <em>interval</em>.
+When adding or subtracting intervals involving months or years, the
+components are handled separately.  For example, when evaluating
+"<strong>2000-06-25 + 1m 10d</strong>", we first add one month to
+get <strong>2000-07-25</strong>, then add 10 days to get
+<strong>2000-08-04</strong> (rather than trying to decide whether
+<strong>1m 10d</strong> means 38 or 40 or 41 days).
+
+<p>Here is an outline of the Date and Interval classes.
+
+<blockquote>
+<pre><small>class <strong>Date</strong>:
+    def <strong>__init__</strong>(self, spec, offset):
+        """Construct a date given a specification and a time zone offset.
+
+        'spec' is a full date or a partial form, with an optional
+        added or subtracted interval.  'offset' is the local time
+        zone offset from GMT in hours.
+        """
+
+    def <strong>__add__</strong>(self, interval):
+        """Add an interval to this date to produce another date."""
+
+    def <strong>__sub__</strong>(self, interval):
+        """Subtract an interval from this date to produce another date."""
+
+    def <strong>__cmp__</strong>(self, other):
+        """Compare this date to another date."""
+
+    def <strong>__str__</strong>(self):
+        """Return this date as a string in the yyyy-mm-dd.hh:mm:ss format."""
+
+    def <strong>local</strong>(self, offset):
+        """Return this date as yyyy-mm-dd.hh:mm:ss in a local time zone."""
+
+class <strong>Interval</strong>:
+    def <strong>__init__</strong>(self, spec):
+        """Construct an interval given a specification."""
+
+    def <strong>__cmp__</strong>(self, other):
+        """Compare this interval to another interval."""
+        
+    def <strong>__str__</strong>(self):
+        """Return this interval as a string."""
+</small></pre>
+</blockquote>
+
+<p>Here are some examples of how these classes would behave in practice.
+For the following examples, assume that we are on Eastern Standard
+Time and the current local time is 19:34:02 on 25 June 2000.
+
+<blockquote><pre><small
+>&gt;&gt;&gt; <span class="input">Date(".")</span>
+<span class="output">&lt;Date 2000-06-26.00:34:02&gt;</span>
+&gt;&gt;&gt; <span class="input">_.local(-5)</span>
+<span class="output">"2000-06-25.19:34:02"</span>
+&gt;&gt;&gt; <span class="input">Date(". + 2d")</span>
+<span class="output">&lt;Date 2000-06-28.00:34:02&gt;</span>
+&gt;&gt;&gt; <span class="input">Date("1997-04-17", -5)</span>
+<span class="output">&lt;Date 1997-04-17.00:00:00&gt;</span>
+&gt;&gt;&gt; <span class="input">Date("01-25", -5)</span>
+<span class="output">&lt;Date 2000-01-25.00:00:00&gt;</span>
+&gt;&gt;&gt; <span class="input">Date("08-13.22:13", -5)</span>
+<span class="output">&lt;Date 2000-08-14.03:13:00&gt;</span>
+&gt;&gt;&gt; <span class="input">Date("14:25", -5)</span>
+<span class="output">&lt;Date 2000-06-25.19:25:00&gt;</span>
+&gt;&gt;&gt; <span class="input">Interval("  3w  1  d  2:00")</span>
+<span class="output">&lt;Interval 22d 2:00&gt;</span>
+&gt;&gt;&gt; <span class="input">Date(". + 2d") - Interval("3w")</span>
+<span class="output">&lt;Date 2000-06-07.00:34:02&gt;</span
+></small></pre></blockquote>
+
+<h3>3.2. Items and Classes</h3>
+
+<p>Items contain data in <em>properties</em>.  To Python, these
+properties are presented as the key-value pairs of a dictionary.
+Each item belongs to a <em>class</em> which defines the names
+and types of its properties.  The database permits the creation
+and modification of classes as well as items.
+
+<h3>3.3. Identifiers and Designators</h3>
+
+<p>Each item has a numeric identifier which is unique among
+items in its class.  The items are numbered sequentially
+within each class in order of creation, starting from 1.
+The <em>designator</em>
+for an item is a way to identify an item in the database, and
+consists of the name of the item's class concatenated with
+the item's numeric identifier.
+
+<p>For example, if "spam" and "eggs" are classes, the first
+item created in class "spam" has id 1 and designator "spam1".
+The first item created in class "eggs" also has id 1 but has
+the distinct designator "eggs1".  Item designators are
+conventionally enclosed in square brackets when mentioned
+in plain text.  This permits a casual mention of, say,
+"[patch37]" in an e-mail message to be turned into an active
+hyperlink.
+
+<h3>3.4. Property Names and Types</h3>
+
+<p>Property names must begin with a letter.
+
+<p>A property may be one of five <em>basic types</em>:
+
+<ul>
+<li><em>String</em> properties are for storing arbitrary-length
+strings.
+
+<li><em>Date</em> properties store date-and-time stamps.
+Their values are Timestamp objects.
+
+<li>A <em>Link</em> property refers to a single other item
+selected from a specified class.  The class is part of the property;
+the value is an integer, the id of the chosen item.
+
+<li>A <em>Multilink</em> property refers to possibly many items
+in a specified class.  The value is a list of integers.
+</ul>
+
+<p><tt>None</tt> is also a permitted value for any of these property
+types.  An attempt to store <tt>None</tt> into a String property
+stores the empty string; an attempt to store <tt>None</tt>
+into a Multilink property stores an empty list.
+
+<h3>3.5. Interface Specification</h3>
+
+<p>The hyperdb module provides property objects to designate
+the different kinds of properties.  These objects are used when
+specifying what properties belong in classes.
+
+<blockquote><pre><small
+>class <strong>String</strong>:
+    def <strong>__init__</strong>(self):
+        """An object designating a String property."""
+
+class <strong>Date</strong>:
+    def <strong>__init__</strong>(self):
+        """An object designating a Date property."""
+
+class <strong>Link</strong>:
+    def <strong>__init__</strong>(self, classname):
+        """An object designating a Link property that links to
+        items in a specified class."""
+
+class <strong>Multilink</strong>:
+    def <strong>__init__</strong>(self, classname):
+        """An object designating a Multilink property that links
+        to items in a specified class."""
+</small></pre></blockquote>
+
+<p>Here is the interface provided by the hyperdatabase.
+
+<blockquote><pre><small
+>class <strong>Database</strong>:
+    """A database for storing records containing flexible data types."""
+
+    def <strong>__init__</strong>(self, storagelocator, journaltag):
+        """Open a hyperdatabase given a specifier to some storage.
+
+        The meaning of 'storagelocator' depends on the particular
+        implementation of the hyperdatabase.  It could be a file name,
+        a directory path, a socket descriptor for a connection to a
+        database over the network, etc.
+
+        The 'journaltag' is a token that will be attached to the journal
+        entries for any edits done on the database.  If 'journaltag' is
+        None, the database is opened in read-only mode: the Class.create(),
+        Class.set(), and Class.retire() methods are disabled.
+        """
+
+    def <strong>__getattr__</strong>(self, classname):
+        """A convenient way of calling self.getclass(classname)."""
+
+    def <strong>getclasses</strong>(self):
+        """Return a list of the names of all existing classes."""
+
+    def <strong>getclass</strong>(self, classname):
+        """Get the Class object representing a particular class.
+
+        If 'classname' is not a valid class name, a KeyError is raised.
+        """
+
+class <strong>Class</strong>:
+    """The handle to a particular class of items in a hyperdatabase."""
+
+    def <strong>__init__</strong>(self, db, classname, **properties):
+        """Create a new class with a given name and property specification.
+
+        'classname' must not collide with the name of an existing class,
+        or a ValueError is raised.  The keyword arguments in 'properties'
+        must map names to property objects, or a TypeError is raised.
+        """
+
+    # Editing items:
+
+    def <strong>create</strong>(self, **propvalues):
+        """Create a new item of this class and return its id.
+
+        The keyword arguments in 'propvalues' map property names to values.
+        The values of arguments must be acceptable for the types of their
+        corresponding properties or a TypeError is raised.  If this class
+        has a key property, it must be present and its value must not
+        collide with other key strings or a ValueError is raised.  Any other
+        properties on this class that are missing from the 'propvalues'
+        dictionary are set to None.  If an id in a link or multilink
+        property does not refer to a valid item, an IndexError is raised.
+        """
+
+    def <strong>get</strong>(self, itemid, propname):
+        """Get the value of a property on an existing item of this class.
+
+        'itemid' must be the id of an existing item of this class or an
+        IndexError is raised.  'propname' must be the name of a property
+        of this class or a KeyError is raised.
+        """
+
+    def <strong>set</strong>(self, itemid, **propvalues):
+        """Modify a property on an existing item of this class.
+        
+        'itemid' must be the id of an existing item of this class or an
+        IndexError is raised.  Each key in 'propvalues' must be the name
+        of a property of this class or a KeyError is raised.  All values
+        in 'propvalues' must be acceptable types for their corresponding
+        properties or a TypeError is raised.  If the value of the key
+        property is set, it must not collide with other key strings or a
+        ValueError is raised.  If the value of a Link or Multilink
+        property contains an invalid item id, a ValueError is raised.
+        """
+
+    def <strong>retire</strong>(self, itemid):
+        """Retire an item.
+        
+        The properties on the item remain available from the get() method,
+        and the item's id is never reused.  Retired items are not returned
+        by the find(), list(), or lookup() methods, and other items may
+        reuse the values of their key properties.
+        """
+
+    def <strong>history</strong>(self, itemid):
+        """Retrieve the journal of edits on a particular item.
+
+        'itemid' must be the id of an existing item of this class or an
+        IndexError is raised.
+
+        The returned list contains tuples of the form
+
+            (date, tag, action, params)
+
+        'date' is a Timestamp object specifying the time of the change and
+        'tag' is the journaltag specified when the database was opened.
+        'action' may be:
+
+            'create' or 'set' -- 'params' is a dictionary of property values
+            'link' or 'unlink' -- 'params' is (classname, itemid, propname)
+            'retire' -- 'params' is None
+        """
+
+    # Locating items:
+
+    def <strong>setkey</strong>(self, propname):
+        """Select a String property of this class to be the key property.
+
+        'propname' must be the name of a String property of this class or
+        None, or a TypeError is raised.  The values of the key property on
+        all existing items must be unique or a ValueError is raised.
+        """
+
+    def <strong>getkey</strong>(self):
+        """Return the name of the key property for this class or None."""
+
+    def <strong>lookup</strong>(self, keyvalue):
+        """Locate a particular item by its key property and return its id.
+
+        If this class has no key property, a TypeError is raised.  If the
+        'keyvalue' matches one of the values for the key property among
+        the items in this class, the matching item's id is returned;
+        otherwise a KeyError is raised.
+        """
+
+    def <strong>find</strong>(self, propname, itemid):
+        """Get the ids of items in this class which link to a given item.
+        
+        'propname' must be the name of a property in this class, or a
+        KeyError is raised.  That property must be a Link or Multilink
+        property, or a TypeError is raised.  'itemid' must be the id of
+        an existing item in the class linked to by the given property,
+        or an IndexError is raised.
+        """
+
+    def <strong>list</strong>(self):
+        """Return a list of the ids of the active items in this class."""
+
+    def <strong>count</strong>(self):
+        """Get the number of items in this class.
+
+        If the returned integer is 'numitems', the ids of all the items
+        in this class run from 1 to numitems, and numitems+1 will be the
+        id of the next item to be created in this class.
+        """
+
+    # Manipulating properties:
+
+    def <strong>getprops</strong>(self):
+        """Return a dictionary mapping property names to property objects."""
+
+    def <strong>addprop</strong>(self, **properties):
+        """Add properties to this class.
+
+        The keyword arguments in 'properties' must map names to property
+        objects, or a TypeError is raised.  None of the keys in 'properties'
+        may collide with the names of existing properties, or a ValueError
+        is raised before any properties have been added.
+        """</small></pre></blockquote>
+
+<h3>3.6. Application Example</h3>
+
+<p>Here is an example of how the hyperdatabase module would work in practice.
+
+<blockquote><pre><small
+>&gt;&gt;&gt; <span class="input">import hyperdb</span>
+&gt;&gt;&gt; <span class="input">db = hyperdb.Database("foo.db", "ping")</span>
+&gt;&gt;&gt; <span class="input">db</span>
+<span class="output">&lt;hyperdb.Database "foo.db" opened by "ping"&gt;</span>
+&gt;&gt;&gt; <span class="input">hyperdb.Class(db, "status", name=hyperdb.String())</span>
+<span class="output">&lt;hyperdb.Class "status"&gt;</span>
+&gt;&gt;&gt; <span class="input">_.setkey("name")</span>
+&gt;&gt;&gt; <span class="input">db.status.create(name="unread")</span>
+<span class="output">1</span>
+&gt;&gt;&gt; <span class="input">db.status.create(name="in-progress")</span>
+<span class="output">2</span>
+&gt;&gt;&gt; <span class="input">db.status.create(name="testing")</span>
+<span class="output">3</span>
+&gt;&gt;&gt; <span class="input">db.status.create(name="resolved")</span>
+<span class="output">4</span>
+&gt;&gt;&gt; <span class="input">db.status.count()</span>
+<span class="output">4</span>
+&gt;&gt;&gt; <span class="input">db.status.list()</span>
+<span class="output">[1, 2, 3, 4]</span>
+&gt;&gt;&gt; <span class="input">db.status.lookup("in-progress")</span>
+<span class="output">2</span>
+&gt;&gt;&gt; <span class="input">db.status.retire(3)</span>
+&gt;&gt;&gt; <span class="input">db.status.list()</span>
+<span class="output">[1, 2, 4]</span>
+&gt;&gt;&gt; <span class="input">hyperdb.Class(db, "issue", title=hyperdb.String(), status=hyperdb.Link("status"))</span>
+<span class="output">&lt;hyperdb.Class "issue"&gt;</span>
+&gt;&gt;&gt; <span class="input">db.issue.create(title="spam", status=1)</span>
+<span class="output">1</span>
+&gt;&gt;&gt; <span class="input">db.issue.create(title="eggs", status=2)</span>
+<span class="output">2</span>
+&gt;&gt;&gt; <span class="input">db.issue.create(title="ham", status=4)</span>
+<span class="output">3</span>
+&gt;&gt;&gt; <span class="input">db.issue.create(title="arguments", status=2)</span>
+<span class="output">4</span>
+&gt;&gt;&gt; <span class="input">db.issue.create(title="abuse", status=1)</span>
+<span class="output">5</span>
+&gt;&gt;&gt; <span class="input">hyperdb.Class(db, "user", username=hyperdb.Key(), password=hyperdb.String())</span>
+<span class="output">&lt;hyperdb.Class "user"&gt;</span>
+&gt;&gt;&gt; <span class="input">db.issue.addprop(fixer=hyperdb.Link("user"))</span>
+&gt;&gt;&gt; <span class="input">db.issue.getprops()</span>
+<span class="output"
+>{"title": &lt;hyperdb.String&gt;, "status": &lt;hyperdb.Link to "status"&gt;,
+ "user": &lt;hyperdb.Link to "user"&gt;}</span>
+&gt;&gt;&gt; <span class="input">db.issue.set(5, status=2)</span>
+&gt;&gt;&gt; <span class="input">db.issue.get(5, "status")</span>
+<span class="output">2</span>
+&gt;&gt;&gt; <span class="input">db.status.get(2, "name")</span>
+<span class="output">"in-progress"</span>
+&gt;&gt;&gt; <span class="input">db.issue.get(5, "title")</span>
+<span class="output">"abuse"</span>
+&gt;&gt;&gt; <span class="input">db.issue.find("status", db.status.lookup("in-progress"))</span>
+<span class="output">[2, 4, 5]</span>
+&gt;&gt;&gt; <span class="input">db.issue.history(5)</span>
+<span class="output"
+>[(&lt;Date 2000-06-28.19:09:43&gt;, "ping", "create", {"title": "abuse", "status": 1}),
+ (&lt;Date 2000-06-28.19:11:04&gt;, "ping", "set", {"status": 2})]</span>
+&gt;&gt;&gt; <span class="input">db.status.history(1)</span>
+<span class="output"
+>[(&lt;Date 2000-06-28.19:09:43&gt;, "ping", "link", ("issue", 5, "status")),
+ (&lt;Date 2000-06-28.19:11:04&gt;, "ping", "unlink", ("issue", 5, "status"))]</span>
+&gt;&gt;&gt; <span class="input">db.status.history(2)</span>
+<span class="output"
+>[(&lt;Date 2000-06-28.19:11:04&gt;, "ping", "link", ("issue", 5, "status"))]</span>
+</small></pre></blockquote>
+
+<p>For the purposes of journalling, when a Multilink property is
+set to a new list of items, the hyperdatabase compares the old
+list to the new list.
+The journal records "unlink" events for all the items that appear
+in the old list but not the new list,
+and "link" events for
+all the items that appear in the new list but not in the old list.
+
+<p><hr>
+<h2>4. Roundup Database</h2>
+
+<p>The Roundup database layer is implemented on top of the
+hyperdatabase and mediates calls to the database.
+Some of the classes in the Roundup database are considered
+<em>item classes</em>.
+The Roundup database layer adds detectors and user items,
+and on items it provides mail spools, nosy lists, and superseders.
+
+<h3>4.1. Reserved Classes</h3>
+
+<p>Internal to this layer we reserve three special classes
+of items that are not items.
+
+<h4>4.1.1. Users</h4>
+
+<p>Users are stored in the hyperdatabase as items of
+class "user".  The "user" class has the definition:
+
+<blockquote><pre><small
+>hyperdb.Class(db, "user", username=hyperdb.String(),
+                          password=hyperdb.String(),
+                          address=hyperdb.String())
+db.user.setkey("username")</small></pre></blockquote>
+
+<h4>4.1.2. Messages</h4>
+
+<p>E-mail messages are represented by hyperdatabase items of class "msg".
+The actual text content of the messages is stored in separate files.
+(There's no advantage to be gained by stuffing them into the
+hyperdatabase, and if messages are stored in ordinary text files,
+they can be grepped from the command line.)  The text of a message is
+saved in a file named after the message item designator (e.g. "msg23")
+for the sake of the command interface (see below).  Attachments are
+stored separately and associated with "file" items.
+The "msg" class has the definition:
+
+<blockquote><pre><small
+>hyperdb.Class(db, "msg", author=hyperdb.Link("user"),
+                         recipients=hyperdb.Multilink("user"),
+                         date=hyperdb.Date(),
+                         summary=hyperdb.String(),
+                         files=hyperdb.Multilink("file"))</small
+></pre></blockquote>
+
+<p>The "author" property indicates the author of the message
+(a "user" item must exist in the hyperdatabase for any messages
+that are stored in the system).
+The "summary" property contains a summary of the message for display
+in a message index.
+
+<h4>4.1.3. Files</h4>
+
+<p>Submitted files are represented by hyperdatabase
+items of class "file".  Like e-mail messages, the file content
+is stored in files outside the database,
+named after the file item designator (e.g. "file17").
+The "file" class has the definition:
+
+<blockquote><pre><small
+>hyperdb.Class(db, "file", user=hyperdb.Link("user"),
+                          name=hyperdb.String(),
+                          type=hyperdb.String())</small></pre></blockquote>
+
+<p>The "user" property indicates the user who submitted the
+file, the "name" property holds the original name of the file,
+and the "type" property holds the MIME type of the file as received.
+
+<h3>4.2. Item Classes</h3>
+
+<p>All items have the following standard properties:
+
+<blockquote><pre><small
+>title=hyperdb.String()
+messages=hyperdb.Multilink("msg")
+files=hyperdb.Multilink("file")
+nosy=hyperdb.Multilink("user")
+superseder=hyperdb.Multilink("item")</small></pre></blockquote>
+
+<p>Also, two Date properties named "creation" and "activity" are
+fabricated by the Roundup database layer.  By "fabricated" we
+mean that no such properties are actually stored in the
+hyperdatabase, but when properties on items are requested, the
+"creation" and "activity" properties are made available.
+The value of the "creation" property is the date when an item was
+created, and the value of the "activity" property is the
+date when any property on the item was last edited (equivalently,
+these are the dates on the first and last records in the item's journal).
+
+<h3>4.3. Interface Specification</h3>
+
+<p>The interface to a Roundup database delegates most method
+calls to the hyperdatabase, except for the following
+changes and additional methods.
+
+<blockquote><pre><small
+>class <strong>Database</strong>:
+    # Overridden methods:
+
+    def <strong>__init__</strong>(self, storagelocator, journaltag):
+        """When the Roundup database is opened by a particular user,
+        the 'journaltag' is the id of the user's "user" item."""
+
+    def <strong>getclass</strong>(self, classname):
+        """This method now returns an instance of either Class or
+        ItemClass depending on whether an item class is specified."""
+
+    # New methods:
+
+    def <strong>getuid</strong>(self):
+        """Return the id of the "user" item associated with the user
+        that owns this connection to the hyperdatabase."""
+
+class <strong>Class</strong>:
+    # Overridden methods:
+
+    def <strong>create</strong>(self, **propvalues):
+    def <strong>set</strong>(self, **propvalues):
+    def <strong>retire</strong>(self, itemid):
+        """These operations trigger detectors and can be vetoed.  Attempts
+        to modify the "creation" or "activity" properties cause a KeyError.
+        """
+
+    # New methods:
+
+    def <strong>audit</strong>(self, event, detector):
+    def <strong>react</strong>(self, event, detector):
+        """Register a detector (see below for more details)."""
+
+class <strong>ItemClass</strong>(Class):
+    # Overridden methods:
+
+    def <strong>__init__</strong>(self, db, classname, **properties):
+        """The newly-created class automatically includes the "messages",
+        "files", "nosy", and "superseder" properties.  If the 'properties'
+        dictionary attempts to specify any of these properties or a
+        "creation" or "activity" property, a ValueError is raised."""
+
+    def <strong>get</strong>(self, itemid, propname):
+    def <strong>getprops</strong>(self):
+        """In addition to the actual properties on the item, these
+        methods provide the "creation" and "activity" properties."""
+
+    # New methods:
+
+    def <strong>addmessage</strong>(self, itemid, summary, text):
+        """Add a message to an item's mail spool.
+
+        A new "msg" item is constructed using the current date, the
+        user that owns the database connection as the author, and
+        the specified summary text.  The "files" and "recipients"
+        fields are left empty.  The given text is saved as the body
+        of the message and the item is appended to the "messages"
+        field of the specified item.
+        """
+
+    def <strong>nosymessage</strong>(self, itemid, msgid):
+        """Send a message to the members of an item's nosy list.
+
+        The message is sent only to users on the nosy list who are not
+        already on the "recipients" list for the message.  These users
+        are then added to the message's "recipients" list.
+        """
+</small></pre></blockquote>
+
+<h3>4.4. Default Schema</h3>
+
+<p>The default schema included with Roundup turns it into a
+typical software bug tracker.  The database is set up like this:
+
+<blockquote><pre><small
+>pri = Class(db, "priority", name=hyperdb.String(), order=hyperdb.String())
+pri.setkey("name")
+pri.create(name="critical", order="1")
+pri.create(name="urgent", order="2")
+pri.create(name="bug", order="3")
+pri.create(name="feature", order="4")
+pri.create(name="wish", order="5")
+
+stat = Class(db, "status", name=hyperdb.String(), order=hyperdb.String())
+stat.setkey("name")
+stat.create(name="unread", order="1")
+stat.create(name="deferred", order="2")
+stat.create(name="chatting", order="3")
+stat.create(name="need-eg", order="4")
+stat.create(name="in-progress", order="5")
+stat.create(name="testing", order="6")
+stat.create(name="done-cbb", order="7")
+stat.create(name="resolved", order="8")
+
+Class(db, "keyword", name=hyperdb.String())
+
+Class(db, "issue", fixer=hyperdb.Multilink("user"),
+                   topic=hyperdb.Multilink("keyword"),
+                   priority=hyperdb.Link("priority"),
+                   status=hyperdb.Link("status"))
+</small></pre></blockquote>
+
+<p>(The "order" property hasn't been explained yet.  It
+gets used by the Web user interface for sorting.)
+
+<p>The above isn't as pretty-looking as the schema specification
+in the first-stage submission, but it could be made just as easy
+with the addition of a convenience function like <tt>Choice</tt>
+for setting up the "priority" and "status" classes:
+
+<blockquote><pre><small
+>def Choice(name, *options):
+    cl = Class(db, name, name=hyperdb.String(), order=hyperdb.String())
+    for i in range(len(options)):
+        cl.create(name=option[i], order=i)
+    return hyperdb.Link(name)
+</small></pre></blockquote>
+
+<p><hr>
+<h2>5. Detector Interface</h2>
+
+<p>Detectors are Python functions that are triggered on certain
+kinds of events.  The definitions of the
+functions live in Python modules placed in a directory set aside
+for this purpose.  Importing the Roundup database module also
+imports all the modules in this directory, and the <tt>init()</tt>
+function of each module is called when a database is opened to
+provide it a chance to register its detectors.
+
+<p>There are two kinds of detectors:
+
+<ul>
+<li>an <em>auditor</em> is triggered just before modifying an item
+<li>a <em>reactor</em> is triggered just after an item has been modified
+</ul>
+
+<p>When the Roundup database is about to perform a
+<tt>create()</tt>, <tt>set()</tt>, or <tt>retire()</tt>
+operation, it first calls any auditors that
+have been registered for that operation on that class.
+Any auditor may raise a <tt>Reject</tt> exception
+to abort the operation.
+
+<p>If none of the auditors raises an exception, the database
+proceeds to carry out the operation.  After it's done, it
+then calls all of the reactors that have been registered
+for the operation.
+
+<h3>5.1. Interface Specification</h3>
+
+<p>The <tt>audit()</tt> and <tt>react()</tt> methods
+register detectors on a given class of items.
+
+<blockquote><pre><small
+>class Class:
+    def <strong>audit</strong>(self, event, detector):
+        """Register an auditor on this class.
+
+        'event' should be one of "create", "set", or "retire".
+        'detector' should be a function accepting four arguments.
+        """
+
+    def <strong>react</strong>(self, event, detector):
+        """Register a reactor on this class.
+
+        'event' should be one of "create", "set", or "retire".
+        'detector' should be a function accepting four arguments.
+        """
+</small></pre></blockquote>
+
+<p>Auditors are called with the arguments:
+
+<blockquote><pre><small
+>audit(db, cl, itemid, newdata)</small></pre></blockquote>
+
+where <tt>db</tt> is the database, <tt>cl</tt> is an
+instance of Class or ItemClass within the database, and <tt>newdata</tt>
+is a dictionary mapping property names to values.
+
+For a <tt>create()</tt>
+operation, the <tt>itemid</tt> argument is <tt>None</tt> and <tt>newdata</tt>
+contains all of the initial property values with which the item
+is about to be created.
+
+For a <tt>set()</tt> operation, <tt>newdata</tt>
+contains only the names and values of properties that are about
+to be changed.
+
+For a <tt>retire()</tt> operation, <tt>newdata</tt> is <tt>None</tt>.
+
+<p>Reactors are called with the arguments:
+
+<blockquote><pre><small
+>react(db, cl, itemid, olddata)</small></pre></blockquote>
+
+where <tt>db</tt> is the database, <tt>cl</tt> is an
+instance of Class or ItemClass within the database, and <tt>olddata</tt>
+is a dictionary mapping property names to values.
+
+For a <tt>create()</tt>
+operation, the <tt>itemid</tt> argument is the id of the
+newly-created item and <tt>olddata</tt> is None.
+
+For a <tt>set()</tt> operation, <tt>olddata</tt>
+contains the names and previous values of properties that were changed.
+
+For a <tt>retire()</tt> operation, <tt>itemid</tt> is the
+id of the retired item and <tt>olddata</tt> is <tt>None</tt>.
+
+<h3>5.2. Detector Example</h3>
+
+<p>Here is an example of detectors written for a hypothetical
+project-management application, where users can signal approval
+of a project by adding themselves to an "approvals" list, and
+a project proceeds when it has three approvals.
+
+<blockquote><pre><small
+># Permit users only to add themselves to the "approvals" list.
+
+def check_approvals(db, cl, id, newdata):
+    if newdata.has_key("approvals"):
+        if cl.get(id, "status") == db.status.lookup("approved"):
+            raise Reject, "You can't modify the approvals list " \
+                          "for a project that has already been approved."
+        old = cl.get(id, "approvals")
+        new = newdata["approvals"]
+        for uid in old:
+            if uid not in new and uid != db.getuid():
+                raise Reject, "You can't remove other users from the "
+                              "approvals list; you can only remove yourself."
+        for uid in new:
+            if uid not in old and uid != db.getuid():
+                raise Reject, "You can't add other users to the approvals "
+                              "list; you can only add yourself."
+
+# When three people have approved a project, change its
+# status from "pending" to "approved".
+
+def approve_project(db, cl, id, olddata):
+    if olddata.has_key("approvals") and len(cl.get(id, "approvals")) == 3:
+        if cl.get(id, "status") == db.status.lookup("pending"):
+            cl.set(id, status=db.status.lookup("approved"))
+
+def init(db):
+    db.project.audit("set", check_approval)
+    db.project.react("set", approve_project)</small
+></pre></blockquote>    
+
+<p>Here is another example of a detector that can allow or prevent
+the creation of new items.  In this scenario, patches for a software
+project are submitted by sending in e-mail with an attached file,
+and we want to ensure that there are <tt>text/plain</tt> attachments on
+the message.  The maintainer of the package can then apply the
+patch by setting its status to "applied".
+
+<blockquote><pre><small
+># Only accept attempts to create new patches that come with patch files.
+
+def check_new_patch(db, cl, id, newdata):
+    if not newdata["files"]:
+        raise Reject, "You can't submit a new patch without " \
+                      "attaching a patch file."
+    for fileid in newdata["files"]:
+        if db.file.get(fileid, "type") != "text/plain":
+            raise Reject, "Submitted patch files must be text/plain."
+
+# When the status is changed from "approved" to "applied", apply the patch.
+
+def apply_patch(db, cl, id, olddata):
+    if cl.get(id, "status") == db.status.lookup("applied") and \
+        olddata["status"] == db.status.lookup("approved"):
+        # ...apply the patch...
+
+def init(db):
+    db.patch.audit("create", check_new_patch)
+    db.patch.react("set", apply_patch)</small
+></pre></blockquote>
+
+<p><hr>
+<h2>6. Command Interface</h2>
+
+<p>The command interface is a very simple and minimal interface,
+intended only for quick searches and checks from the shell prompt.
+(Anything more interesting can simply be written in Python using
+the Roundup database module.)
+
+<h3>6.1. Interface Specification</h3>
+
+<p>A single command, <tt>roundup</tt>, provides basic access to
+the hyperdatabase from the command line.
+
+<ul>
+<li><tt>roundup&nbsp;get&nbsp;</tt>[<tt>-list</tt>]<tt>&nbsp;</tt
+><em>designator</em>[<tt>,</tt
+><em>designator</em><tt>,</tt>...]<tt>&nbsp;</tt><em>propname</em>
+<li><tt>roundup&nbsp;set&nbsp;</tt><em>designator</em>[<tt>,</tt
+><em>designator</em><tt>,</tt>...]<tt>&nbsp;</tt><em>propname</em
+><tt>=</tt><em>value</em> ...
+<li><tt>roundup&nbsp;find&nbsp;</tt>[<tt>-list</tt>]<tt>&nbsp;</tt
+><em>classname</em><tt>&nbsp;</tt><em>propname</em>=<em>value</em> ...
+</ul>
+
+<p>Property values are represented as strings in command arguments
+and in the printed results:
+
+<ul>
+<li>Strings are, well, strings.
+
+<li>Date values are printed in the full date format in the local
+time zone, and accepted in the full format or any of the partial
+formats explained above.
+
+<li>Link values are printed as item designators.  When given as
+an argument, item designators and key strings are both accepted.
+
+<li>Multilink values are printed as lists of item designators
+joined by commas.  When given as an argument, item designators
+and key strings are both accepted; an empty string, a single item,
+or a list of items joined by commas is accepted.
+</ul>
+
+<p>When multiple items are specified to the
+<tt>roundup&nbsp;get</tt> or <tt>roundup&nbsp;set</tt>
+commands, the specified properties are retrieved or set
+on all the listed items.
+
+<p>When multiple results are returned by the <tt>roundup&nbsp;get</tt>
+or <tt>roundup&nbsp;find</tt> commands, they are printed one per
+line (default) or joined by commas (with the <tt>-list</tt>) option.
+
+<h3>6.2. Usage Example</h3>
+
+<p>To find all messages regarding in-progress issues that
+contain the word "spam", for example, you could execute the
+following command from the directory where the database
+dumps its files:
+
+<blockquote><pre><small
+>shell% <span class="input">for issue in `roundup find issue status=in-progress`; do</span>
+&gt; <span class="input">grep -l spam `roundup get $issue messages`</span>
+&gt; <span class="input">done</span>
+<span class="output">msg23
+msg49
+msg50
+msg61</span>
+shell%</small></pre></blockquote>
+
+<p>Or, using the <tt>-list</tt> option, this can be written as a single command:
+
+<blockquote><pre><small
+>shell% <span class="input">grep -l spam `roundup get \
+    \`roundup find -list issue status=in-progress\` messages`</span>
+<span class="output">msg23
+msg49
+msg50
+msg61</span>
+shell%</small></pre></blockquote>
+    
+<p><hr>
+<h2>7. E-mail User Interface</h2>
+
+<p>The Roundup system must be assigned an e-mail address
+at which to receive mail.  Messages should be piped to
+the Roundup mail-handling script by the mail delivery
+system (e.g. using an alias beginning with "|" for sendmail).
+
+<h3>7.1. Message Processing</h3>
+
+<p>Incoming messages are examined for multiple parts.
+In a <tt>multipart/mixed</tt> message or part, each subpart is
+extracted and examined.  In a <tt>multipart/alternative</tt>
+message or part, we look for a <tt>text/plain</tt> subpart and
+ignore the other parts.  The <tt>text/plain</tt> subparts are
+assembled to form the textual body of the message, to
+be stored in the file associated with a "msg" class item.
+Any parts of other types are each stored in separate
+files and given "file" class items that are linked to
+the "msg" item.
+
+<p>The "summary" property on message items is taken from
+the first non-quoting section in the message body.
+The message body is divided into sections by blank lines.
+Sections where the second and all subsequent lines begin
+with a "&gt;" or "|" character are considered "quoting
+sections".  The first line of the first non-quoting 
+section becomes the summary of the message.
+
+<p>All of the addresses in the To: and Cc: headers of the
+incoming message are looked up among the user items, and
+the corresponding users are placed in the "recipients"
+property on the new "msg" item.  The address in the From:
+header similarly determines the "author" property of the
+new "msg" item.
+The default handling for
+addresses that don't have corresponding users is to create
+new users with no passwords and a username equal to the
+address.  (The web interface does not permit logins for
+users with no passwords.)  If we prefer to reject mail from
+outside sources, we can simply register an auditor on the
+"user" class that prevents the creation of user items with
+no passwords.
+
+<p>The subject line of the incoming message is examined to
+determine whether the message is an attempt to create a new
+item or to discuss an existing item.  A designator enclosed
+in square brackets is sought as the first thing on the
+subject line (after skipping any "Fwd:" or "Re:" prefixes).
+
+<p>If an item designator (class name and id number) is found
+there, the newly created "msg" item is added to the "messages"
+property for that item, and any new "file" items are added to
+the "files" property for the item.
+
+<p>If just an item class name is found there, we attempt to
+create a new item of that class with its "messages" property
+initialized to contain the new "msg" item and its "files"
+property initialized to contain any new "file" items.
+
+<p>Both cases may trigger detectors (in the first case we
+are calling the <tt>set()</tt> method to add the message to the
+item's spool; in the second case we are calling the
+<tt>create()</tt> method to create a new item).  If an auditor
+raises an exception, the original message is bounced back to
+the sender with the explanatory message given in the exception.
+
+<h3>7.2. Nosy Lists</h3>
+
+<p>A standard detector is provided that watches for additions
+to the "messages" property.  When a new message is added, the
+detector sends it to all the users on the "nosy" list for the
+item that are not already on the "recipients" list of the
+message.  Those users are then appended to the "recipients"
+property on the message, so multiple copies of a message
+are never sent to the same user.  The journal recorded by
+the hyperdatabase on the "recipients" property then provides
+a log of when the message was sent to whom.
+
+<h3>7.3. Setting Properties</h3>
+
+<p>The e-mail interface also provides a simple way to set
+properties on items.  At the end of the subject line,
+<em>propname</em><tt>=</tt><em>value</em> pairs can be
+specified in square brackets, using the same conventions
+as for the <tt>roundup&nbsp;set</tt> shell command.
+
+<p><hr>
+<h2>8. Web User Interface</h2>
+
+<p>The web interface is provided by a CGI script that can be
+run under any web server.  A simple web server can easily be
+built on the standard <tt>CGIHTTPServer</tt> module, and
+should also be included in the distribution for quick
+out-of-the-box deployment.
+
+<p>The user interface is constructed from a number of template
+files containing mostly HTML.  Among the HTML tags in templates
+are interspersed some nonstandard tags, which we use as
+placeholders to be replaced by properties and their values.
+
+<h3>8.1. Views and View Specifiers</h3>
+
+<p>There are two main kinds of views: index views and item views.
+An index view displays a list of items of a particular class,
+optionally sorted and filtered as requested.  An item view
+presents the properties of a particular item for editing
+and displays the message spool for the item.
+
+<p>A <em>view specifier</em> is a string that specifies
+all the options needed to construct a particular view.
+It goes after the URL to the Roundup CGI script or the
+web server to form the complete URL to a view.  When the
+result of selecting a link or submitting a form takes
+the user to a new view, the Web browser should be redirected
+to a canonical location containing a complete view specifier
+so that the view can be bookmarked.
+
+<h3>8.2. Displaying Properties</h3>
+
+<p>Properties appear in the user interface in three contexts:
+in indices, in editors, and as filters.  For each type of
+property, there are several display possibilities.  For example,
+in an index view, a string property may just be printed as
+a plain string, but in an editor view, that property should
+be displayed in an editable field.
+
+<p>The display of a property is handled by functions in
+a <tt>displayers</tt> module.  Each function accepts at
+least three standard arguments -- the database, class name,
+and item id -- and returns a chunk of HTML.
+
+<p>Displayer functions are triggered by <tt>&lt;display&gt;</tt>
+tags in templates.  The <tt>call</tt> attribute of the tag
+provides a Python expression for calling the displayer
+function.  The three standard arguments are inserted in
+front of the arguments given.  For example, the occurrence of
+
+<blockquote><pre><small
+>    &lt;display call="plain('status', max=30)"&gt;
+</small></pre></blockquote>
+
+in a template triggers a call to
+    
+<blockquote><pre><small
+>    plain(db, "issue", 13, "status", max=30)
+</small></pre></blockquote>
+
+when displaying item 13 in the "issue" class.  The displayer
+functions can accept extra arguments to further specify
+details about the widgets that should be generated.  By defining new
+displayer functions, the user interface can be highly customized.
+
+<p>Some of the standard displayer functions include:
+
+<ul>
+<li><strong>plain</strong>: display a String property directly;
+display a Date property in a specified time zone with an option
+to omit the time from the date stamp; for a Link or Multilink
+property, display the key strings of the linked items (or the
+ids if the linked class has no key property)
+
+<li><strong>field</strong>: display a property like the
+<strong>plain</strong> displayer above, but in a text field
+to be edited
+
+<li><strong>menu</strong>: for a Link property, display
+a menu of the available choices
+
+<li><strong>link</strong>: for a Link or Multilink property,
+display the names of the linked items, hyperlinked to the
+item views on those items
+
+<li><strong>count</strong>: for a Multilink property, display
+a count of the number of links in the list
+
+<li><strong>reldate</strong>: display a Date property in terms
+of an interval relative to the current date (e.g. "+ 3w", "- 2d").
+
+<li><strong>download</strong>: show a Link("file") or Multilink("file")
+property using links that allow you to download files
+
+<li><strong>checklist</strong>: for a Link or Multilink property,
+display checkboxes for the available choices to permit filtering
+</ul>
+
+<h3>8.3. Index Views</h3>
+
+<p>An index view contains two sections: a filter section
+and an index section.
+The filter section provides some widgets for selecting
+which items appear in the index.  The index section is
+a table of items.
+
+<h4>8.3.1. Index View Specifiers</h4>
+
+<p>An index view specifier looks like this (whitespace
+has been added for clarity):
+
+<blockquote><pre><small
+>/issue?status=unread,in-progress,resolved&amp;
+        topic=security,ui&amp;
+        :group=+priority&amp;
+        :sort=-activity&amp;
+        :filters=status,topic&amp;
+        :columns=title,status,fixer
+</small></pre></blockquote>
+
+<p>The index view is determined by two parts of the
+specifier: the layout part and the filter part.
+The layout part consists of the query parameters that
+begin with colons, and it determines the way that the
+properties of selected items are displayed.
+The filter part consists of all the other query parameters,
+and it determines the criteria by which items 
+are selected for display.
+
+<p>The filter part is interactively manipulated with
+the form widgets displayed in the filter section.  The
+layout part is interactively manipulated by clicking
+on the column headings in the table.
+
+<p>The filter part selects the <em>union</em> of the
+sets of items with values matching any specified Link
+properties and the <em>intersection</em> of the sets
+of items with values matching any specified Multilink
+properties.
+
+<p>The example specifies an index of "issue" items.
+Only items with a "status" of <em>either</em>
+"unread" or "in-progres" or "resolved" are displayed,
+and only items with "topic" values including <em>both</em>
+"security" <em>and</em> "ui" are displayed.  The items
+are grouped by priority, arranged in ascending order;
+and within groups, sorted by activity, arranged in
+descending order.  The filter section shows filters
+for the "status" and "topic" properties, and the
+table includes columns for the "title", "status", and
+"fixer" properties.
+
+<p>Associated with each item class is a default
+layout specifier.  The layout specifier in the above
+example is the default layout to be provided with
+the default bug-tracker schema described above in
+section 4.4.
+
+<h4>8.3.2. Filter Section</h4>
+
+<p>The template for a filter section provides the
+filtering widgets at the top of the index view.
+Fragments enclosed in <tt>&lt;property&gt;</tt>...<tt>&lt;/property&gt;</tt>
+tags are included or omitted depending on whether the
+view specifier requests a filter for a particular property.
+
+<p>Here's a simple example of a filter template.
+
+<blockquote><pre><small
+>&lt;property name=status&gt;
+    &lt;display call="checklist('status')"&gt;
+&lt;/property&gt;
+&lt;br&gt;
+&lt;property name=priority&gt;
+    &lt;display call="checklist('priority')"&gt;
+&lt;/property&gt;
+&lt;br&gt;
+&lt;property name=fixer&gt;
+    &lt;display call="menu('fixer')"&gt;
+&lt;/property&gt;</small></pre></blockquote>
+
+<h4>8.3.3. Index Section</h4>
+
+<p>The template for an index section describes one row of
+the index table.
+Fragments enclosed in <tt>&lt;property&gt;</tt>...<tt>&lt;/property&gt;</tt>
+tags are included or omitted depending on whether the
+view specifier requests a column for a particular property.
+The table cells should contain <tt>&lt;display&gt;</tt> tags
+to display the values of the item's properties.
+
+<p>Here's a simple example of an index template.
+
+<blockquote><pre><small
+>&lt;tr&gt;
+    &lt;property name=title&gt;
+        &lt;td&gt;&lt;display call="plain('title', max=50)"&gt;&lt;/td&gt;
+    &lt;/property&gt;
+    &lt;property name=status&gt;
+        &lt;td&gt;&lt;display call="plain('status')"&gt;&lt;/td&gt;
+    &lt;/property&gt;
+    &lt;property name=fixer&gt;
+        &lt;td&gt;&lt;display call="plain('fixer')"&gt;&lt;/td&gt;
+    &lt;/property&gt;
+&lt;/tr&gt;</small></pre></blockquote>
+
+<h4>8.3.4. Sorting</h4>
+
+<p>String and Date values are sorted in the natural way.
+Link properties are sorted according to the value of the
+"order" property on the linked items if it is present; or
+otherwise on the key string of the linked items; or
+finally on the item ids.  Multilink properties are
+sorted according to how many links are present.
+
+<h3>8.4. Item Views</h3>
+
+<p>An item view contains an editor section and a spool section.
+At the top of an item view, links to superseding and superseded
+items are always displayed.
+
+<h4>8.4.1. Item View Specifiers</h4>
+
+<p>An item view specifier is simply the item's designator:
+
+<blockquote><pre><small
+>/patch23
+</small></pre></blockquote>
+
+<h4>8.4.2. Editor Section</h4>
+
+<p>The editor section is generated from a template
+containing <tt>&lt;display&gt;</tt> tags to insert
+the appropriate widgets for editing properties.
+
+<p>Here's an example of a basic editor template.
+
+<blockquote><pre><small
+>&lt;table&gt;
+&lt;tr&gt;
+    &lt;td colspan=2&gt;
+        &lt;display call="field('title', size=60)"&gt;
+    &lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+    &lt;td&gt;
+        &lt;display call="field('fixer', size=30)"&gt;
+    &lt;/td&gt;
+    &lt;td&gt;
+        &lt;display call="menu('status')&gt;
+    &lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+    &lt;td&gt;
+        &lt;display call="field('nosy', size=30)"&gt;
+    &lt;/td&gt;
+    &lt;td&gt;
+        &lt;display call="menu('priority')&gt;
+    &lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+    &lt;td colspan=2&gt;
+        &lt;display call="note()"&gt;
+    &lt;/td&gt;
+&lt;/tr&gt;
+&lt;/table&gt;
+</small></pre></blockquote>
+
+<p>As shown in the example, the editor template can also
+request the display of a "note" field, which is a
+text area for entering a note to go along with a change.
+
+<p>When a change is submitted, the system automatically
+generates a message describing the changed properties.
+The message displays all of the property values on the
+item and indicates which ones have changed.
+An example of such a message might be this:
+
+<blockquote><pre><small
+>title: Polly Parrot is dead
+priority: critical
+status: unread -&gt; in-progress
+fixer: (none)
+keywords: parrot,plumage,perch,nailed,dead
+</small></pre></blockquote>
+
+<p>If a note is given in the "note" field, the note is
+appended to the description.  The message is then added
+to the item's message spool (thus triggering the standard
+detector to react by sending out this message to the nosy list).
+
+<h4>8.4.3. Spool Section</h4>
+
+<p>The spool section lists messages in the item's "messages"
+property.  The index of messages displays the "date", "author",
+and "summary" properties on the message items, and selecting a
+message takes you to its content.
+
+<p><hr>
+<h2>9. Deployment Scenarios</h2>
+
+<p>The design described above should be general enough
+to permit the use of Roundup for bug tracking, managing
+projects, managing patches, or holding discussions.  By
+using items of multiple types, one could deploy a system
+that maintains requirement specifications, catalogs bugs,
+and manages submitted patches, where patches could be
+linked to the bugs and requirements they address.
+
+<p><hr>
+<h2>10. Acknowledgements</h2>
+
+<p>My thanks are due to Christy Heyl for 
+reviewing and contributing suggestions to this paper
+and motivating me to get it done, and to
+Jesse Vincent, Mark Miller, Christopher Simons,
+Jeff Dunmall, Wayne Gramlich, and Dean Tribble for
+their assistance with the first-round submission.
+</td>
+</tr>
+</table>
+
+<p>
+
+<center>
+<table>
+<tr>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/index.html"><b>[Home]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/faq.html"><b>[FAQ]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/license.html"><b>[License]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/contest-rules.html"><b>[Rules]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/sc_config/"><b>[Configure]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/sc_build/"><b>[Build]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/sc_test/"><b>[Test]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/sc_track/"><b>[Track]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/biblio.html"><b>[Resources]</b></a>&nbsp;&nbsp;&nbsp;</td>
+<td>&nbsp;&nbsp;&nbsp;<a href="http://www.software-carpentry.com/lists/"><b>[Archives]</b></a>&nbsp;&nbsp;&nbsp;</td>
+</tr>
+</table>
+</center>
+
+<p><hr>
+<center>Last modified 2001/04/06 11:50:59.9063 US/Mountain</center>
+</BODY>
+</HTML>

Added: tracker/vendor/roundup/current/doc/tracker_templates.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/tracker_templates.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,42 @@
+=========================
+Roundup Tracker Templates
+=========================
+
+:Version: $Revision: 1.2 $
+
+The templates distributed with Roundup are stored in the "share" directory
+nominated by Python. On Unix this is typically
+``/usr/share/roundup/templates/`` (or ``/usr/local/share...``) and
+on Windows this is ``c:\python22\share\roundup\templates\``.
+
+The template loading looks in four places to find the templates:
+
+1. *share* - eg. ``<prefix>/share/roundup/templates/*``.
+   This should be the standard place to find them when Roundup is
+   installed.
+2. ``<roundup.admin.__file__>/../templates/*``.
+   This will be used if Roundup's run in the distro (aka. source)
+   directory.
+3. ``<current working dir>/*``.
+   This is for when someone unpacks a 3rd-party template.
+4. ``<current working dir>``.
+   This is for someone who "cd"s to the 3rd-party template dir.
+
+Templates contain:
+
+- modules ``schema.py`` and ``initial_data.py``
+- directories ``html``, ``detectors`` and ``extensions``
+  (with appropriate contents)
+- template "marker" file ``TEMPLATE-INFO.txt``, which contains
+  the name of the template, a description of the template
+  and its intended audience.
+
+An example TEMPLATE-INFO.txt::
+
+ Name: classic
+ Description: This is a generic issue tracker that may be used to track bugs,
+              feature requests, project issues or any number of other types
+              of issues. Most users of Roundup will find that this template
+              suits them, with perhaps a few customisations.
+ Intended-For: All first-time Roundup users
+

Added: tracker/vendor/roundup/current/doc/upgrading.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/upgrading.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,1309 @@
+======================================
+Upgrading to newer versions of Roundup
+======================================
+
+Please read each section carefully and edit your tracker home files
+accordingly. Note that there is information about upgrade procedures in the
+`administration guide`_.
+
+If a specific version transition isn't mentioned here (eg. 0.6.7 to 0.6.8)
+then you don't need to do anything. If you're upgrading from 0.5.6 to
+0.6.8 though, you'll need to check the "0.5 to 0.6" and "0.6.x to 0.6.3"
+steps.
+
+.. contents::
+
+Migrating from 1.1.0 to 1.1.1
+=============================
+
+1.1.1 "Clear this message"
+--------------------------
+
+In 1.1.1, the standard ``page.html`` template includes a "clear this message"
+link in the green "ok" message bar that appears after a successful edit
+(or other) action.
+
+To include this in your tracker, change the following in your ``page.html``
+template::
+
+ <p tal:condition="options/ok_message | nothing" class="ok-message"
+    tal:repeat="m options/ok_message" tal:content="structure m">error</p>
+
+to be::
+
+ <p tal:condition="options/ok_message | nothing" class="ok-message">
+   <span tal:repeat="m options/ok_message"
+      tal:content="structure string:$m <br/ > " />
+    <a class="form-small" tal:attributes="href request/current_url"
+       i18n:translate="">clear this message</a>
+ </p>
+
+
+If you implemented the "clear this message" in your 1.1.0 tracker, then you
+should change it to the above and it will work much better!
+
+
+Migrating from 1.0.x to 1.1.0
+=============================
+
+1.1 Login "For Session Only"
+----------------------------
+
+In 1.1, web logins are alive for the length of a session only, *unless* you
+add the following to the login form in your tracker's ``page.html``::
+
+    <input type="checkbox" name="remember" id="remember">
+    <label for="remember" i18n:translate="">Remember me?</label><br>
+
+See the classic tracker ``page.html`` if you're unsure where this should
+go.
+
+
+1.1 Query Display Name
+----------------------
+
+The ``dispname`` web variable has been renamed ``@dispname`` to avoid
+clashing with other variables of the same name. If you are using the
+display name feature, you will need to edit your tracker's ``page.html``
+and ``issue.index.html`` pages to change ``dispname`` to ``@dispname``.
+
+A side-effect of this change is that the renderWith method used in the
+``home.html`` page may now take a dispname argument.
+
+
+1.1 "Clear this message"
+------------------------
+
+In 1.1, the standard ``page.html`` template includes a "clear this message"
+link in the green "ok" message bar that appears after a successful edit
+(or other) action.
+
+To include this in your tracker, change the following in your ``page.html``
+template::
+
+ <p tal:condition="options/ok_message | nothing" class="ok-message"
+    tal:repeat="m options/ok_message" tal:content="structure m">error</p>
+
+to be::
+
+ <p tal:condition="options/ok_message | nothing" class="ok-message">
+   <span tal:repeat="m options/ok_message"
+      tal:content="structure string:$m <br/ > " />
+    <a class="form-small" tal:attributes="href string:issue${context/id}"
+       i18n:translate="">clear this message</a>
+ </p>
+
+
+Migrating from 0.8.x to 1.0
+===========================
+
+1.0 New Query Permissions
+-------------------------
+
+New permissions are defined for query editing and viewing. To include these
+in your tracker, you need to add these lines to your tracker's
+``schema.py``::
+
+ # Users should be able to edit and view their own queries. They should also
+ # be able to view any marked as not private. They should not be able to
+ # edit others' queries, even if they're not private
+ def view_query(db, userid, itemid):
+     private_for = db.query.get(itemid, 'private_for')
+     if not private_for: return True
+     return userid == private_for
+ def edit_query(db, userid, itemid):
+     return userid == db.query.get(itemid, 'creator')
+ p = db.security.addPermission(name='View', klass='query', check=view_query,
+     description="User is allowed to view their own and public queries")
+ db.security.addPermissionToRole('User', p)
+ p = db.security.addPermission(name='Edit', klass='query', check=edit_query,
+     description="User is allowed to edit their queries")
+ db.security.addPermissionToRole('User', p)
+ p = db.security.addPermission(name='Create', klass='query',
+     description="User is allowed to create queries")
+ db.security.addPermissionToRole('User', p)
+
+and then remove 'query' from the line::
+
+ # Assign the access and edit Permissions for issue, file and message
+ # to regular users now
+ for cl in 'issue', 'file', 'msg', 'query', 'keyword':
+
+so it looks like::
+
+ for cl in 'issue', 'file', 'msg', 'keyword':
+
+
+Migrating from 0.8.0 to 0.8.3
+=============================
+
+0.8.3 Nosy Handling Changes
+---------------------------
+
+A change was made to fix a bug in the ``nosyreaction.py`` standard
+detector. To incorporate this fix in your trackers, you will need to copy
+the ``nosyreaction.py`` file from the ``templates/classic/detectors``
+directory of the source to your tracker's ``templates`` directory.
+
+If you have modified the ``nosyreaction.py`` file from the standard
+version, you will need to roll your changes into the new file.
+
+
+Migrating from 0.7.1 to 0.8.0
+=============================
+
+You *must* fully uninstall previous Roundup version before installing
+Roundup 0.8.0.  If you don't do that, ``roundup-admin install``
+command may fail to function properly.
+
+0.8.0 Backend changes
+---------------------
+
+Backends 'bsddb' and 'bsddb3' are removed.  If you are using one of these,
+you *must* migrate to another backend before upgrading.
+
+
+0.8.0 API changes
+-----------------
+
+Class.safeget() was removed from the API. Test your item ids before calling
+Class.get() instead.
+
+
+0.8.0 New tracker layout
+------------------------
+
+The ``config.py`` file has been replaced by ``config.ini``. You may use the
+roundup-admin command "genconfig" to generate a new config file::
+
+  roundup-admin genconfig <tracker home>/config.ini
+
+and modify the values therein based on the contents of your old config.py.
+In most cases, the names of the config variables are the same.
+
+The ``select_db.py`` file has been replaced by a file in the ``db``
+directory called ``backend_name``. As you might guess, this file contains
+just the name of the backend. To figure what the contents of yours should
+be, use the following table:
+
+  ================================ =========================
+  ``select_db.py`` contents        ``backend_name`` contents
+  ================================ =========================
+  from back_anydbm import ...      anydbm
+  from back_metakit import ...     metakit
+  from back_sqlite import ...      sqlite
+  from back_mysql import ...       mysql
+  from back_postgresql import ...  postgresql
+  ================================ =========================
+
+The ``dbinit.py`` file has been split into two new files,
+``initial_data.py`` and ``schema.py``. The contents of this file are:
+
+``initial_data.py``
+  You don't need one of these as your tracker is already initialised.
+
+``schema.py``
+  Copy the body of the ``def open(name=None)`` function from your old
+  tracker's ``dbinit.py`` file to this file. As the lines you're copying
+  aren't part of a function definition anymore, one level of indentation
+  needs to be removed (remove only the leading four spaces on each
+  line). 
+
+  The first few lines -- those starting with ``from roundup.hyperdb
+  import ...`` and the ``db = Database(config, name)`` line -- don't
+  need to be copied. Neither do the last few lines -- those starting
+  with ``import detectors``, down to ``return db`` inclusive.
+
+You may remove the ``__init__.py`` module from the "detectors" directory as
+it is no longer used.
+
+There's a new way to write extension code for Roundup - the old
+``interfaces.py`` file will be ignored. See the `customisation
+documentation`_ for information about how extensions are now written.
+
+
+0.8.0 Permissions Changes
+-------------------------
+
+The creation of a new item in the user interfaces is now controlled by the
+"Create" Permission. You will need to add an assignment of this Permission
+to your users who are allowed to create items. The most common form of this
+is the following in your ``schema.py`` added just under the current
+assignation of the Edit Permission::
+
+    for cl in 'issue', 'file', 'msg', 'query', 'keyword':
+        p = db.security.getPermission('Create', cl)
+        db.security.addPermissionToRole('User', p)
+
+You will need to explicitly let anonymous users access the web interface so
+that regular users are able to see the login form. Note that almost all
+trackers will need this Permission. The only situation where it's not
+required is in a tracker that uses an HTTP Basic Authenticated front-end.
+It's enabled by adding to your ``schema.py``::
+
+    p = db.security.getPermission('Web Access')
+    db.security.addPermissionToRole('Anonymous', p)
+
+Finally, you will need to enable permission for your users to edit their
+own details by adding the following to ``schema.py``::
+
+    # Users should be able to edit their own details. Note that this
+    # permission is limited to only the situation where the Viewed or
+    # Edited item is their own.
+    def own_record(db, userid, itemid):
+        '''Determine whether the userid matches the item being accessed.'''
+        return userid == itemid
+    p = db.security.addPermission(name='View', klass='user', check=own_record,
+        description="User is allowed to view their own user details")
+    p = db.security.addPermission(name='Edit', klass='user', check=own_record,
+        description="User is allowed to edit their own user details")
+    db.security.addPermissionToRole('User', p)
+
+
+0.8.0 Use of TemplatingUtils
+----------------------------
+
+If you used custom python functions in TemplatingUtils, they must
+be moved from interfaces.py to a new file in the ``extensions`` directory. 
+
+Each Function that should be available through TAL needs to be defined
+as a toplevel function in the newly created file. Furthermore you
+add an inititialization function, that registers the functions with the 
+tracker.
+
+If you find this too tedious, donfu wrote an automatic init function that
+takes an existing TemplatingUtils class, and registers all class methods
+that do not start with an underscore. The following hack should be placed
+in the ``extensions`` directory alongside other extensions::
+
+    class TemplatingUtils:
+         # copy from interfaces.py
+
+    def init(tracker):
+         util = TemplatingUtils()
+
+         def setClient(tu):
+             util.client = tu.client
+             return util
+
+         def execUtil(name):
+             return lambda tu, *args, **kwargs: \
+                     getattr(setClient(tu), name)(*args, **kwargs)
+
+         for name in dir(util):
+             if callable(getattr(util, name)) and not name.startswith('_'):
+                  tracker.registerUtil(name, execUtil(name))
+
+
+0.8.0 Logging Configuration
+---------------------------
+
+See the `administration guide`_ for information about configuring the new
+logging implemented in 0.8.0.
+
+
+Migrating from 0.7.2 to 0.7.3
+=============================
+
+0.7.3 Configuration
+-------------------
+
+If you choose, you may specify the directory from which static files are
+served (those which use the URL component ``@@file``). Currently the
+directory defaults to the ``TEMPLATES`` configuration variable. You may
+define a new variable, ``STATIC_FILES`` which overrides this value for
+static files.
+
+
+Migrating from 0.7.0 to 0.7.2
+=============================
+
+0.7.2 DEFAULT_TIMEZONE is now required
+--------------------------------------
+
+The DEFAULT_TIMEZONE configuration variable is now required. Add the
+following to your tracker's ``config.py`` file::
+
+    # You may specify a different default timezone, for use when users do not
+    # choose their own in their settings.
+    DEFAULT_TIMEZONE = 0            # specify as numeric hour offest
+
+
+Migrating from 0.7.0 to 0.7.1
+=============================
+
+0.7.1 Permission assignments
+----------------------------
+
+If you allow anonymous access to your tracker, you might need to assign
+some additional View (or Edit if your tracker is that open) permissions
+to the "anonymous" user. To do so, find the code in your ``dbinit.py`` that
+says::
+
+    for cl in 'issue', 'file', 'msg', 'query', 'keyword':
+        p = db.security.getPermission('View', cl)
+        db.security.addPermissionToRole('User', p)
+        p = db.security.getPermission('Edit', cl)
+        db.security.addPermissionToRole('User', p)
+    for cl in 'priority', 'status':
+        p = db.security.getPermission('View', cl)
+        db.security.addPermissionToRole('User', p)
+
+Add add a line::
+
+        db.security.addPermissionToRole('Anonymous', p)
+
+next to the existing ``'User'`` lines for the Permissions you wish to
+assign to the anonymous user.
+
+
+Migrating from 0.6 to 0.7
+=========================
+
+0.7.0 Permission assignments
+----------------------------
+
+Due to a change in the rendering of web widgets, permissions are now
+checked on Classes where they previously weren't (this is a good thing).
+
+You will need to add some additional Permission assignments for your
+regular users, or some displays will break. After the following in your 
+tracker's ``dbinit.py``::
+
+    # Assign the access and edit Permissions for issue, file and message
+    # to regular users now
+    for cl in 'issue', 'file', 'msg', 'query', 'keyword':
+        p = db.security.getPermission('View', cl)
+        db.security.addPermissionToRole('User', p)
+        p = db.security.getPermission('Edit', cl)
+        db.security.addPermissionToRole('User', p)
+
+add::
+
+    for cl in 'priority', 'status':
+        p = db.security.getPermission('View', cl)
+        db.security.addPermissionToRole('User', p)
+
+
+0.7.0 Getting the current user id
+---------------------------------
+
+The Database.curuserid attribute has been removed.
+
+Any code referencing this attribute should be replaced with a
+call to Database.getuid().
+
+
+0.7.0 ZRoundup changes
+----------------------
+
+The templates in your tracker's html directory will need updating if you
+wish to use ZRoundup. If you've not modified those files (or some of them),
+you may just copy the new versions from the Roundup source in the
+templates/classic/html directory.
+
+If you have modified the html files, then you'll need to manually edit them
+to change all occurances of special form variables from using the colon ":"
+special character to the at "@" special character. That is, variables such
+as::
+
+  :action :required :template :remove:messages ...
+
+should become::
+
+  @action @required @template @remove at messages ...
+
+Note that ``tal:`` statements are unaffected. So are TAL expression type
+prefixes such as ``python:`` and ``string:``. Please ask on the
+roundup-users mailing list for help if you're unsure.
+
+
+0.7.0 Edit collision detection
+------------------------------
+
+Roundup now detects collisions with editing in the web interface (that is,
+two people editing the same item at the same time).
+
+You must copy the ``_generic.collision.html`` file from Roundup source in
+the ``templates/classic/html`` directory. to your tracker's ``html``
+directory.
+
+
+Migrating from 0.6.x to 0.6.3
+=============================
+
+0.6.3 Configuration
+-------------------
+
+You will need to copy the file::
+
+  templates/classic/detectors/__init__.py
+
+to your tracker's ``detectors`` directory, replacing the one already there.
+This fixes a couple of bugs in that file.
+
+
+
+Migrating from 0.5 to 0.6
+=========================
+
+
+0.6.0 Configuration
+-------------------
+
+Introduced EMAIL_FROM_TAG config variable. This value is inserted into
+the From: line of nosy email. If the sending user is "Foo Bar", the
+From: line is usually::
+
+     "Foo Bar" <issue_tracker at tracker.example>
+
+the EMAIL_FROM_TAG goes inside the "Foo Bar" quotes like so::
+
+     "Foo Bar EMAIL_FROM_TAG" <issue_tracker at tracker.example>
+
+I've altered the mechanism in the detectors __init__.py module so that it
+doesn't cross-import detectors from other trackers (if you run more than one
+in a single roundup-server). This change means that you'll need to copy the
+__init__.py from roundup/templates/classic/detectors/__init__.py to your
+<tracker home>/detectors/__init__.py. Don't worry, the "classic" __init__ is a
+one-size-fits-all, so it'll work even if you've added/removed detectors.
+
+0.6.0 Templating changes
+------------------------
+
+The ``user.item`` template (in the tracker home "templates" directory)
+needs to have the following hidden variable added to its form (between the
+``<form...>`` and ``</form>`` tags::
+
+  <input type="hidden" name=":template" value="item">
+
+
+0.6.0 Form handling changes
+---------------------------
+
+Roundup's form handling capabilities have been significantly expanded. This
+should not affect users of 0.5 installations - but if you find you're
+getting errors from form submissions, please ask for help on the Roundup
+users mailing list:
+
+  http://lists.sourceforge.net/lists/listinfo/roundup-users
+
+See the customisation doc section on `Form Values`__ for documentation of the
+new form variables possible.
+
+__ customizing.html#form-values
+
+
+0.6.0 Multilingual character set support
+----------------------------------------
+
+Added internationalization support. This is done via encoding all data
+stored in roundup database to utf-8 (unicode encoding). To support utf-8 in
+web interface you should add the folowing line to your tracker's html/page
+and html/_generic.help files inside <head> tag::
+  
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+
+Since latin characters in utf-8 have the same codes as in ASCII table, this
+modification is optional for users who use only plain latin characters. 
+
+After this modification, you will be able to see and enter any world
+character via web interface. Data received via mail interface also converted
+to utf-8, however only new messages will be converted. If your roundup
+database contains some of non-ASCII characters in one of 8-bit encoding,
+they will not be visible in new unicode environment. Some of such data (e.g.
+user names, keywords, etc)  can be edited by administrator, the others
+(e.g. messages' contents) is not editable via web interface. Currently there
+is no tool for converting such data, the only solution is to close
+appropriate old issues and create new ones with the same content.
+
+
+0.6.0 User timezone support
+---------------------------
+
+From version 0.6.0 roundup supports displaying of Date data in user' local
+timezone if he/she has provided timezone information. To make it possible
+some modification to tracker's schema and HTML templates are required.
+First you must add string property 'timezone' to user class in dbinit.py
+like this::
+  
+    user = Class(db, "user", 
+                    username=String(),   password=Password(),
+                    address=String(),    realname=String(), 
+                    phone=String(),      organisation=String(),
+                    alternate_addresses=String(),
+                    queries=Multilink('query'), roles=String(),
+                    timezone=String())
+  
+And second - html interface. Add following lines to
+$TRACKER_HOME/html/user.item template::
+  
+     <tr>
+      <th>Timezone</th>
+      <td tal:content="structure context/timezone/field">timezone</td>
+     </tr>
+
+After that all users should be able to provide their timezone information.
+Timezone should be a positive or negative integer - offset from GMT.
+
+After providing timezone, roundup will show all dates values, found in web
+and mail interfaces in local time. It will also accept any Date info in
+local time, convert and store it in GMT.
+
+
+0.6.0 Search page structure
+---------------------------
+
+In order to accomodate query editing the search page has been restructured. If
+you want to provide your users with query editing, you should update your
+search page using the macros detailed in the customisation doc section
+`Searching on categories`__.
+
+__ customizing.html#searching-on-categories
+
+Also, the url field in the query class no longer starts with a '?'. You'll need
+to remove this question mark from the url field to support queries. There's
+a script in the "tools" directory called ``migrate-queries.py`` that should
+automatically change any existing queries for you. As always, make a backup
+of your database before running such a script.
+
+
+0.6.0 Notes for metakit backend users
+-------------------------------------
+
+Roundup 0.6.0 introduced searching on ranges of dates and intervals. To
+support it, some modifications to interval storing routine were made. So if
+your tracker uses metakit backend and your db schema contains intervals
+property, searches on that property will not be accurate for db items that
+was stored before roundup' upgrade. However all new records should be
+searchable on intervals.
+
+It is possible to convert your database to new format: you can export and
+import back all your data (consult "Migrating backends" in "Maintenance"
+documentation). After this operation all your interval properties should
+become searchable.
+
+Users of backends others than metakit should not worry about this issue.
+
+
+Migrating from 0.4.x to 0.5.0
+=============================
+
+This has been a fairly major revision of Roundup:
+
+1. Brand new, much more powerful, flexible, tasty and nutritious templating.
+   Unfortunately, this means all your current templates are useless. Hopefully
+   the new documentation and examples will be enough to help you make the
+   transition. Please don't hesitate to ask on roundup-users for help (or
+   complete conversions if you're completely stuck)!
+2. The database backed got a lot more flexible, allowing Metakit and SQL
+   databases! The only decent SQL database implemented at present is sqlite,
+   but others shouldn't be a whole lot more work.
+3. A brand new, highly flexible and much more robust security system including
+   a system of Permissions, Roles and Role assignments to users. You may now
+   define your own Permissions that may be checked in CGI transactions.
+4. Journalling has been made less storage-hungry, so has been turned on
+   by default *except* for author, recipient and nosy link/unlink events. You
+   are advised to turn it off in your trackers too.
+5. We've changed the terminology from "instance" to "tracker", to ease the
+   learning curve/impact for new users.
+6. Because of the above changes, the tracker configuration has seen some
+   major changes. See below for the details.
+
+Please, **back up your database** before you start the migration process. This
+is as simple as copying the "db" directory and all its contents from your
+tracker to somewhere safe.
+
+
+0.5.0 Configuration
+-------------------
+
+First up, rename your ``instance_config.py`` file to just ``config.py``.
+
+Then edit your tracker's ``__init__.py`` module. It'll currently look
+like this::
+
+ from instance_config import *
+ try:
+     from dbinit import *
+ except ImportError:
+     pass # in installdir (probably :)
+ from interfaces import *
+
+and it needs to be::
+
+ import config
+ from dbinit import open, init
+ from interfaces import Client, MailGW
+
+Due to the new templating having a top-level ``page`` that defines links for
+searching, indexes, adding items etc, the following variables are no longer
+used:
+
+- HEADER_INDEX_LINKS
+- HEADER_ADD_LINKS
+- HEADER_SEARCH_LINKS
+- SEARCH_FILTERS
+- DEFAULT_INDEX
+- UNASSIGNED_INDEX
+- USER_INDEX
+- ISSUE_FILTER
+
+The new security implementation will require additions to the dbinit module,
+but also removes the need for the following tracker config variables:
+
+- ANONYMOUS_ACCESS
+- ANONYMOUS_REGISTER
+
+but requires two new variables which define the Roles assigned to users who
+register through the web and e-mail interfaces:
+
+- NEW_WEB_USER_ROLES
+- NEW_EMAIL_USER_ROLES
+
+in both cases, 'User' is a good initial setting. To emulate
+``ANONYMOUS_ACCESS='deny'``, remove all "View" Permissions from the
+"Anonymous" Role. To emulate ``ANONYMOUS_REGISTER='deny'``, remove the "Web
+Registration" and/or the "Email Registration" Permission from the "Anonymous"
+Role. See the section on customising security in the `customisation
+documentation`_ for more information.
+
+Finally, the following config variables have been renamed to make more sense:
+
+- INSTANCE_HOME -> TRACKER_HOME
+- INSTANCE_NAME -> TRACKER_NAME
+- ISSUE_TRACKER_WEB -> TRACKER_WEB
+- ISSUE_TRACKER_EMAIL -> TRACKER_EMAIL
+
+
+0.5.0 Schema Specification
+--------------------------
+
+0.5.0 Database backend changes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Your select_db module in your tracker has changed a fair bit. Where it used
+to contain::
+
+ # WARNING: DO NOT EDIT THIS FILE!!!
+ from roundup.backends.back_anydbm import Database
+
+it must now contain::
+
+ # WARNING: DO NOT EDIT THIS FILE!!!
+ from roundup.backends.back_anydbm import Database, Class, FileClass, IssueClass
+
+Yes, I realise the irony of the "DO NOT EDIT THIS FILE" statement :)
+Note the addition of the Class, FileClass, IssueClass imports. These are very
+important, as they're going to make the next change work too. You now need to
+modify the top of the dbinit module in your tracker from::
+
+ import instance_config
+ from roundup import roundupdb
+ from select_db import Database
+
+ from roundup.roundupdb import Class, FileClass
+
+ class Database(roundupdb.Database, select_db.Database):
+     ''' Creates a hybrid database from:
+          . the selected database back-end from select_db
+          . the roundup extensions from roundupdb
+     '''
+     pass
+
+ class IssueClass(roundupdb.IssueClass):
+     ''' issues need the email information
+     '''
+     pass
+
+to::
+
+ import config
+ from select_db import Database, Class, FileClass, IssueClass
+
+Yes, remove the Database and IssueClass definitions and those other imports.
+They're not needed any more!
+
+Look for places in dbinit.py where ``instance_config`` is used too, and
+rename them ``config``.
+
+
+0.5.0 Journalling changes
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Journalling has been optimised for storage. Journalling of links has been
+turned back on by default. If your tracker has a large user base, you may wish
+to turn off journalling of nosy list, message author and message recipient
+link and unlink events. You do this by adding ``do_journal='no'`` to the Class
+initialisation in your dbinit. For example, your *msg* class initialisation
+probably looks like this::
+
+    msg = FileClass(db, "msg",
+                    author=Link("user"), recipients=Multilink("user"),
+                    date=Date(),         summary=String(),
+                    files=Multilink("file"),
+                    messageid=String(),  inreplyto=String())
+
+to turn off journalling of author and recipient link events, add
+``do_journal='no'`` to the ``author=Link("user")`` part of the statement,
+like so::
+
+    msg = FileClass(db, "msg",
+                    author=Link("user", do_journal='no'),
+                    recipients=Multilink("user", do_journal='no'),
+                    date=Date(),         summary=String(),
+                    files=Multilink("file"),
+                    messageid=String(),  inreplyto=String())
+
+Nosy list link event journalling is actually turned off by default now. If you
+want to turn it on, change to your issue class' nosy list, change its
+definition from::
+
+    issue = IssueClass(db, "issue",
+                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    priority=Link("priority"), status=Link("status"))
+
+to::
+
+    issue = IssueClass(db, "issue", nosy=Multilink("user", do_journal='yes'),
+                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    priority=Link("priority"), status=Link("status"))
+
+noting that your definition of the nosy Multilink will override the normal one.
+
+
+0.5.0 User schema changes
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Users have two more properties, "queries" and "roles". You'll have something
+like this in your dbinit module now::
+
+    user = Class(db, "user",
+                    username=String(),   password=Password(),
+                    address=String(),    realname=String(),
+                    phone=String(),      organisation=String(),
+                    alternate_addresses=String())
+    user.setkey("username")
+
+and you'll need to add the new properties and the new "query" class to it
+like so::
+
+    query = Class(db, "query",
+                    klass=String(),     name=String(),
+                    url=String())
+    query.setkey("name")
+
+    # Note: roles is a comma-separated string of Role names
+    user = Class(db, "user",
+                    username=String(),   password=Password(),
+                    address=String(),    realname=String(),
+                    phone=String(),      organisation=String(),
+                    alternate_addresses=String(),
+                    queries=Multilink('query'), roles=String())
+    user.setkey("username")
+
+The "queries" property is used to store off the user's favourite database
+queries. The "roles" property is explained below in `0.5.0 Security
+Settings`_.
+
+
+0.5.0 Security Settings
+~~~~~~~~~~~~~~~~~~~~~~~
+
+See the `security documentation`_ for an explanation of how the new security
+system works. In a nutshell though, the security is handled as a four step
+process:
+
+1. Permissions are defined as having a name and optionally a hyperdb class
+   they're specific to,
+2. Roles are defined that have one or more Permissions,
+3. Users are assigned Roles in their "roles" property, and finally
+4. Roundup checks that users have appropriate Permissions at appropriate times
+   (like editing issues).
+
+Your tracker dbinit module's *open* function now has to define any
+Permissions that are specific to your tracker, and also the assignment
+of Permissions to Roles. At the moment, your open function
+ends with::
+
+    import detectors
+    detectors.init(db)
+
+    return db
+
+and what we need to do is insert some commands that will set up the security
+parameters. Right above the ``import detectors`` line, you'll want to insert
+these lines::
+
+    #
+    # SECURITY SETTINGS
+    #
+    # new permissions for this schema
+    for cl in 'issue', 'file', 'msg', 'user':
+        db.security.addPermission(name="Edit", klass=cl,
+            description="User is allowed to edit "+cl)
+        db.security.addPermission(name="View", klass=cl,
+            description="User is allowed to access "+cl)
+
+    # Assign the access and edit permissions for issue, file and message
+    # to regular users now
+    for cl in 'issue', 'file', 'msg':
+        p = db.security.getPermission('View', cl)
+        db.security.addPermissionToRole('User', p)
+        p = db.security.getPermission('Edit', cl)
+        db.security.addPermissionToRole('User', p)
+    # and give the regular users access to the web and email interface
+    p = db.security.getPermission('Web Access')
+    db.security.addPermissionToRole('User', p)
+    p = db.security.getPermission('Email Access')
+    db.security.addPermissionToRole('User', p)
+
+    # May users view other user information? Comment these lines out
+    # if you don't want them to
+    p = db.security.getPermission('View', 'user')
+    db.security.addPermissionToRole('User', p)
+
+    # Assign the appropriate permissions to the anonymous user's Anonymous
+    # Role. Choices here are:
+    # - Allow anonymous users to register through the web
+    p = db.security.getPermission('Web Registration')
+    db.security.addPermissionToRole('Anonymous', p)
+    # - Allow anonymous (new) users to register through the email gateway
+    p = db.security.getPermission('Email Registration')
+    db.security.addPermissionToRole('Anonymous', p)
+    # - Allow anonymous users access to the "issue" class of data
+    #   Note: this also grants access to related information like files,
+    #         messages, statuses etc that are linked to issues
+    #p = db.security.getPermission('View', 'issue')
+    #db.security.addPermissionToRole('Anonymous', p)
+    # - Allow anonymous users access to edit the "issue" class of data
+    #   Note: this also grants access to create related information like
+    #         files and messages etc that are linked to issues
+    #p = db.security.getPermission('Edit', 'issue')
+    #db.security.addPermissionToRole('Anonymous', p)
+
+    # oh, g'wan, let anonymous access the web interface too
+    p = db.security.getPermission('Web Access')
+    db.security.addPermissionToRole('Anonymous', p)
+
+Note in the comments there the places where you might change the permissions
+to restrict users or grant users more access. If you've created additional
+classes that users should be able to edit and view, then you should add them
+to the "new permissions for this schema" section at the start of the security
+block. Then add them to the "Assign the access and edit permissions" section
+too, so people actually have the new Permission you've created.
+
+One final change is needed that finishes off the security system's
+initialisation. We need to add a call to ``db.post_init()`` at the end of the
+dbinit open() function. Add it like this::
+
+    import detectors
+    detectors.init(db)
+
+    # schema is set up - run any post-initialisation
+    db.post_init()
+    return db
+
+You may verify the setup of Permissions and Roles using the new
+"``roundup-admin security``" command.
+
+
+0.5.0 User changes
+~~~~~~~~~~~~~~~~~~
+
+To support all those schema changes, you'll need to massage your user database
+a little too, to:
+
+1. make sure there's an "anonymous" user - this user is mandatory now and is
+   the one that unknown users are logged in as.
+2. make sure all users have at least one Role.
+
+If you don't have the "anonymous" user, create it now with the command::
+
+  roundup-admin create user username=anonymous roles=Anonymous
+
+making sure the capitalisation is the same as above. Once you've done that,
+you'll need to set the roles property on all users to a reasonable default.
+The admin user should get "Admin", the anonymous user "Anonymous"
+and all other users "User". The ``fixroles.py`` script in the tools directory
+will do this. Run it like so (where python is your python 2+ binary)::
+
+  python tools/fixroles.py -i <tracker home> fixroles
+
+
+
+0.5.0 CGI interface changes
+---------------------------
+
+The CGI interface code was completely reorganised and largely rewritten. The
+end result is that this section of your tracker interfaces module will need
+changing from::
+
+ from roundup import cgi_client, mailgw
+ from roundup.i18n import _
+ 
+ class Client(cgi_client.Client):
+     ''' derives basic CGI implementation from the standard module,
+         with any specific extensions
+     '''
+     pass
+
+to::
+
+ from roundup import mailgw
+ from roundup.cgi import client
+ 
+ class Client(client.Client): 
+     ''' derives basic CGI implementation from the standard module,
+         with any specific extensions
+     '''
+     pass
+
+You will also need to install the new version of roundup.cgi from the source
+cgi-bin directory if you're using it.
+
+
+0.5.0 HTML templating
+---------------------
+
+You'll want to make a backup of your current tracker html directory. You
+should then copy the html directory from the Roundup source "classic" template
+and modify it according to your local schema changes.
+
+If you need help with the new templating system, please ask questions on the
+roundup-users mailing list (available through the roundup project page on
+sourceforge, http://roundup.sf.net/)
+
+
+0.5.0 Detectors
+---------------
+
+The nosy reactor has been updated to handle the tracker not having an
+"assignedto" property on issues. You may want to copy it into your tracker's
+detectors directory. Chances are you've already fixed it though :)
+
+
+Migrating from 0.4.1 to 0.4.2
+=============================
+
+0.4.2 Configuration
+-------------------
+The USER_INDEX definition introduced in 0.4.1 was too restrictive in its
+allowing replacement of 'assignedto' with the user's userid. Users must change
+the None value of 'assignedto' to 'CURRENT USER' (the string, in quotes) for
+the replacement behaviour to occur now.
+
+The new configuration variables are:
+
+- EMAIL_KEEP_QUOTED_TEXT 
+- EMAIL_LEAVE_BODY_UNCHANGED
+- ADD_RECIPIENTS_TO_NOSY
+
+See the sample configuration files in::
+
+ <roundup source>/roundup/templates/classic/instance_config.py
+
+and::
+
+ <roundup source>/roundup/templates/extended/instance_config.py
+
+and the `customisation documentation`_ for information on how they're used.
+
+
+0.4.2 Changes to detectors
+--------------------------
+You will need to copy the detectors from the distribution into your instance
+home "detectors" directory. If you used the classic schema, the detectors
+are in::
+
+ <roundup source>/roundup/templates/classic/detectors/
+
+If you used the extended schema, the detectors are in::
+
+ <roundup source>/roundup/templates/extended/detectors/
+
+The change means that schema-specific code has been removed from the
+mail gateway and cgi interface and made into auditors:
+
+- nosyreactor.py has now got an updatenosy auditor which updates the nosy
+  list with author, recipient and assignedto information.
+- statusauditor.py makes the unread or resolved -> chatting changes and
+  presets the status of an issue to unread.
+
+There's also a bug or two fixed in the nosyreactor code.
+
+0.4.2 HTML templating changes
+-----------------------------
+The link() htmltemplate function now has a "showid" option for links and
+multilinks. When true, it only displays the linked item id as the anchor
+text. The link value is displayed as a tooltip using the title anchor
+attribute. To use in eg. the superseder field, have something like this::
+
+   <td>
+    <display call="field('superseder', showid=1)">
+    <display call="classhelp('issue', 'id,title', label='list', width=500)">
+    <property name="superseder">
+     <br>View: <display call="link('superseder', showid=1)">
+    </property>
+   </td>
+
+The stylesheets have been cleaned up too. You may want to use the newer
+versions in::
+
+ <roundup source>/roundup/templates/<template>/html/default.css
+
+
+
+Migrating from 0.4.0 to 0.4.1
+=============================
+
+0.4.1 Files storage
+-------------------
+
+Messages and files from newly created issues will be put into subdierectories
+in thousands e.g. msg123 will be put into files/msg/0/msg123, file2003
+will go into files/file/2/file2003. Previous messages are still found, but
+could be put into this structure.
+
+0.4.1 Configuration
+-------------------
+
+To allow more fine-grained access control, the variable used to check
+permission to auto-register users in the mail gateway is now called
+ANONYMOUS_REGISTER_MAIL rather than overloading ANONYMOUS_REGISTER. If the
+variable doesn't exist, then ANONYMOUS_REGISTER is tested as before.
+
+Configuring the links in the web header is now easier too. The following
+variables have been added to the classic instance_config.py::
+
+  HEADER_INDEX_LINKS   - defines the "index" links to be made available
+  HEADER_ADD_LINKS     - defines the "add" links
+  DEFAULT_INDEX        - specifies the index view for DEFAULT
+  UNASSIGNED_INDEX     - specifies the index view for UNASSIGNED
+  USER_INDEX           - specifies the index view for USER
+
+See the <roundup source>/roundup/templates/classic/instance_config.py for more
+information - including how the variables are to be set up. Most users will
+just be able to copy the variables from the source to their instance home. If
+you've modified the header by changing the source of the interfaces.py file in
+the instance home, you'll need to remove that customisation and move it into
+the appropriate variables in instance_config.py.
+
+The extended schema has similar variables added too - see the source for more
+info.
+
+0.4.1 Alternate E-Mail Addresses
+--------------------------------
+
+If you add the property "alternate_addresses" to your user class, your users
+will be able to register alternate email addresses that they may use to
+communicate with roundup as. All email from roundup will continue to be sent
+to their primary address.
+
+If you have not edited the dbinit.py file in your instance home directory,
+you may simply copy the new dbinit.py file from the core code. If you used
+the classic schema, the interfaces file is in::
+
+ <roundup source>/roundup/templates/classic/dbinit.py
+
+If you used the extended schema, the file is in::
+
+ <roundup source>/roundup/templates/extended/dbinit.py 
+
+If you have modified your dbinit.py file, you need to edit the dbinit.py
+file in your instance home directory. Find the lines which define the user
+class::
+
+    user = Class(db, "msg",
+                    username=String(),   password=Password(),
+                    address=String(),    realname=String(), 
+                    phone=String(),      organisation=String(),
+                    alternate_addresses=String())
+
+You will also want to add the property to the user's details page. The
+template for this is the "user.item" file in your instance home "html"
+directory. Similar to above, you may copy the file from the roundup source if
+you haven't modified it. Otherwise, add the following to the template::
+
+   <display call="multiline('alternate_addresses')">
+
+with appropriate labelling etc. See the standard template for an idea.
+
+
+
+Migrating from 0.3.x to 0.4.0
+=============================
+
+0.4.0 Message-ID and In-Reply-To addition
+-----------------------------------------
+0.4.0 adds the tracking of messages by message-id and allows threading
+using in-reply-to. Most e-mail clients support threading using this
+feature, and we hope to add support for it to the web gateway. If you
+have not edited the dbinit.py file in your instance home directory, you may
+simply copy the new dbinit.py file from the core code. If you used the
+classic schema, the interfaces file is in::
+
+ <roundup source>/roundup/templates/classic/dbinit.py
+
+If you used the extended schema, the file is in::
+
+ <roundup source>/roundup/templates/extended/dbinit.py 
+
+If you have modified your dbinit.py file, you need to edit the dbinit.py
+file in your instance home directory. Find the lines which define the msg
+class::
+
+    msg = FileClass(db, "msg",
+                    author=Link("user"), recipients=Multilink("user"),
+                    date=Date(),         summary=String(),
+                    files=Multilink("file"))
+
+and add the messageid and inreplyto properties like so::
+
+    msg = FileClass(db, "msg",
+                    author=Link("user"), recipients=Multilink("user"),
+                    date=Date(),         summary=String(),
+                    files=Multilink("file"),
+                    messageid=String(),  inreplyto=String())
+
+Also, configuration is being cleaned up. This means that your dbinit.py will
+also need to be changed in the open function. If you haven't changed your
+dbinit.py, the above copy will be enough. If you have, you'll need to change
+the line (round line 50)::
+
+    db = Database(instance_config.DATABASE, name)
+
+to::
+
+    db = Database(instance_config, name)
+
+
+0.4.0 Configuration
+--------------------
+``TRACKER_NAME`` and ``EMAIL_SIGNATURE_POSITION`` have been added to the
+instance_config.py. The simplest solution is to copy the default values
+from template in the core source.
+
+The mail gateway now checks ``ANONYMOUS_REGISTER`` to see if unknown users
+are to be automatically registered with the tracker. If it is set to "deny"
+then unknown users will not have access. If it is set to "allow" they will be
+automatically registered with the tracker.
+
+
+0.4.0 CGI script roundup.cgi
+----------------------------
+The CGI script has been updated with some features and a bugfix, so you should
+copy it from the roundup cgi-bin source directory again. Make sure you update
+the ROUNDUP_INSTANCE_HOMES after the copy.
+
+
+0.4.0 Nosy reactor
+------------------
+The nosy reactor has also changed - copy the nosyreactor.py file from the core
+source::
+
+   <roundup source>/roundup/templates/<template>/detectors/nosyreactor.py
+
+to your instance home "detectors" directory.
+
+
+0.4.0 HTML templating
+---------------------
+The field() function was incorrectly implemented - links and multilinks now
+display as text fields when rendered using field(). To display a menu (drop-
+down or select box) you need to use the menu() function.
+
+
+
+Migrating from 0.2.x to 0.3.x
+=============================
+
+0.3.x Cookie Authentication changes
+-----------------------------------
+0.3.0 introduces cookie authentication - you will need to copy the
+interfaces.py file from the roundup source to your instance home to enable
+authentication. If you used the classic schema, the interfaces file is in::
+
+ <roundup source>/roundup/templates/classic/interfaces.py
+
+If you used the extended schema, the file is in::
+
+ <roundup source>/roundup/templates/extended/interfaces.py
+
+If you have modified your interfaces.Client class, you will need to take
+note of the login/logout functionality provided in roundup.cgi_client.Client
+(classic schema) or roundup.cgi_client.ExtendedClient (extended schema) and
+modify your instance code apropriately.
+
+
+0.3.x Password encoding
+-----------------------
+This release also introduces encoding of passwords in the database. If you
+have not edited the dbinit.py file in your instance home directory, you may
+simply copy the new dbinit.py file from the core code. If you used the
+classic schema, the interfaces file is in::
+
+ <roundup source>/roundup/templates/classic/dbinit.py
+
+If you used the extended schema, the file is in::
+
+ <roundup source>/roundup/templates/extended/dbinit.py
+
+
+If you have modified your dbinit.py file, you may use encoded passwords:
+
+1. Edit the dbinit.py file in your instance home directory
+   a. At the first code line of the open() function::
+
+       from roundup.hyperdb import String, Date, Link, Multilink
+
+      alter to include Password, as so::
+
+       from roundup.hyperdb import String, Password, Date, Link, Multilink
+
+   b. Where the password property is defined (around line 66)::
+
+       user = Class(db, "user", 
+                       username=String(),   password=String(),
+                       address=String(),    realname=String(), 
+                       phone=String(),      organisation=String())
+       user.setkey("username")
+
+      alter the "password=String()" to "password=Password()"::
+
+       user = Class(db, "user", 
+                       username=String(),   password=Password(),
+                       address=String(),    realname=String(), 
+                       phone=String(),      organisation=String())
+       user.setkey("username")
+
+2. Any existing passwords in the database will remain cleartext until they
+   are edited. It is recommended that at a minimum the admin password be
+   changed immediately::
+
+      roundup-admin -i <instance home> set user1 password=<new password>
+
+
+0.3.x Configuration
+-------------------
+FILTER_POSITION, ANONYMOUS_ACCESS, ANONYMOUS_REGISTER have been added to
+the instance_config.py. Simplest solution is to copy the default values from
+template in the core source.
+
+MESSAGES_TO_AUTHOR has been added to the IssueClass in dbinit.py. Set to 'yes'
+to send nosy messages to the author. Default behaviour is to not send nosy
+messages to the author. You will need to add MESSAGES_TO_AUTHOR to your
+dbinit.py in your instance home.
+
+
+0.3.x CGI script roundup.cgi
+----------------------------
+There have been some structural changes to the roundup.cgi script - you will
+need to install it again from the cgi-bin directory of the source
+distribution. Make sure you update the ROUNDUP_INSTANCE_HOMES after the
+copy.
+
+
+.. _`customisation documentation`: customizing.html
+.. _`security documentation`: security.html
+.. _`administration guide`: admin_guide.html

Added: tracker/vendor/roundup/current/doc/user_guide.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/user_guide.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,787 @@
+==========
+User Guide
+==========
+
+:Version: $Revision: 1.32 $
+
+.. contents::
+
+.. hint::
+   This document will refer to *issues* as the primary store of
+   information in the tracker. This is the default of the classic template,
+   but may vary in any given installation.
+
+
+Your Tracker in a Nutshell
+==========================
+
+Your tracker holds information about issues in bundles we call *items*.
+An item may be an *issue* (a bug or feature request) or a *user*. The
+issue-ness or user-ness is called the item's *class*. So, for bug
+reports and features, the class is "issue", and for users the class is
+"user".
+
+Each item in the tracker has an id number that identifies it along with
+its item class. To identify a particular issue or user, we combine the
+class with the number to create a unique label, so that user 1 (who,
+incidentally, is *always* the "admin" user) is referred to as "user1".
+Issue number 315 is referred to as "issue315". We call that label the
+item's *designator*.
+
+Items in the database are never deleted, they're just "retired". You
+can still refer to them by ID - hence removing an item won't break
+references to the item. It's just that the item won't appear in any
+listings.
+
+
+Accessing the Tracker
+---------------------
+
+You may access your tracker through one of three ways:
+
+1. through the `web interface`_,
+2. through the `e-mail gateway`_, or
+3. using the `command line tool`_.
+
+The last is usually only used by administrators. Most users will use the
+web and e-mail interfaces. All three are explained below.
+
+
+Issue life cycles in Roundup
+----------------------------
+
+New issues may be submitted via the web or e-mail.
+
+By default, the issue will have the status "unread". If another message
+is received for the issue, its status will change to "chatting". 
+
+The "home" page for a tracker will generally display all issues which
+are not "resolved".
+
+If an issue is closed, and a new message is received then it'll be
+reopened to the state of "chatting".
+
+
+Entering values in your Tracker
+-------------------------------
+
+All interfaces to your tracker use the same format for entering values.
+This means the web interface for entering a new issue, the web interface
+for searching issues, the e-mail interface and even the command-line
+administration tool.
+
+
+String and Numeric properties
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These fields just take a simple text value, like ``It's broken``.
+
+
+Boolean properties
+~~~~~~~~~~~~~~~~~~
+
+These fields take a value which indicates "yes"/"no", "true"/"false",
+"1"/"0" or "on"/"off".
+
+
+Constrained (link and multilink) properties
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Fields like "Assigned To" and "Topics" hold references to items in other
+classes ("user" and "keyword" in those two cases.)
+
+Sometimes, the selection is done through a menu, like in the "Assigned
+To" field.
+
+Where the input is not a simple menu selection, we use a comma-separated
+list of values to indicated which values of "user" or "keyword" are
+interesting. The values may be either numeric ids or the names of items.
+The special value "-1" may be used to match items where the property is
+not set. For example, the following searches on the issues:
+
+``assignedto=richard,george``
+  match issues which are assigned to richard or george.
+``assignedto=-1``
+  match issues that are not assigned to a user.
+``assignedto=2,3,40``
+  match issues that are assigned to users 2, 3 or 40.
+``topic=user interface``
+  match issues with the keyword "user interface" in their topic list
+``topic=web interface,e-mail interface``
+  match issues with the keyword "web interface" or "e-mail interface" in
+  their topic list
+``topic=-1``
+  match issues with no topics set
+
+
+Date properties
+~~~~~~~~~~~~~~~
+
+Date-and-time stamps are specified with the date in
+international standard format (``yyyy-mm-dd``) joined to the time
+(``hh:mm:ss``) by a period ``.``.  Dates in this form can be easily
+compared and are fairly readable when printed.  An example of a valid
+stamp is ``2000-06-24.13:03:59``. We'll call this the "full date
+format".  When Timestamp objects are printed as strings, they appear in
+the full date format.
+
+For user input, some partial forms are also permitted: the whole time or
+just the seconds may be omitted; and the whole date may be omitted or
+just the year may be omitted.  If the time is given, the time is
+interpreted in the user's local time zone. The Date constructor takes
+care of these conversions. In the following examples, suppose that
+``yyyy`` is the current year, ``mm`` is the current month, and ``dd`` is
+the current day of the month.
+
+-   "2000-04-17" means <Date 2000-04-17.00:00:00>
+-   "01-25" means <Date yyyy-01-25.00:00:00>
+-   "2000-04-17.03:45" means <Date 2000-04-17.08:45:00>
+-   "08-13.22:13" means <Date yyyy-08-14.03:13:00>
+-   "11-07.09:32:43" means <Date yyyy-11-07.14:32:43>
+-   "14:25" means
+-   <Date yyyy-mm-dd.19:25:00>
+-   "8:47:11" means
+-   <Date yyyy-mm-dd.13:47:11>
+-   the special date "." means "right now"
+
+
+When searching, a plain date entered as a search field will match that date
+exactly in the database.  We may also accept ranges of dates. You can
+specify range of dates in one of two formats:
+
+1. English syntax::
+
+    [From <value>][To <value>]
+
+   Keywords "From" and "To" are case insensitive. Keyword "From" is
+   optional.
+
+2. "Geek" syntax::
+
+    [<value>];[<value>]
+
+Either first or second ``<value>`` can be omitted in both syntaxes.
+
+For example, if you enter string "from 9:00" to "Creation date" field,
+roundup will find  all issues, that were created today since 9 AM.
+
+The ``<value>`` may also be an interval, as described in the next section.
+Searching of "-2m; -1m" on activity field gives you issues which were
+active between period of time since 2 months up-till month ago.
+
+Other possible examples (consider local time is 2003-03-08.22:07:48):
+
+- "from 2-12 to 4-2" means
+  <Range from 2003-02-12.00:00:00 to 2003-04-02.00:00:00>
+- "FROM 18:00 TO +2m" means
+  <Range from 2003-03-08.18:00:00 to 2003-05-08.20:07:48>
+- "12:00;" means
+  <Range from 2003-03-08.12:00:00 to None>
+- "tO +3d" means
+  <Range from None to 2003-03-11.20:07:48>
+- "2002-11-10; 2002-12-12" means
+  <Range from 2002-11-10.00:00:00 to 2002-12-12.00:00:00>
+- "; 20:00 +1d" means
+  <Range from None to 2003-03-09.20:00:00>
+- "2003" means
+  <Range from 2003-01-01.00:00:00 to 2003-12-31.23:59:59>
+- "2003-04" means
+  <Range from 2003-04-01.00:00:00 to 2003-04-30.23:59:59>
+    
+
+Interval properties
+~~~~~~~~~~~~~~~~~~~
+
+Date intervals are specified using the suffixes "y", "m", and "d".  The
+suffix "w" (for "week") means 7 days. Time intervals are specified in
+hh:mm:ss format (the seconds may be omitted, but the hours and minutes
+may not).
+
+-   "3y" means three years
+-   "2y 1m" means two years and one month
+-   "1m 25d" means one month and 25 days
+-   "2w 3d" means two weeks and three days
+-   "1d 2:50" means one day, two hours, and 50 minutes
+-   "14:00" means 14 hours
+-   "0:04:33" means four minutes and 33 seconds
+
+
+Simple support for collision detection
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Item edit pages remember when the item was last edited. When a form is
+submitted, the user will be informed if someone else has edited the item
+at the same time they tried to.
+
+
+Web Interface
+=============
+
+.. note::
+   This document contains screenshots of the default look and feel.
+   Your site may have a slightly (or very) different look, but the
+   functionality will be very similar, and the concepts still hold.
+
+The web interface is broken up into the following parts:
+
+1. `lists of items`_,
+2. `display, edit or entry of an item`_, and
+3. `searching page`_.
+
+
+Lists of Items
+--------------
+
+The first thing you'll see when you log into Roundup will be a list of
+open (ie. not resolved) issues. This list has been generated by a bunch
+of controls `under the covers`_ but for now, you can see something like:
+
+.. img: images/index_logged_out.png
+
+The screen is divided up into three sections:
+
+.. img: images/page_layout.png
+
+you may either register or log in. Registration takes you to:
+
+.. img: images/registration.png
+
+Once you're logged in, the screen changes slightly to:
+
+.. img: images/index_logged_in.png
+
+Note that the sidebar menu has changed slightly, so you can now get to
+your "My Details" page:
+
+.. img: images/my_details.png
+
+Note the new information on this page - the history.
+
+
+Display, edit or entry of an item
+---------------------------------
+
+Create a new issue with "create new" under the issue subheading. This
+will take you to:
+
+.. img: images/new_issue.png
+
+The `nosy list`_ is explained below. Enter some information and click
+"submit new entry" and you'll be rewarded with:
+
+.. img: images/new_issue_created.png
+
+or, if you don't enter all the required information (or some other error
+occurs) you'll get something like:
+
+.. img: images/new_issue_error.png
+
+
+Searching Page
+--------------
+
+See `entering values in your tracker`_ for an explanation of what you
+may type into the search form.
+
+
+Saving queries
+~~~~~~~~~~~~~~
+
+You may save queries in the tracker by giving the query a name. Each user
+may only have one query with a given name - if a subsequent search is
+performed with the same query name supplied, then it will edit the
+existing query of the same name.
+
+Queries may be marked as "private". These queries are only visible to the
+user that created them. If they're not marked "private" then all other
+users may include the query in their list of "Your Queries". Marking it as
+private at a later date does not affect users already using the query, nor
+does deleting the query.
+
+If a user subsequently creates or edits a public query, a new personal
+version of that query is made, with the same editing rules as described
+above.
+
+
+Under the covers
+~~~~~~~~~~~~~~~~
+
+The searching page converts your selections into the following
+arguments:
+
+============ =============================================================
+Argument     Description
+============ =============================================================
+ at sort        sort by prop name, optionally preceeded with '-' to give
+             descending or nothing for ascending sorting.
+ at group       group by prop name, optionally preceeded with '-' or to sort
+             in descending or nothing for ascending order.
+ at columns     selects the columns that should be displayed. Default is
+             all.                     
+ at filter      indicates which properties are being used in filtering.
+             Default is none.
+propname     selects the values the item properties given by propname must
+             have (very basic search/filter).
+ at search_text performs a full-text search (message bodies, issue titles,
+             etc)
+============ =============================================================
+
+You may manually write URLS that contain these arguments, like so
+(whitespace has been added for clarity)::
+
+    /issue?status=unread,in-progress,resolved&
+        topic=security,ui&
+        @group=priority&
+        @sort=-activity&
+        @filters=status,topic&
+        @columns=title,status,fixer
+
+
+Access Controls
+---------------
+
+User access is controlled through Permissions. These are are grouped
+into Roles, and users have a comma-separated list of Roles assigned to
+them.
+
+Permissions divide access controls up into answering questions like:
+
+- may the user edit issues ("Edit", "issue")
+- is the user allowed to use the web interface ("Web Access")
+- may the user edit other user's Roles through the web ("Web Roles")
+
+Any number of new Permissions and Roles may be created as described in
+the customisation documentation. Examples of new access controls are:
+
+- only managers may sign off issues as complete
+- don't give users who register through e-mail web access
+- let some users edit the details of all users
+
+
+E-Mail Gateway
+==============
+
+Roundup trackers may be used to facilitate e-mail conversations around
+issues. The "nosy" list attached to each issue indicates the users who
+should receive e-mail when messages are added to the issue.
+
+When e-mail comes into a tracker that identifies an issue in the subject
+line, the content of the e-mail is attached to the issue.
+
+You may even create new issues from e-mail messages.
+
+E-mail sent to a tracker is examined for several pieces of information:
+
+1. `subject-line information`_ identifying the purpose of the e-mail
+2. `sender identification`_ using the sender of the message
+3. `e-mail message content`_ which is to be extracted
+4. e-mail attachments which should be associated with the message
+
+
+Subject-line information
+------------------------
+
+The subject line of the incoming message is examined to find one of:
+
+1. the item that the message is responding to,
+2. the type of item the message should create, or
+3. we default the item class and try some trickiness
+
+If the subject line contains a prefix in ``[square brackets]`` then
+we're looking at case 1 or 2 above. Any "re:" or "fwd:" prefixes are
+stripped off the subject line before we start looking for real
+information.
+
+If an item designator (class name and id number, for example
+``issue123``) is found there, a new "msg" item is added to the
+"messages" property for that item, and any new "file" items are added to
+the "files" property for the item.
+
+If just an item class name is found there, we attempt to create a new
+item of that class with its "messages" property initialized to contain
+the new "msg" item and its "files" property initialized to contain any
+new "file" items.
+
+The third case above - where no ``[information]`` is provided, the
+tracker's ``MAIL_DEFAULT_CLASS`` configuration variable defines what
+class of item the message relates to. We try to match the subject line
+to an existing item of the default class, and if there's a match, the
+message is related to that matched item. If not, then a new item of the
+default class is created.
+
+
+Setting Properties
+~~~~~~~~~~~~~~~~~~
+
+The e-mail interface also provides a simple way to set properties on
+items. At the end of the subject line, propname=value pairs can be
+specified in square brackets, using the same conventions as for the
+roundup set shell command.
+
+For example,
+
+- setting the priority of an issue::
+
+   Subject: Re: [issue1] the coffee machine is broken! [priority=urgent]
+
+- adding yourself to a nosy list::
+
+   Subject: Re: [issue2] we're out of widgets [nosy=+richard]
+
+- setting the nosy list to just you and cliff::
+
+   Subject: Re: [issue2] we're out of widgets [nosy=richard,cliff]
+
+- removing yourself from a nosy list and setting the priority::
+
+   Subject: Re: [issue2] we're out of widgets [nosy=-richard;priority=bug]
+
+In all cases, the message relates to issue 2. The ``Re:`` prefix is
+stripped off.
+
+
+Automatic Properties
+~~~~~~~~~~~~~~~~~~~~
+
+**status of new issues**
+ When a new message is received that is not identified as being related
+ to an existing issue, it creates a new issue. The status of the new
+ issue is defaulted to "unread".
+
+**reopening of resolved issues**
+ When a message is is received for a resolved issue, the issue status is
+ automatically reset to "chatting" to indicate new information has been
+ received.
+
+
+Sender identification
+---------------------
+
+If the sender of an e-mail is unknown to Roundup (looking up both user
+primary e-mail addresses and their alternate addresses) then a new user
+will be created. The new user will have their username set to the "user"
+part of "user at domain" in their e-mail address. Their password will be
+completely randomised, and they'll have to visit the web interface to
+have it changed. Some sites don't allow web access by users who register
+via e-mail like this.
+
+
+E-Mail Message Content
+----------------------
+
+Roundup only associates plain text (MIME type ``text/plain``) as
+messages for items. Any other parts of a message are associated as
+downloadable files. If no plain text part is found, the message is
+rejected.
+
+To do this, incoming messages are examined for multiple parts:
+
+* In a multipart/mixed message or part, each subpart is extracted and
+  examined. The text/plain subparts are assembled to form the textual
+  body of the message, to be stored in the file associated with a "msg"
+  class item. Any parts of other types are each stored in separate files
+  and given "file" class items that are linked to the "msg" item.
+* In a multipart/alternative message or part, we look for a text/plain
+  subpart and ignore the other parts.
+
+If the message is a response to a previous message, and contains quoted
+sections, then these will be stripped out of the message if the
+``EMAIL_KEEP_QUOTED_TEXT`` configuration variable is set to ``'no'``.
+
+Message summary
+~~~~~~~~~~~~~~~
+
+The "summary" property on message items is taken from the first
+non-quoting section in the message body. The message body is divided
+into sections by blank lines. Sections where the second and all
+subsequent lines begin with a ">" or "|" character are considered
+"quoting sections". The first line of the first non-quoting section
+becomes the summary of the message.
+
+
+Address handling
+----------------
+
+All of the addresses in the ``To:`` and ``Cc:`` headers of the incoming
+message are looked up among the tracker users, and the corresponding
+users are placed in the "recipients" property on the new "msg" item. The
+address in the ``From:`` header similarly determines the "author"
+property of the new "msg" item. The default handling for addresses that
+don't have corresponding users is to create new users with no passwords
+and a username equal to the address.
+
+The addresses mentioned in the ``To:``, ``From:`` and ``Cc:`` headers of
+the message may be added to the `nosy list`_ depending on:
+
+``ADD_AUTHOR_TO_NOSY``
+ Does the author of a message get placed on the nosy list automatically?
+ If 'new' is used, then the author will only be added when a message
+ creates a new issue. If 'yes', then the author will be added on
+ followups too. If 'no', they're never added to the nosy.
+
+``ADD_RECIPIENTS_TO_NOSY``
+ Do the recipients (To:, Cc:) of a message get placed on the nosy list?
+ If 'new' is used, then the recipients will only be added when a message
+ creates a new issue. If 'yes', then the recipients will be added on
+ followups too. If 'no', they're never added to the nosy.
+
+
+Nosy List
+~~~~~~~~~
+
+Roundup watches for additions to the "messages" property of items.
+
+When a new message is added, it is sent to all the users on the "nosy"
+list for the item that are not already on the "recipients" list of the
+message. Those users are then appended to the "recipients" property on
+the message, so multiple copies of a message are never sent to the same
+user. The journal recorded by the hyperdatabase on the "recipients"
+property then provides a log of when the message was sent to whom.
+
+If the author of the message is also in the nosy list for the item that
+the message is attached to, then the config var ``MESSAGES_TO_AUTHOR``
+is queried to determine if they get a nosy list copy of the message too.
+
+
+Mail gateway script command line
+--------------------------------
+
+Usage::
+
+  roundup-mailgw [[-C class] -S field=value]* <instance home> [method]
+
+The roundup mail gateway may be called in one of three ways:
+
+ - with an instance home as the only argument,
+ - with both an instance home and a mail spool file, or
+ - with both an instance home and a pop server account.
+ 
+It also supports optional -C and -S arguments that allows you to set a
+fields for a class created by the roundup-mailgw. The default class if
+not specified is msg, but the other classes: issue, file, user can also
+be used. The -S or --set options uses the same
+property=value[;property=value] notation accepted by the command line
+roundup command or the commands that can be given on the Subject line of
+an e-mail message.
+
+It can let you set the type of the message on a per e-mail address basis.
+
+PIPE:
+ In the first case, the mail gateway reads a single message from the
+ standard input and submits the message to the roundup.mailgw module.
+
+UNIX mailbox:
+ In the second case, the gateway reads all messages from the mail spool
+ file and submits each in turn to the roundup.mailgw module. The file is
+ emptied once all messages have been successfully handled. The file is
+ specified as::
+
+   mailbox /path/to/mailbox
+
+POP:
+ In the third case, the gateway reads all messages from the POP server
+ specified and submits each in turn to the roundup.mailgw module. The
+ server is specified as::
+
+    pop username:password at server
+
+ The username and password may be omitted::
+
+    pop username at server
+    pop server
+
+ are both valid. The username and/or password will be prompted for if
+ not supplied on the command-line.
+
+APOP:
+ Same as POP, but using Authenticated POP::
+
+    apop username:password at server
+
+
+Command Line Tool
+=================
+
+The basic usage is::
+
+ Usage: roundup-admin [options] [<command> <arguments>]
+
+ Options:
+  -i instance home  -- specify the issue tracker "home directory" to administer
+  -u                -- the user[:password] to use for commands
+  -d                -- print full designators not just class id numbers
+  -c                -- when outputting lists of data, comma-separate them.
+               Same as '-S ","'.
+  -S <string>       -- when outputting lists of data, string-separate them
+  -s                -- when outputting lists of data, space-separate them.
+               Same as '-S " "'.
+
+  Only one of -s, -c or -S can be specified.
+
+ Help:
+  roundup-admin -h
+  roundup-admin help                       -- this help
+  roundup-admin help <command>             -- command-specific help
+  roundup-admin help all                   -- all available help
+
+ Commands: 
+  commit
+  create classname property=value ...
+  display designator[,designator]*
+  export [class[,class]] export_dir
+  find classname propname=value ...
+  get property designator[,designator]*
+  help topic
+  history designator
+  import import_dir
+  initialise [adminpw]
+  install [template [backend [admin password]]]
+  list classname [property]
+  pack period | date
+  reindex
+  retire designator[,designator]*
+  rollback
+  security [Role name]
+  set items property=value property=value ...
+  specification classname
+  table classname [property[,property]*]
+ Commands may be abbreviated as long as the abbreviation matches only one
+ command, e.g. l == li == lis == list.
+
+
+All commands (except help) require a tracker specifier. This is just the
+path to the roundup tracker you're working with. A roundup tracker is
+where roundup keeps the database and configuration file that defines an
+issue tracker. It may be thought of as the issue tracker's "home
+directory". It may be specified in the environment variable
+``TRACKER_HOME`` or on the command line as "``-i tracker``".
+
+A designator is a classname and an itemid concatenated, eg. bug1,
+user10, ... Property values are represented as strings in command
+arguments and in the printed results:
+
+- Strings are, well, strings.
+- Password values will display as their encoded value.
+- Date values are printed in the full date format in the local time
+  zone, and accepted in the full format or any of the partial formats
+  explained below.::
+  
+    Input of...        Means...
+    "2000-04-17.03:45" 2000-04-17.03:45:00
+    "2000-04-17"       2000-04-17.00:00:00
+    "01-25"            yyyy-01-25.00:00:00
+    "08-13.22:13"      yyyy-08-13.22:13:00
+    "11-07.09:32:43"   yyyy-11-07.09:32:43
+    "14:25"            yyyy-mm-dd.14:25:00
+    "8:47:11"          yyyy-mm-dd.08:47:11
+    "2003"             2003-01-01.00:00:00
+    "2003-04"          2003-04-01.00:00:00
+    "."                "right now"
+    
+- Link values are printed as item designators. When given as an
+  argument, item designators and key strings are both accepted.
+- Multilink values are printed as lists of item designators joined by
+  commas. When given as an argument, item designators and key strings
+  are both accepted; an empty string, a single item, or a list of items
+  joined by commas is accepted.
+  
+When multiple items are specified to the roundup get or roundup set
+commands, the specified properties are retrieved or set on all the
+listed items.  When multiple results are returned by the roundup get or
+roundup find commands, they are printed one per line (default) or joined
+by commas (with the "``-c``" option).
+
+Where the command changes data, a login name/password is required. The
+login may be specified as either "``name``" or "``name:password``".
+
+- ``ROUNDUP_LOGIN`` environment variable
+- the "``-u``" command-line option
+
+If either the name or password is not supplied, they are obtained from
+the command-line.
+
+
+Using with the shell
+--------------------
+
+With version 0.6.0 or newer of roundup which supports: multiple
+designators to display and the -d, -S and -s flags.
+
+To find all messages regarding chatting issues that contain the word
+"spam", for example, you could execute the following command from the
+directory where the database dumps its files::
+
+    shell% for issue in `roundup-admin -ds find issue status=chatting`; do
+    > grep -l spam `roundup-admin -ds ' ' get messages $issue`
+    > done
+    msg23
+    msg49
+    msg50
+    msg61
+    shell%
+
+Or, using the -dc option, this can be written as a single command::
+
+    shell% grep -l spam `roundup get messages \
+        \`roundup -dc find issue status=chatting\``
+    msg23
+    msg49
+    msg50
+    msg61
+    shell%
+
+You can also display issue contents::
+
+    shell% roundup-admin display `roundup-admin -dc get messages \
+               issue3,issue1`
+    files: []
+    inreplyto: None
+    recipients: []
+    author: 1
+    date: 2003-02-16.21:23:03
+    messageid: None
+    summary: jkdskldjf
+    files: []
+    inreplyto: None
+    recipients: []
+    author: 1
+    date: 2003-02-15.01:59:11
+    messageid: None
+    summary: jlkfjadsf    
+    
+or status::
+
+    shell% roundup-admin get name `/tools/roundup/bin/roundup-admin \
+          -dc -i /var/roundup/sysadmin get status issue3,issue1`
+    unread
+    deferred
+
+or status on a single line::
+
+    shell% echo `roundup-admin get name \`/tools/roundup/bin/roundup-admin \
+             -dc -i /var/roundup/sysadmin get status issue3,issue1\``
+    unread deferred
+
+which is the same as::
+
+    shell% roundup-admin -s get name `/tools/roundup/bin/roundup-admin \
+             -dc -i /var/roundup/sysadmin get status issue3,issue1`
+    unread deferred
+
+Also the tautological::
+
+   shell% roundup-admin get name \
+      `roundup-admin -dc get status \`roundup-admin -dc find issue \
+          status=chatting\``
+   chatting
+   chatting
+
+Remember the roundup commands that accept multiple designators accept
+them ',' separated so using '-dc' is almost always required.
+
+-----------------
+
+Back to `Table of Contents`_
+
+.. _`Table of Contents`: index.html
+.. _`customisation documentation`: customizing.html

Added: tracker/vendor/roundup/current/doc/whatsnew-0.7.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/whatsnew-0.7.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,481 @@
+=========================
+What's New in Roundup 0.7
+=========================
+
+For those completely new to Roundup, you might want to look over the very
+terse features__ page.
+
+__ features.html
+
+.. contents::
+
+Instant-Gratification script even more gratifying
+=================================================
+
+The immensely popular ``python demo.py`` instant-gratification script has
+been extended to allow you to choose the backend to use with the demo. To
+select the "sqlite" backend (assuming it is available) you use::
+
+  python demo.py sqlite nuke
+
+This will nuke any existing demo and reinitialise it with the sqlite
+backend. Remember folks, if you want to restart the demo at a later point,
+you just need to type::
+
+  python demo.py
+
+without the "sqlite nuke" part, or you'll clear out the demo again. The
+backend names are:
+
+  anydbm bsddb bsddb3 sqlite metakit mysql postgresql
+
+You will need support modules installed for all except the first two. If
+you're not sure whether you have support, run::
+
+  python run_tests.py
+
+and if you see a line saying "Including XXXX tests" where XXXX is the
+backend you wish to try, then you're on your way. The mysql and postgresql
+require their test environments to be set up. Read their respective
+documents in the "doc" directory to do that.
+
+
+Web Interface
+=============
+
+Saving and sharing of user queries
+----------------------------------
+
+Due to popular demand, the user query saving mechanisms have been
+overhauled.
+
+As before, you may save queries in the tracker by giving the query a
+name. Each user may only have one query with a given name - if a
+subsequent search is performed with the same query name supplied, then
+it will edit the existing query of the same name.
+
+Queries may be marked as "private". These queries are only visible to the
+user that created them. If they're not marked "private" then all other
+users may include the query in their list of "Your Queries". Marking it as
+private at a later date does not affect users already using the query, nor
+does deleting the query.
+
+If a user subsequently creates or edits a public query, a new personal
+version of that query is made, with the same editing rules as described
+above.
+
+You *are not required* to make these changes in your tracker. You only
+need to make them if you wish to use the new query editing features. It's
+highly recommended, as the effort is minimal.
+
+1. You will need to edit your tracker's ``dbinit.py`` to change the way
+   queries are stored. Change the lines::
+
+      query = Class(db, "query",
+                      klass=String(),     name=String(),
+                      url=String())
+      query.setkey("name")
+
+   to::
+
+      query = Class(db, "query",
+                      klass=String(),     name=String(),
+                      url=String(),       private_for=Link('user'))
+
+   That is, add the "private_for" property, and remove the line that says
+   ``query.setkey("name")``.
+
+2. You will also need to copy the ``query.edit.html`` template page from the
+   ``templates/classic/html/`` directory of the source to your tracker's
+   ``html`` directory.
+
+3. Once you've done that, edit the tracker's ``page.html`` template to
+   change::
+
+    <td rowspan="2" valign="top" class="sidebar">
+     <p class="classblock" tal:condition="request/user/queries">
+      <b>Your Queries</b><br>
+      <tal:block tal:repeat="qs request/user/queries">
+
+   to::
+
+    <td rowspan="2" valign="top" class="sidebar">
+     <p class="classblock">
+      <b>Your Queries</b> (<a href="query?@template=edit">edit</a>)<br>
+      <tal:block tal:repeat="qs request/user/queries">
+
+   That is, you're removing the ``tal:condition`` and adding a link to the
+   new edit page.
+
+4. You might also wish to remove the redundant query editing section from the
+   ``user.item.html`` page.
+
+ZRoundup reinstated
+-------------------
+
+The Zope interface, ZRoundup, lives again!
+
+See the `upgrading documentation`__ if you wish to use it.
+
+__ upgrading.html#zroundup-changes
+
+
+Simple support for collision detection
+--------------------------------------
+
+Item edit pages that use the ``context/submit`` function to generate their
+submit buttons now automatically include a datestamp in the form. This
+datestamp is compared to the "activity" property of the item when the form
+is submitted. If the "actvity" property is younger than the datestamp in
+the form submission, then someone else has edited the item, and a page
+indicating this is displayed to the user.
+
+
+Extending the cgi interface
+---------------------------
+
+Before 0.7.0 adding or extending web actions was done by overriding or adding
+methods on the Client class. Though this approach still works to provide
+backwards compatibility, it is recommended you upgrade to the new approach, as
+described in the `Defining new web actions`__ section of the customization
+documentation. You might also want to take a look at the `Using an external
+password validation source`__ example.
+
+__ customizing.html#defining-new-web-actions
+__ customizing.html#using-an-external-password-validation-source
+
+Actions may also return the content that should return to the user, which
+causes the web interface to skip the normal template formatting step.
+This could be used to return an image to the user instead of HTML. Be sure
+to set the correct content-type header though! The default is still
+text/html. This is done with::
+
+   self.client.setHeader('Content-Type', 'image/png')
+
+if you were returning a PNG image.
+
+
+Roundup server 
+--------------
+
+The roundup-server web interface now supports setgid and running on port
+< 1024.
+
+It also forks to handle new connections, which means that trackers using
+the postgresql or mysql backends will be able to have multiple users
+accessing the tracker simultaneously.
+
+
+HTML templating made easier
+---------------------------
+
+All HTML templating functions perform checks for permissions required to
+display or edit the data they are manipulating. The simplest case is
+editing an issue title. Including the expression::
+
+   context/title/field
+
+will present the user with an edit field if they have Edit Permission. If
+not, then they will be presented with a static display if they have View
+Permission. If they don't even have View Permission, then an error message
+is raised, preventing the display of the page, indicating that they don't
+have permission to view the information.
+
+This removes the need for the template to perform those checks, which was
+just plain messy.
+
+Some new permissions will need to be created in your trackers to cope with
+this change, as outlined in the `upgrading documentation`__.
+
+__ upgrading.html#permission-assignments
+
+
+Standards changes
+-----------------
+
+The HTTP Content-Length header when we serve up files, either
+static ones from the "html" folder or file content from the database.
+
+We also handle If-Modified-Since and supply Last-Modified for both types
+of file too.
+
+The HTML generated in the classic tracker is now HTML4 (or optionally
+XHTML) compliant. The ``config.py`` variable "HTML_VERSION" is used to
+control this behaviour.
+
+The stylesheet includes printer settings now too, so printed pages
+don't include the sidebar.
+
+
+Quoting of URLs and HTML
+------------------------
+
+Templates that wish to offer file downloads may now use a new
+``download_url`` method::
+
+ <tr tal:repeat="file context/files">
+  <td>
+   <a tal:attributes="href file/download_url"
+      tal:content="file/name">dld link</a>
+  </td>
+ ...
+
+The ``download_url`` method looks up the file's "id" and "name" and
+generates a correctly-quoted URL.
+
+Additionally, users wishing to URL- or HTML- quote text in their templates
+may use the new ``utils.url_quote(url)`` and ``utils.html_quote(html)``
+methods.
+
+
+CSV download of search results
+------------------------------
+
+A new CGI action, ``export_csv`` has been added which exports a given
+index page query as a comma-separated-value file.
+
+To use this new action, just add a link to your ``issue.index.html``
+page::
+
+  <a tal:attributes="href python:request.indexargs_url('issue',
+            {'@action':'export_csv'})">Download as CSV</a>
+
+You may use this for other classes by adding it to their index page and
+changing the ``'issue'`` part of the expression to the new class' name.
+
+
+Other changes
+-------------
+
+- we serve up a favicon now
+- the page titles have the tracker name at the end of the text instead
+  of the start
+- added url_quote and html_quote methods to the utils object
+- added isset method to HTMLProperty
+- added search_checkboxes as an option for the search form
+
+
+Email Interface
+===============
+
+Better handling of some email headers
+-------------------------------------
+
+We ignore messages with the header "Precedence: bulk".
+
+If a Resent-From: header is present, it is used in preference to the From:
+header when determining the author of the message. Useful for redirecting
+error messages from automated systems.
+
+
+Email character set
+-------------------
+
+The default character set for sending email is UTF-8 (ie. Unicode). If you
+have users whose email clients can't handle UTF-8 (eg. Eudora) then you
+will need to edit the new config.py variable ``EMAIL_CHARSET``.
+
+
+Dispatcher configuration
+------------------------
+
+A new config option has been added that specifies the email address of
+a "dispatcher" role.  This email address acts as a central sentinel for
+issues coming into the system. You can configure it so that all e-mail
+error messages get bounced to them, them and the user in question, or
+just the user (default).
+
+To toggle these switches, add the "DISPATCHER_EMAIL" and
+"ERROR_MESSAGES_TO" configuration values to your tracker's ``config.py``.
+See the `customisation documentation`_ for how to use them.
+
+
+More flexible message generation
+--------------------------------
+
+The code for generating email messages in Roundup has been refactored. A
+new module, ``roundup.mailer`` contains most of the nuts-n-bolts required
+to generate email messages from Roundup.
+
+In addition, the ``IssueClass`` methods ``nosymessage()`` and
+``send_message()`` have both been altered so that they don't require the
+message id parameter. This means that change notes with no associated
+change message may now be generated much more easily.
+
+The roundupdb nosymessage() method also accepts a ``bcc`` argument which
+specifies additional userids to send the message to that will not be
+included in the To: header of the message.
+
+
+Registration confirmation by email
+----------------------------------
+
+Users may now reply to their registration confirmation email, and the
+roundup mail gateway will complete their registration.
+
+
+``roundup-mailgw`` now supports IMAP
+------------------------------------
+
+To retrieve from an IMAP mailbox, use a *cron* entry similar to the
+POP one::
+
+  0,10,20,30,40,50 * * * * /usr/local/bin/roundup-mailgw /opt/roundup/trackers/support imap <imap_spec>
+
+where imap_spec is "``username:password at server``" that specifies the roundup
+submission user's IMAP account name, password and server. You may
+optionally include a mailbox to use other than the default ``INBOX`` with
+"``imap username:password at server mailbox``".
+
+If you have a secure (ie. HTTPS) IMAP server then you may use ``imaps``
+in place of ``imap`` in the command to use a secure connection.
+
+
+Database configuration
+======================
+
+Postgresql added as a backend option
+------------------------------------
+
+Trackers may now use the postgresql RDBMS as a database store.
+
+Postgresql is a good choice if you expect your tracker to grow very large,
+and are expecting many users.
+
+
+API change
+----------
+
+The Database.curuserid attribute was removed. Any code referencing this
+attribute should be replaced with a call to Database.getuid().
+
+
+New configuration options
+-------------------------
+
+- Added DEFAULT_TIMEZONE which allows the tracker to have a different
+  default to UTC when users don't specify their own preference.
+
+- Added EMAIL_CHARSET (in 0.6.6, but worth mentioning here) which hard-codes
+  the character set to be used when sending email from Roundup. This works
+  around some email clients' inability to cope well with UTF-8 (the
+  default).
+
+- ERROR_MESSAGES_TO and DISPATCHER_EMAIL as described above in `Dispatcher
+  configuration`_.
+
+
+Typed columns in RDBMS backends
+-------------------------------
+
+The SQLite, MySQL and Postgresql backends now create tables with
+appropriate column datatypes (not just varchar).
+
+Your database will be automatically migrated to use the new schemas, but
+it will take time. It's probably a good idea to make sure you do this as
+part of the upgrade when users are not expected to be using the system.
+
+
+Permission setup
+----------------
+
+0.7 automatically sets up the Edit and View Permissions for all classes,
+thus you don't need to do so. Feel free to remove the code::
+
+    # Add new Permissions for this schema
+    for cl in 'issue', 'file', 'msg', 'user', 'query', 'keyword':
+        db.security.addPermission(name="Edit", klass=cl,
+            description="User is allowed to edit "+cl)
+        db.security.addPermission(name="View", klass=cl,
+            description="User is allowed to access "+cl)
+
+from your ``dbinit.py``.
+
+
+New "actor" property
+--------------------
+
+Roundup's database has a new per-item property "actor" which reflects the
+user performing the last "actvitiy". See the classic template for ways to
+integrate this new property into your interface.
+
+The property will be automatically added to your existing database.
+
+
+New Reject exception for Auditors
+---------------------------------
+
+An auditor may raise this exception when the current create or set
+operation should be stopped.
+
+It is up to the specific interface invoking the create or set to
+handle this exception sanely. For example:
+
+- mailgw will trap and ignore Reject for file attachments and messages
+- cgi will trap and present the exception in a nice format
+
+
+New auditor fixes Outlook bug
+-----------------------------
+
+The new optional auditor ``detectors/emailauditor.py`` fires whenever a
+new file entity is created.
+
+If the file is of type message/rfc822, we tack on the extension .mht.
+
+The reason for this is that Microsoft Internet Explorer will not open
+things with a .eml attachment, as they deem it 'unsafe'. Worse yet,
+they'll just give you an incomprehensible error message. For more 
+information, please see: 
+
+http://support.microsoft.com/default.aspx?scid=kb;EN-US;825803
+
+Their suggested work around is (excerpt):
+
+ WORKAROUND
+
+ To work around this behavior, rename the .EML file that the URL
+ links to so that it has a .MHT file name extension, and then update
+ the URL to reflect the change to the file name. To do this:
+
+ 1. In Windows Explorer, locate and then select the .EML file that
+    the URL links.
+ 2. Right-click the .EML file, and then click Rename.
+ 3. Change the file name so that the .EML file uses a .MHT file name
+    extension, and then press ENTER.
+ 4. Updated the URL that links to the file to reflect the new file
+    name extension.
+
+
+New script for copying users
+----------------------------
+
+A new script, ``scripts/copy-user.py``, will copy users from one tracker
+to another.  Example usage::
+
+    copy-user.py /roundup/tracker1 /roundup/tracker2 `seq 3 10` 14 16
+
+which copies users 3, 4, 5, 6, 7, 8, 9, 10, 14 and 16.
+
+
+Other improvements
+------------------
+
+- All RDBMS backends now have indexes automatically created on critical
+  table columns.
+
+- Additionally, the RDBMS backends also implement their own session,
+  one-time-key and full-text indexing stores. These were previously external
+  dbm stores. This change allows control of locking the database to be
+  completely handed over to the RDBMS.
+
+- Date values capture fractions of seconds now. Note that the MySQL backend
+  is not capable of storing this precision though, so it will be lost for
+  users of that backend.
+
+- The roundup-admin "export" and "import" commands now handle the database
+  journals too. This means that exports from previous versions of Roundup
+  will not work under 0.7!
+
+
+.. _`customisation documentation`: customizing.html

Added: tracker/vendor/roundup/current/doc/whatsnew-0.8.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/doc/whatsnew-0.8.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,187 @@
+=========================
+What's New in Roundup 0.8
+=========================
+
+For those completely new to Roundup, you might want to look over the very
+terse features__ page.
+
+__ features.html
+
+.. contents::
+
+In Summary
+==========
+
+(this information copied directly from the ``CHANGES.txt`` file)
+
+XXX this section needs more detail
+
+- create a new RDBMS cursor after committing
+- roundup-admin reindex command may now work on single items or classes
+
+- roundup-server options -g and -u accept both ids and names (sf bug 983769)
+- roundup-server now has a configuration file (-C option)
+- roundup windows service may be installed with command line options
+  recognized by roundup-server (but not tracker specification arguments).
+  Use this to specify server configuration file for the service.
+
+- added option to turn off registration confirmation via email
+  ("instant_registration" in config) (sf rfe 922209)
+
+
+
+Performance improvements
+========================
+
+We don't try to import all backends in backends.__init__ unless we *want*
+to.
+
+Roundup may now use the Apache mod_python interface (see installation.txt)
+which is much faster than the standard cgi-bin and a little faster than
+roundup-server.
+
+There is now an experimental multi-thread server which should allow faster
+concurrent access.
+
+In the hyperdb, a few other speedups were implemented, such as:
+
+- record journaltag lookup ("fixes" sf bug 998140)
+- unless in debug mode, keep a single persistent connection through a
+  single web or mailgw request.
+- remove "manual" locking of sqlite database
+
+
+Logging of internal messages
+============================
+
+Roundup's previously ad-hoc logging of events has been cleaned up and is
+now configured in a single place in the tracker configuration file.
+
+The `customization documentation`_ has more details on how this is
+configured.
+
+roundup-mailgw now logs fatal exceptions rather than mailing them to admin.
+
+
+Security Changes
+================
+
+``security.addPermissionToRole()`` has been extended to allow skipping the
+separate getPermission call.
+
+
+Password Storage
+----------------
+
+Added MD5 scheme for password hiding. This extends the existing SHA and
+crypt methods and is useful if you have an existing MD5 password database.
+
+
+Permission Definitions
+----------------------
+
+Permissions may now be defined on a per-property basis, allowing access to
+only specific properties on items. 
+
+Permissions may also have code attached which is executed to check whether
+the Permission is valid for the current user and item.
+
+Permissions are now automatically checked when information is rendered
+through the web. This includes:
+
+1. View checks for properties when being rendered via the ``plain()`` or
+   similar methods. If the check fails, the text "[hidden]" will be
+   displayed.
+2. Edit checks for properties when the edit field is being rendered via
+   the ``field()`` or similar methods. If the check fails, the property
+   will be rendered via the ``plain()`` method (see point 1. for additional
+   checking performed)
+3. View checks are performed in index pages for each item being displayed
+   such that if the user does not have permission, the row is not rendered.
+
+
+Extending Roundup
+=================
+
+To write extension code for Roundup you place a file in the tracker home
+``extensions`` directory. See the `customisation documentation`_ for more
+information about how this is done.
+
+
+8-bit character set support in Web interface
+============================================
+
+This is used to override the UTF-8 default. It may be overridden in both
+forms and a browser cookie.
+
+- In forms, use the ``@charset`` variable.
+- To use the cookie override, have the ``roundup_charset`` cookie set.
+
+In both cases, the value is a valid charset name (eg. ``utf-8`` or
+``kio8-r``).
+
+Inside Roundup, all strings are stored and processed in utf-8.
+Unfortunately, some older browsers do not work properly with
+utf-8-encoded pages (e.g. Netscape Navigator 4 displays wrong
+characters in form fields).  This version allows to change
+the character set for http transfers.  To do so, you may add
+the following code to your ``page.html`` template::
+
+ <tal:block define="uri string:${request/base}${request/env/PATH_INFO}">
+  <a tal:attributes="href python:request.indexargs_url(uri,
+   {'@charset':'utf-8'})">utf-8</a>
+  <a tal:attributes="href python:request.indexargs_url(uri,
+   {'@charset':'koi8-r'})">koi8-r</a>
+ </tal:block>
+
+(substitute ``koi8-r`` with the appropriate charset for your language).
+Charset preference is kept in the browser cookie ``roundup_charset``.
+
+``meta http-equiv`` lines added to the tracker templates in version 0.6.0
+should be changed to include actual character set name::
+
+ <meta http-equiv="Content-Type"
+  tal:attributes="content string:text/html;; charset=${request/client/charset}"
+ />
+
+Actual charset is also sent in the http header.
+
+
+Web Interface Miscellanea
+=========================
+
+The web interface has seen some changes:
+
+Editing
+
+Templating
+  We implement __nonzero__ for HTMLProperty - properties may now be used in
+  boolean conditions (eg ``tal:condition="issue/nosy"`` will be false if
+  the nosy list is empty).
+
+  We added a default argument to the DateHTMLProperty.field method, and an
+  optional Interval (string or object) to the DateHTMLProperty.now
+
+  We've added a multiple selection Link/Multilink search field macro to the
+  default classic page.html template.
+
+  We relaxed hyperlinking in web interface (accept "issue123" or "Issue 123")
+
+  The listing popup may be used in query forms.
+
+Standard templates
+  We hide "(list)" popup links when issue is only viewable
+
+  The issue search page now has fields to allow no sorting / grouping of
+  the results.
+
+  The default page.html template now has a search box in the top right
+  corner which performs a full-text search of issues. The "show issue"
+  quick jump form in the sidebar has had its font size reduced to use less
+  space.
+
+Web server
+  The builtin web server may now perform HTTP Basic Authentication by
+  itself.
+
+.. _`customization documentation`: customizing.html

Added: tracker/vendor/roundup/current/frontends/README.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/frontends/README.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,8 @@
+This directory contains alternate front-ends for Roundup.
+
+Zope - ZRoundup
+---------------
+
+This installs as a regular Zope product. See Roundup's doc/installation.txt
+for more info.
+

Added: tracker/vendor/roundup/current/frontends/ZRoundup/.cvsignore
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/frontends/ZRoundup/.cvsignore	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,2 @@
+*.pyc
+*.pyo

Added: tracker/vendor/roundup/current/frontends/ZRoundup/ZRoundup.py
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/frontends/ZRoundup/ZRoundup.py	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,218 @@
+# Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
+# This module is free software, and you may redistribute it and/or modify
+# under the same terms as Python, so long as this copyright message and
+# disclaimer are retained in their original form.
+#
+# IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
+# OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
+# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
+# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+# 
+# $Id: ZRoundup.py,v 1.22 2006/01/25 03:43:04 richard Exp $
+#
+''' ZRoundup module - exposes the roundup web interface to Zope
+
+This frontend works by providing a thin layer that sits between Zope and the
+regular CGI interface of roundup, providing the web frontend with the minimum
+of effort.
+
+This means that the regular CGI interface does all authentication quite
+independently of Zope. The roundup code is kept in memory though, and it
+runs in the same server as all your other Zope stuff, so it does have _some_
+advantages over regular CGI :)
+'''
+
+import urlparse
+
+from Globals import InitializeClass, HTMLFile
+from OFS.SimpleItem import Item
+from OFS.PropertyManager import PropertyManager
+from Acquisition import Explicit, Implicit
+from Persistence import Persistent
+from AccessControl import ClassSecurityInfo
+from AccessControl import ModuleSecurityInfo
+modulesecurity = ModuleSecurityInfo()
+
+import roundup.instance
+from roundup.cgi import client
+
+modulesecurity.declareProtected('View management screens',
+    'manage_addZRoundupForm')
+manage_addZRoundupForm = HTMLFile('dtml/manage_addZRoundupForm', globals())
+
+modulesecurity.declareProtected('Add Z Roundups', 'manage_addZRoundup')
+def manage_addZRoundup(self, id, instance_home, REQUEST):
+    """Add a ZRoundup product """
+    # validate the instance_home
+    roundup.instance.open(instance_home)
+    self._setObject(id, ZRoundup(id, instance_home))
+    return self.manage_main(self, REQUEST)
+
+class RequestWrapper:
+    '''Make the Zope RESPONSE look like a BaseHTTPServer
+    '''
+    def __init__(self, RESPONSE):
+        self.RESPONSE = RESPONSE
+        self.wfile = self.RESPONSE
+    def send_response(self, status):
+        self.RESPONSE.setStatus(status)
+    def send_header(self, header, value):
+        self.RESPONSE.addHeader(header, value)
+    def end_headers(self):
+        # not needed - the RESPONSE object handles this internally on write()
+        pass
+
+class FormItem:
+    '''Make a Zope form item look like a cgi.py one
+    '''
+    def __init__(self, value):
+        self.value = value
+        if hasattr(self.value, 'filename'):
+            self.filename = self.value.filename
+            self.value = self.value.read()
+
+class FormWrapper:
+    '''Make a Zope form dict look like a cgi.py one
+    '''
+    def __init__(self, form):
+        self.__form = form
+    def __getitem__(self, item):
+        entry = self.__form[item]
+        if isinstance(entry, type([])):
+            entry = map(FormItem, entry)
+        else:
+            entry = FormItem(entry)
+        return entry
+    def getvalue(self, key, default=None):
+        if self.__form.has_key(key):
+            return self.__form[key]
+        else:
+            return default
+    def has_key(self, item):
+        return self.__form.has_key(item)
+    def keys(self):
+        return self.__form.keys()
+
+    def __repr__(self):
+        return '<ZRoundup.FormWrapper %r>'%self.__form
+
+class ZRoundup(Item, PropertyManager, Implicit, Persistent):
+    '''An instance of this class provides an interface between Zope and
+       roundup for one roundup instance
+    '''
+    meta_type =  'Z Roundup'
+    security = ClassSecurityInfo()
+
+    def __init__(self, id, instance_home):
+        self.id = id
+        self.instance_home = instance_home
+
+    # define the properties that define this object
+    _properties = (
+        {'id':'id', 'type': 'string', 'mode': 'w'},
+        {'id':'instance_home', 'type': 'string', 'mode': 'w'},
+    )
+    property_extensible_schema__ = 0
+
+    # define the tabs for the management interface
+    manage_options= PropertyManager.manage_options + (
+        {'label': 'View', 'action':'index_html'},
+    ) + Item.manage_options
+
+    icon = "misc_/ZRoundup/icon"
+
+    security.declarePrivate('roundup_opendb')
+    def roundup_opendb(self):
+        '''Open the roundup instance database for a transaction.
+        '''
+        tracker = roundup.instance.open(self.instance_home)
+        request = RequestWrapper(self.REQUEST['RESPONSE'])
+        env = self.REQUEST.environ
+
+        # figure out the path components to set
+        url = urlparse.urlparse( self.absolute_url() )
+        path = url[2]
+        path_components = path.split( '/' )
+
+        # special case when roundup is '/' in this virtual host,
+        if path == "/" :
+            env['SCRIPT_NAME'] = "/"
+            env['TRACKER_NAME'] = ''
+        else :
+            # all but the last element is the path
+            env['SCRIPT_NAME'] = '/'.join( path_components[:-1] )
+            # the last element is the name
+            env['TRACKER_NAME'] = path_components[-1]
+
+        form = FormWrapper(self.REQUEST.form)
+        if hasattr(tracker, 'Client'):
+            return tracker.Client(tracker, request, env, form)
+        return client.Client(tracker, request, env, form)
+
+    security.declareProtected('View', 'index_html')
+    def index_html(self):
+        '''Alias index_html to roundup's index
+        '''
+        # Redirect misdirected requests -- bugs 558867 , 565992
+        # PATH_INFO, as defined by the CGI spec, has the *real* request path
+        orig_path = self.REQUEST.environ['PATH_INFO']
+        if orig_path[-1] != '/' : 
+            url = urlparse.urlparse( self.absolute_url() )
+            url = list( url ) # make mutable
+            url[2] = url[2]+'/' # patch
+            url = urlparse.urlunparse( url ) # reassemble
+            RESPONSE = self.REQUEST.RESPONSE
+            RESPONSE.setStatus( "MovedPermanently" ) # 301
+            RESPONSE.setHeader( "Location" , url )
+            return RESPONSE
+
+        client = self.roundup_opendb()
+        # fake the path that roundup should use
+        client.split_path = ['index']
+        return client.main()
+
+    def __getitem__(self, item):
+        '''All other URL accesses are passed throuh to roundup
+        '''
+        return PathElement(self, item).__of__(self)
+
+class PathElement(Item, Implicit):
+    def __init__(self, zr, path):
+        self.zr = zr
+        self.path = path
+
+    def __getitem__(self, item):
+        ''' Get a subitem.
+        '''
+        return PathElement(self.zr, self.path + '/' + item).__of__(self)
+
+    def index_html(self, REQUEST=None):
+        ''' Actually call through to roundup to handle the request.
+        '''
+        try:
+            client = self.zr.roundup_opendb()
+            # fake the path that roundup should use
+            client.path = self.path
+            # and call roundup to do something 
+            client.main()
+            return ''
+        except client.NotFound:
+            raise 'NotFound', REQUEST.URL
+            pass
+        except:
+            import traceback
+            traceback.print_exc()
+            # all other exceptions in roundup are valid
+            raise
+
+InitializeClass(ZRoundup)
+modulesecurity.apply(globals())
+
+
+# vim: set filetype=python ts=4 sw=4 et si

Added: tracker/vendor/roundup/current/frontends/ZRoundup/__init__.py
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/frontends/ZRoundup/__init__.py	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,56 @@
+# Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
+# This module is free software, and you may redistribute it and/or modify
+# under the same terms as Python, so long as this copyright message and
+# disclaimer are retained in their original form.
+#
+# IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
+# OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
+# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
+# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+# 
+# $Id: __init__.py,v 1.4 2002/10/10 03:47:27 richard Exp $
+#
+__version__='1.0'
+
+import os
+# figure where ZRoundup is installed
+here = None
+if os.environ.has_key('INSTANCE_HOME'):
+    here = os.environ['INSTANCE_HOME']
+    path = os.path.join(here, 'Products', 'ZRoundup')
+    if not os.path.exists(path):
+        path = os.path.join(here, 'lib', 'python', 'Products', 'ZRoundup')
+        if not os.path.exists(path):
+            here = None
+if here is None:
+    from __main__ import here
+    path = os.path.join(here, 'Products', 'ZRoundup')
+    if not os.path.exists(path):
+        path = os.path.join(here, 'lib', 'python', 'Products', 'ZRoundup')
+        if not os.path.exists(path):
+            raise ValueError, "Can't determine where ZRoundup is installed"
+
+# product initialisation
+import ZRoundup
+def initialize(context):
+    context.registerClass(
+        ZRoundup, meta_type = 'Z Roundup',
+        constructors = (
+            ZRoundup.manage_addZRoundupForm, ZRoundup.manage_addZRoundup
+        )
+    )
+
+# set up the icon
+from ImageFile import ImageFile
+misc_ = {
+    'icon': ImageFile('icons/tick_symbol.gif', path), 
+}
+
+
+# vim: set filetype=python ts=4 sw=4 et si

Added: tracker/vendor/roundup/current/frontends/ZRoundup/dtml/manage_addZRoundupForm.dtml
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/frontends/ZRoundup/dtml/manage_addZRoundupForm.dtml	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,5 @@
+<form action="manage_addZRoundup">
+ID: <input type="text" name="id"><br>
+Instance Home: <input type="text" name="instance_home"><br>
+<input type="submit">
+</form>

Added: tracker/vendor/roundup/current/frontends/ZRoundup/icons/tick_symbol.gif
==============================================================================
Binary file. No diff available.

Added: tracker/vendor/roundup/current/frontends/ZRoundup/refresh.txt
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/frontends/ZRoundup/refresh.txt	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,2 @@
+The existence of this file enables the Zope product refresh option.
+Read the Zope documentation for more info about product refresh.

Added: tracker/vendor/roundup/current/locale/.cvsignore
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/locale/.cvsignore	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,5 @@
+*.mo
+*.bak
+*.swp
+*.tmp
+*.poedit
\ No newline at end of file

Added: tracker/vendor/roundup/current/locale/GNUmakefile
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/locale/GNUmakefile	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,56 @@
+# Extract translatable strings from Roundup sources,
+# update and compile all existing translations
+#
+# $Id: GNUmakefile,v 1.10 2006/03/04 09:04:29 a1s Exp $
+
+# tool locations
+XPOT ?= xpot
+MSGFMT ?= msgfmt
+MSGMERGE ?= msgmerge
+XGETTEXT ?= xgettext
+PYTHON ?= python
+
+TEMPLATE=roundup.pot
+
+PACKAGES=$(shell find ../roundup -name '*.py'|sed -e 's,/[^/]*$$,,'|sort|uniq)
+SOURCES=$(PACKAGES:=/*.py)
+PO_FILES=$(wildcard *.po)
+MO_FILES=$(PO_FILES:.po=.mo)
+RUN_PYTHON=PYTHONPATH=../build/lib $(PYTHON) -O
+
+all: dist
+
+help:
+	@echo "$(MAKE)           - build MO files.  Run this before sdist"
+	@echo "$(MAKE) template  - update message template from sources"
+	@echo "$(MAKE) locale.po - update message file from template"
+	@echo "$(MAKE) locale.mo - compile individual message file"
+	@echo "$(MAKE) help      - this text"\
+
+# This will rebuild all MO files without updating their corresponding PO
+# files first.  Run before creating Roundup distribution (hence the name).
+# PO files should be updated by their translators only, automatic update
+# adds unwanted fuzzy labels.
+dist:
+	for file in $(PO_FILES); do \
+	  ${MSGFMT} -o `basename $$file .po`.mo $$file; \
+	done
+
+template:
+	${XPOT} -n -o $(TEMPLATE) $(SOURCES)
+	${RUN_PYTHON} ../roundup/cgi/TAL/talgettext.py -u $(TEMPLATE) \
+	  ../templates/classic/html/*.html ../templates/minimal/html/*.html
+	${XGETTEXT} -j -w 80 -F \
+	  --msgid-bugs-address=roundup-devel at lists.sourceforge.net \
+	  --copyright-holder="See Roundup README.txt" \
+	  -o $(TEMPLATE) $(SOURCES)
+
+# helps to check template file before check in
+diff:
+	cvs diff roundup.pot|grep -v '^[-+]#'|vim -Rv -
+
+%.po: $(TEMPLATE)
+	${MSGMERGE} -U --suffix=.bak $@ $<
+
+%.mo: %.po
+	${MSGFMT} --statistics -o $@ $<

Added: tracker/vendor/roundup/current/locale/de.po
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/locale/de.po	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,2989 @@
+# German message file for Roundup Issue Tracker
+# Stefan Niederhauser <stefan.niederhauser at unibas.ch>, 2004.
+#
+# $Id: de.po,v 1.3 2005/01/13 23:08:12 richard Exp $
+#
+# roundup.pot revision 1.8
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Roundup 0.7.0\n"
+"Report-Msgid-Bugs-To: roundup-devel at lists.sourceforge.net\n"
+"POT-Creation-Date: 2004-12-08 10:25+0200\n"
+"PO-Revision-Date: 2004-07-05 15:00+0100\n"
+"Last-Translator: Stefan Niederhauser <stefan.niederhauser at unibas.ch>\n"
+"Language-Team: German Translators <roundup-devel at lists.sourceforge.net>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+# ../roundup/admin.py:83 :949 :998 :1020
+#: ../roundup/admin.py:84 ../roundup/admin.py:954 ../roundup/admin.py:1003
+#: ../roundup/admin.py:1025
+#, python-format
+msgid "no such class \"%(classname)s\""
+msgstr "Die Klasse \"%(classname)s\" existiert nicht"
+
+# ../roundup/admin.py:93 :97
+#: ../roundup/admin.py:94 ../roundup/admin.py:98
+#, python-format
+msgid "argument \"%(arg)s\" not propname=value"
+msgstr ""
+"Der Parameter \"%(arg)s\" entspricht nicht dem Format Eigenschaft=Wert"
+
+#: ../roundup/admin.py:111
+#, python-format
+msgid ""
+"Problem: %(message)s\n"
+"\n"
+msgstr ""
+"Problem: %(message)s\n"
+"\n"
+
+#: ../roundup/admin.py:112
+#, python-format
+msgid ""
+"%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
+"\n"
+"Options:\n"
+" -i instance home  -- specify the issue tracker \"home directory\" to "
+"administer\n"
+" -u                -- the user[:password] to use for commands\n"
+" -d                -- print full designators not just class id numbers\n"
+" -c                -- when outputting lists of data, comma-separate them.\n"
+"                      Same as '-S \",\"'.\n"
+" -S <string>       -- when outputting lists of data, string-separate them\n"
+" -s                -- when outputting lists of data, space-separate them.\n"
+"                      Same as '-S \" \"'.\n"
+"\n"
+" Only one of -s, -c or -S can be specified.\n"
+"\n"
+"Help:\n"
+" roundup-admin -h\n"
+" roundup-admin help                       -- this help\n"
+" roundup-admin help <command>             -- command-specific help\n"
+" roundup-admin help all                   -- all available help\n"
+msgstr ""
+"%(message)sVerwendung: roundup-admin [Optionen] [<Befehl> <Parameter>]\n"
+"\n"
+"Optionen:\n"
+" -i <Instanzverzeichnis> -- Tracker-Instanz zur Administration auswählen\n"
+" -u                -- Benutzer[:Password] für das Ausführen von Befehlen\n"
+" -d                -- Lange Bezeichner anzeigen statt Klassen-Ids\n"
+" -c                -- Komma-getrennte Listenausgabe (CSV).\n"
+"                      Analog zu '-S \",\"'.\n"
+" -S <Zeichenkette> -- Trennzeichen bei der Listenausgabe.\n"
+" -s                -- Leerschlag als Trennzeichen verwenden.\n"
+"                      Analog zu '-S \" \"'.\n"
+"\n"
+" Nur eine der Optionen -s, -c or -S kann gewählt werden.\n"
+"\n"
+"Hilfe:\n"
+" roundup-admin -h\n"
+" roundup-admin help                       -- diese Kurzhilfe anzeigen\n"
+" roundup-admin help <Befehl>              -- Hilfe zu einem Befehl anzeigen\n"
+" roundup-admin help all                   -- Sämtliche Hilfe anzeigen\n"
+
+#: ../roundup/admin.py:137
+msgid "Commands:"
+msgstr "Befehle:"
+
+#: ../roundup/admin.py:144
+msgid ""
+"Commands may be abbreviated as long as the abbreviation\n"
+"matches only one command, e.g. l == li == lis == list."
+msgstr ""
+"Befehle können abgekürzt werden, solange sie eindeutig bleiben, \n"
+"z.B. l == li == lis == list."
+
+#: ../roundup/admin.py:174
+msgid ""
+"\n"
+"All commands (except help) require a tracker specifier. This is just\n"
+"the path to the roundup tracker you're working with. A roundup tracker\n"
+"is where roundup keeps the database and configuration file that defines\n"
+"an issue tracker. It may be thought of as the issue tracker's \"home\n"
+"directory\". It may be specified in the environment variable TRACKER_HOME\n"
+"or on the command line as \"-i tracker\".\n"
+"\n"
+"A designator is a classname and a nodeid concatenated, eg. bug1, "
+"user10, ...\n"
+"\n"
+"Property values are represented as strings in command arguments and in the\n"
+"printed results:\n"
+" . Strings are, well, strings.\n"
+" . Date values are printed in the full date format in the local time zone,\n"
+"   and accepted in the full format or any of the partial formats explained\n"
+"   below.\n"
+" . Link values are printed as node designators. When given as an argument,\n"
+"   node designators and key strings are both accepted.\n"
+" . Multilink values are printed as lists of node designators joined\n"
+"   by commas.  When given as an argument, node designators and key\n"
+"   strings are both accepted; an empty string, a single node, or a list\n"
+"   of nodes joined by commas is accepted.\n"
+"\n"
+"When property values must contain spaces, just surround the value with\n"
+"quotes, either ' or \". A single space may also be backslash-quoted. If a\n"
+"value must contain a quote character, it must be backslash-quoted or inside\n"
+"quotes. Examples:\n"
+"           hello world      (2 tokens: hello, world)\n"
+"           \"hello world\"    (1 token: hello world)\n"
+"           \"Roch'e\" Compaan (2 tokens: Roch'e Compaan)\n"
+"           Roch\\'e Compaan  (2 tokens: Roch'e Compaan)\n"
+"           address=\"1 2 3\"  (1 token: address=1 2 3)\n"
+"           \\\\               (1 token: \\)\n"
+"           \\n\\r\\t           (1 token: a newline, carriage-return and "
+"tab)\n"
+"\n"
+"When multiple nodes are specified to the roundup get or roundup set\n"
+"commands, the specified properties are retrieved or set on all the listed\n"
+"nodes.\n"
+"\n"
+"When multiple results are returned by the roundup get or roundup find\n"
+"commands, they are printed one per line (default) or joined by commas (with\n"
+"the -c) option.\n"
+"\n"
+"Where the command changes data, a login name/password is required. The\n"
+"login may be specified as either \"name\" or \"name:password\".\n"
+" . ROUNDUP_LOGIN environment variable\n"
+" . the -u command-line option\n"
+"If either the name or password is not supplied, they are obtained from the\n"
+"command-line.\n"
+"\n"
+"Date format examples:\n"
+"  \"2000-04-17.03:45\" means <Date 2000-04-17.08:45:00>\n"
+"  \"2000-04-17\" means <Date 2000-04-17.00:00:00>\n"
+"  \"01-25\" means <Date yyyy-01-25.00:00:00>\n"
+"  \"08-13.22:13\" means <Date yyyy-08-14.03:13:00>\n"
+"  \"11-07.09:32:43\" means <Date yyyy-11-07.14:32:43>\n"
+"  \"14:25\" means <Date yyyy-mm-dd.19:25:00>\n"
+"  \"8:47:11\" means <Date yyyy-mm-dd.13:47:11>\n"
+"  \".\" means \"right now\"\n"
+"\n"
+"Command help:\n"
+msgstr ""
+"\n"
+"Sie müssen für sämtliche Befehle - ausser für die Hilfe - das Verzeichnis\n"
+"einer Tracker-Instanz angeben. Dort wird die Konfiguration gespeichert und\n"
+" - je nach Datenbank - auch die Daten. Das Tracker-Verzeichnis kann über\n"
+"die Umgebungsvariable TRACKER_HOME oder die Option \"-i Verzeichnis\"\n"
+"angegeben werden.\n"
+"\n"
+"Ein Bezeichner besteht aus einem Klassennamen und einer ID, zum Beispiel\n"
+"\"issue12\"\n"
+"\n"
+"Eigenschaften werden als Zeichenketten übergeben und angezeigt.\n"
+" . Eine Zeichenkette (\"String\") wird direkt ausgegeben.\n"
+" . Datumswerte werden als vollständiges Datum in der lokalen Zeitzone\n"
+"   ausgegeben und können im vollständigen Format oder in einem Teilformat\n"
+"   eingeben werden (siehe unten).\n"
+" . Links zu anderen Einträgen werden mit dem Bezeichner dargestellt.\n"
+"   Bei der Eingabe wird entweder der Bezeichner, oder nur der Schlüssel\n"
+"   angegeben.\n"
+" . Bei Mehrfach-Links werden die verlinkten Bezeichner mit Komma getrennt\n"
+"   ausgegeben. Bei der Eingabe können Bezeichner oder Schlüssel\n"
+"   mit Kommas getrennt eingegeben werden.\n"
+"\n"
+"Falls Eigenschaften Leerschläge enthalten, müssen die Werte in\n"
+"\"Anführungszeichen\" eingeschlossen werden. Leerschläge können auch mit\n"
+"einem \\Backslash geschützt werden. Ebenso müssen Anführungszeichen im Wert\n"
+"mit einem Backslash versehen werden, einfache ' wie doppelte \".\n"
+"Beispiele:\n"
+"           Hallo Welt          (2 Werte: Hallo, Welt)\n"
+"           \"Hallo Welt\"      (1 Wert: Hallo Welt)\n"
+"           \"Sophie's\" Welt   (2 Werte: Sophie's, Welt)\n"
+"           Adresse=\"1 2 3\"   (1 Wert: Address=1 2 3)\n"
+"           \\\\                (1 Wert: \\)\n"
+"           \\n\\r\\t           (1 Wert: Zeilenumbruch + CR + Tab)\n"
+"\n"
+"Wenn bei einer Abfrage oder einer Änderung mehrere Einträge angegeben\n"
+"werden, so werden die gewünschten Eigenschaften aller Einträge angezeigt\n"
+"order geändert.\n"
+"\n"
+"Wenn ein Befehl \"get\" oder \"find\" mehrere Einträge zurückgibt, so \n"
+"werden diese Zeile für Zeile, oder (mit der -c Option) kommagetrennet\n"
+"ausgegeben.\n"
+"\n"
+"Bei Änderungen wird ein Benutzername und ein Passwort benötigt.\n"
+"Diese Angaben können in der Umgebungsvariable ROUNDUP_LOGIN oder mit der\n"
+"Option -u gemacht werden, entweder als \"Benutzername\" oder als\n"
+"\"benutzername:passwort\".\n"
+"\n"
+"Beispiele für Datumsformate:\n"
+"  \"2000-04-17.03:45\" ergibt <Date 2000-04-17.08:45:00>\n"
+"  \"2000-04-17\" ergibt <Date 2000-04-17.00:00:00>\n"
+"  \"01-25\" ergibt <Date yyyy-01-25.00:00:00>\n"
+"  \"08-13.22:13\" ergibt <Date yyyy-08-14.03:13:00>\n"
+"  \"11-07.09:32:43\" ergibt <Date yyyy-11-07.14:32:43>\n"
+"  \"14:25\" ergibt <Date yyyy-mm-dd.19:25:00>\n"
+"  \"8:47:11\" ergibt <Date yyyy-mm-dd.13:47:11>\n"
+"  \".\" ergibt \"jetzt\"\n"
+"\n"
+"Befehlshilfe:\n"
+
+#: ../roundup/admin.py:237
+#, python-format
+msgid "%s:"
+msgstr "%s:"
+
+#: ../roundup/admin.py:242
+msgid ""
+"Usage: help topic\n"
+"        Give help about topic.\n"
+"\n"
+"        commands  -- list commands\n"
+"        <command> -- help specific to a command\n"
+"        initopts  -- init command options\n"
+"        all       -- all available help\n"
+"        "
+msgstr ""
+"Verwendung: help Thema\n"
+"        Zeigt die Hilfe für ein Thema ein.\n"
+"\n"
+"        commands  -- Befehle auflisten\n"
+"        <command> -- Hilfe zu einem bestimmten Befehl\n"
+"        initopts  -- Optionen zur Initialisierung\n"
+"        all       -- Sämtlichen Hilfetext anzeigen\n"
+"        "
+
+#: ../roundup/admin.py:265
+#, python-format
+msgid "Sorry, no help for \"%(topic)s\""
+msgstr "Zum Thema \"%(topic)s\" existiert leider kein Hilfetext"
+
+# ../roundup/admin.py:336 :382
+#: ../roundup/admin.py:337 ../roundup/admin.py:386
+msgid "Templates:"
+msgstr "Vorlagen:"
+
+# ../roundup/admin.py:339 :393
+#: ../roundup/admin.py:340 ../roundup/admin.py:397
+msgid "Back ends:"
+msgstr "Datenbanken:"
+
+#: ../roundup/admin.py:343
+msgid ""
+"Usage: install [template [backend [admin password]]]\n"
+"        Install a new Roundup tracker.\n"
+"\n"
+"        The command will prompt for the tracker home directory\n"
+"        (if not supplied through TRACKER_HOME or the -i option).\n"
+"        The template, backend and admin password may be specified\n"
+"        on the command-line as arguments, in that order.\n"
+"\n"
+"        The initialise command must be called after this command in order\n"
+"        to initialise the tracker's database. You may edit the tracker's\n"
+"        initial database contents before running that command by editing\n"
+"        the tracker's dbinit.py module init() function.\n"
+"\n"
+"        See also initopts help.\n"
+"        "
+msgstr ""
+"Verwendung: install [Vorlage [Datenbanktyp [Administratorpasswort]]]\n"
+"        Installiert einen neuen Roundup-Tracker.\n"
+"\n"
+"        Sie werden aufgefordert, ein Tracker-Verzeichnis zu wählen\n"
+"        (falls Sie keines mit TRACKER_HOME oder -i angegeben haben),\n"
+"        sowie eine Vorlage, den Datenbanktyp und das Administrations-\n"
+"        passwort anzugeben.\n"
+"        Sie können die Vorlage, den Datenbanktyp und das Passwort\n"
+"        auch in dieser Reihenfolge auf der Kommandozeile angegen.\n"
+"\n"
+"        Nach der Installation müssen Sie die Datenbank mit dem Befehl \n"
+"        \"initialise\" einrichten. Zuvor können Sie in der Datei\n"
+"        \"dbinit.py\" die Funktion \"init()\" einen Anfangsbestand an\n"
+"        Daten programmieren.\n"
+"\n"
+"        Siehe auch unter dem Hilfethema \"initopts\".\n"
+"        "
+
+# ../roundup/admin.py:358 :483 :562 :612 :682 :703 :731 :802 :869 :940 :988
+# :1010 :1037 :1098 :1156
+#: ../roundup/admin.py:359 ../roundup/admin.py:441 ../roundup/admin.py:502
+#: ../roundup/admin.py:581 ../roundup/admin.py:631 ../roundup/admin.py:687
+#: ../roundup/admin.py:708 ../roundup/admin.py:736 ../roundup/admin.py:807
+#: ../roundup/admin.py:874 ../roundup/admin.py:945 ../roundup/admin.py:993
+#: ../roundup/admin.py:1015 ../roundup/admin.py:1042 ../roundup/admin.py:1104
+#: ../roundup/admin.py:1170
+msgid "Not enough arguments supplied"
+msgstr "Zu wenig Parameter übergeben"
+
+#: ../roundup/admin.py:365
+#, python-format
+msgid "Instance home parent directory \"%(parent)s\" does not exist"
+msgstr "Das angegebene Tracker-Verzeichnis \"%(parent)s\" existiert nicht"
+
+#: ../roundup/admin.py:373
+#, python-format
+msgid ""
+"WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
+"If you re-install it, you will lose all the data!\n"
+"Erase it? Y/N: "
+msgstr ""
+"WARNUNG: Im Verzeichnis \"%(tracker_home)s\" scheint bereits ein Tracker\n"
+"installiert zu sein! Eine erneute Installation löscht sämtliche Daten!\n"
+"Wirklich löschen? Y/N: "
+
+#: ../roundup/admin.py:388
+msgid "Select template [classic]: "
+msgstr "Template auswählen [classic]:"
+
+#: ../roundup/admin.py:399
+msgid "Select backend [anydbm]: "
+msgstr "Datenbank auswählen [anydbm]"
+
+#: ../roundup/admin.py:408
+#, python-format
+msgid ""
+"\n"
+" You should now edit the tracker configuration file:\n"
+"   %(config_file)s"
+msgstr ""
+"\n"
+" Sie sollten nun die Konfigurationsdatei des Trackers bearbeiten:\n"
+"   %(config_file)s"
+
+#: ../roundup/admin.py:417
+msgid " ... at a minimum, you must set following options:"
+msgstr " ... passen sie zumindest folgende Optionen an:"
+
+#: ../roundup/admin.py:422
+#, python-format
+msgid ""
+"\n"
+" If you wish to modify the database schema,\n"
+" you should also edit the schema file:\n"
+"   %(database_config_file)s\n"
+" You may also change the database initialisation file:\n"
+"   %(database_init_file)s\n"
+" ... see the documentation on customizing for more information.\n"
+msgstr ""
+"\n"
+" Um das Datenbank-Schema anzupassen, bearbeiten Sie die Datei:\n"
+"   %(database_config_file)s\n"
+" Sie können zudem auch den anfänglichen Datenbestand ändern:\n"
+"   %(database_init_file)s\n"
+" ... die Online-Dokumentation erhält ein eigenes Kapitel über Anpassungen.\n"
+
+#: ../roundup/admin.py:436
+msgid ""
+"Usage: genconfig <filename>\n"
+"        Generate a new tracker config file (ini style) with default values\n"
+"        in <filename>.\n"
+"        "
+msgstr ""
+"Verwendung: genconfig <filename>\n"
+"        Schreibt eine neue Tracker-Konfiguration (im \".ini\"-Format) mit \n"
+"        Vorgabe-Werten in die Datei <filename>.\n"
+"        "
+
+#. password
+#: ../roundup/admin.py:446
+msgid ""
+"Usage: initialise [adminpw]\n"
+"        Initialise a new Roundup tracker.\n"
+"\n"
+"        The administrator details will be set at this step.\n"
+"\n"
+"        Execute the tracker's initialisation function dbinit.init()\n"
+"        "
+msgstr ""
+"Verwendung: initialise [Administrationspasswort]\n"
+"        Initialisieren eines neuen Roundup-Trackers.\n"
+"\n"
+"        Der Administrator-Benutzer wird eingerichtet.\n"
+"\n"
+"        Die Funktion dbinit.init() wirf aufgerufen\n"
+"        "
+
+#: ../roundup/admin.py:460
+msgid "Admin Password: "
+msgstr "Admin Passwort: "
+
+#: ../roundup/admin.py:461
+msgid "       Confirm: "
+msgstr "    Bestätigen: "
+
+#: ../roundup/admin.py:465
+msgid "Instance home does not exist"
+msgstr "Tracker-Verzeichnis existiert nicht"
+
+#: ../roundup/admin.py:469
+msgid "Instance has not been installed"
+msgstr "Tracker-Instanz wurde nicht installiert"
+
+#: ../roundup/admin.py:474
+msgid ""
+"WARNING: The database is already initialised!\n"
+"If you re-initialise it, you will lose all the data!\n"
+"Erase it? Y/N: "
+msgstr ""
+"WARNUNG: Die Datenbank ist schon initialisiert!\n"
+"Eine erneute Initialisierung löscht sämtliche Daten!\n"
+"Wirklich löschen? Y/N: "
+
+#: ../roundup/admin.py:495
+msgid ""
+"Usage: get property designator[,designator]*\n"
+"        Get the given property of one or more designator(s).\n"
+"\n"
+"        Retrieves the property value of the nodes specified\n"
+"        by the designators.\n"
+"        "
+msgstr ""
+"Verwendung: get Eigenschaft Bezeichner[,Bezeichner]*\n"
+"        Gibt die Eigenschaft eines oder mehrerer Einträge zurück.\n"
+"\n"
+"        Diese Funktion zeigt Ihnen die Werte einer bestimmten\n"
+"        Eigenschaft der gewünschten Einträge an.\n"
+"        "
+
+# ../roundup/admin.py:516 :531
+#: ../roundup/admin.py:535 ../roundup/admin.py:550
+#, python-format
+msgid "property %s is not of type Multilink or Link so -d flag does not apply."
+msgstr ""
+"Die Eigenschaft %s ist kein Multilink oder Link. Das Option -d trifft "
+"deshalb hier nicht zu."
+
+# ../roundup/admin.py:539 :951 :1000 :1022
+#: ../roundup/admin.py:558 ../roundup/admin.py:956 ../roundup/admin.py:1005
+#: ../roundup/admin.py:1027
+#, python-format
+msgid "no such %(classname)s node \"%(nodeid)s\""
+msgstr ""
+"Es existiert kein Eintrag der Klasse %(classname)s mit der ID \"%(nodeid)s\""
+
+#: ../roundup/admin.py:560
+#, python-format
+msgid "no such %(classname)s property \"%(propname)s\""
+msgstr ""
+"Die Eigenschaft \"%(propname)s\" ist nicht definiert für die Klasse \"%"
+"(classname)s\""
+
+#: ../roundup/admin.py:569
+msgid ""
+"Usage: set items property=value property=value ...\n"
+"        Set the given properties of one or more items(s).\n"
+"\n"
+"        The items are specified as a class or as a comma-separated\n"
+"        list of item designators (ie \"designator[,designator,...]\").\n"
+"\n"
+"        This command sets the properties to the values for all designators\n"
+"        given. If the value is missing (ie. \"property=\") then the "
+"property\n"
+"        is un-set. If the property is a multilink, you specify the linked\n"
+"        ids for the multilink as comma-separated numbers (ie \"1,2,3\").\n"
+"        "
+msgstr ""
+"Verwendung: set Einträge Eigenschaft=Wert Eigenschaft=Wert ...\n"
+"        Bearbeitet den Eigenschaftswert eines oder mehrerer Einträge.\n"
+"\n"
+"        Für \"Einträge\" können Sie eine Klasse angeben, oder eine Liste\n"
+"        von einem oder mehreren kommagetrennten Bezeichnern aufgeführen\n"
+"        (\"Bezeichner[,Bezeichner]*\").\n"
+"\n"
+"        Der Wert der Eigenschaft wird für alle angegebenen Eintrge gesetzt.\n"
+"        Wenn der Wert fehlt (Eigenschaft=), wird die Eigenschaft gelöscht.\n"
+"        Wenn die Eigenschaft ein Link/Multilink ist, werden die verlinkten\n"
+"        Einträge als kommagetrennte ID-Nummern angegeben (\"1,2,3\").\n"
+"        "
+
+#: ../roundup/admin.py:623
+msgid ""
+"Usage: find classname propname=value ...\n"
+"        Find the nodes of the given class with a given link property value.\n"
+"\n"
+"        Find the nodes of the given class with a given link property value.\n"
+"        The value may be either the nodeid of the linked node, or its key\n"
+"        value.\n"
+"        "
+msgstr ""
+"Verwendung: find Klassenname Eigenschaft=Wert ...\n"
+"        Findet Einträge, welche die angegebene Verlinkung aufweisen.\n"
+"\n"
+"        Findet sämtliche Einträge einer Klasse, bei welchen die Link-\n"
+"        Eigenschaft den angegebenen Wert enthält. Der Wert kann entweder\n"
+"        als ID oder als Bezeichner (\"msg23\") spezifiziert werden.\n"
+"        "
+
+# ../roundup/admin.py:631 :669 :822 :834 :888
+#: ../roundup/admin.py:674 ../roundup/admin.py:827 ../roundup/admin.py:839
+#: ../roundup/admin.py:893
+#, python-format
+msgid "%(classname)s has no property \"%(propname)s\""
+msgstr "Die Klasse \"%(classname)s\" hat keine Eigenschaft \"%(propname)s\""
+
+#: ../roundup/admin.py:681
+msgid ""
+"Usage: specification classname\n"
+"        Show the properties for a classname.\n"
+"\n"
+"        This lists the properties for a given class.\n"
+"        "
+msgstr ""
+"Verwendung: specification Klassenname\n"
+"        Gibt die Spezifikation der Klasseneigenschaften aus.\n"
+"\n"
+"        Listet sämtliche Eigenschaften der Klasse auf.\n"
+"        "
+
+#: ../roundup/admin.py:696
+#, python-format
+msgid "%(key)s: %(value)s (key property)"
+msgstr "%(key)s: %(value)s (Schlüsseleigenschaft)"
+
+#: ../roundup/admin.py:698
+#, python-format
+msgid "%(key)s: %(value)s"
+msgstr "%(key)s: %(value)s"
+
+#: ../roundup/admin.py:701
+msgid ""
+"Usage: display designator[,designator]*\n"
+"        Show the property values for the given node(s).\n"
+"\n"
+"        This lists the properties and their associated values for the given\n"
+"        node.\n"
+"        "
+msgstr ""
+"Verwendung: display Bezeichner[,Bezeichner]*\n"
+"        Zeigt alle Eigenschaften eines oder mehrerer Eintrage an.\n"
+"\n"
+"        Der Befehl listet sämtliche Eigenschaften und Ihre Werte des\n"
+"        Eintrages an.\n"
+"        "
+
+#: ../roundup/admin.py:725
+#, python-format
+msgid "%(key)s: %(value)r"
+msgstr "%(key)s: %(value)r"
+
+#: ../roundup/admin.py:728
+msgid ""
+"Usage: create classname property=value ...\n"
+"        Create a new entry of a given class.\n"
+"\n"
+"        This creates a new entry of the given class using the property\n"
+"        name=value arguments provided on the command line after the \"create"
+"\"\n"
+"        command.\n"
+"        "
+msgstr ""
+"Verwendung: create Klassenname Eigenschaft=Wert ...\n"
+"        Erstellt einen neuen Eintrag der angegebenen Klasse.\n"
+"\n"
+"        Ein neuer Eintrag der Klasse wird erstellt und die Eigenschaften\n"
+"        werden mit den Werten initialisiert\n"
+"        "
+
+#: ../roundup/admin.py:755
+#, python-format
+msgid "%(propname)s (Password): "
+msgstr "%(propname)s (Passwort):"
+
+#: ../roundup/admin.py:757
+#, python-format
+msgid "   %(propname)s (Again): "
+msgstr "   %(propname)s (Wiederholen):"
+
+#: ../roundup/admin.py:759
+msgid "Sorry, try again..."
+msgstr "Bitte erneut versuchen..."
+
+#: ../roundup/admin.py:763
+#, python-format
+msgid "%(propname)s (%(proptype)s): "
+msgstr "%(propname)s (%(proptype)s): "
+
+#: ../roundup/admin.py:781
+#, python-format
+msgid "you must provide the \"%(propname)s\" property."
+msgstr "Sie müssen die Eigenschaft \"%(propname)s\" angeben."
+
+#: ../roundup/admin.py:792
+msgid ""
+"Usage: list classname [property]\n"
+"        List the instances of a class.\n"
+"\n"
+"        Lists all instances of the given class. If the property is not\n"
+"        specified, the  \"label\" property is used. The label property is\n"
+"        tried in order: the key, \"name\", \"title\" and then the first\n"
+"        property, alphabetically.\n"
+"\n"
+"        With -c, -S or -s print a list of item id's if no property\n"
+"        specified.  If property specified, print list of that property\n"
+"        for every class instance.\n"
+"        "
+msgstr ""
+"Usage: list Klassenname [Eigenschaft]\n"
+"        Listet sämtliche Einträge einer Klasse auf.\n"
+"\n"
+"        Es werden sämtliche Einträge der Klasse ausgegeben. Wird keine\n"
+"        Eigenschaft angegeben, so wird ein Bezeichner verwendet. Falls ein\n"
+"        Schlüsselfeld existiert, wird dieses ausgegeben, sonst ein Feld "
+"namens \n"
+"        \"name\" oder \"title\". Falls auch diese Felder nicht existieren, "
+"wird \n"
+"        erste Feld alphabetisch sortiert angezeigt.\n"
+"\n"
+"        Mit den Optionen -c, -S or -s wird eine Liste von ID's ausgegeben,\n"
+"        falls keine Eigenschaft angegeben wird. Sonst werden die Werte\n"
+"        dieser Eigenschaften sämtlicher Instanzen dieser Klasse "
+"aufgelistet.\n"
+"        "
+
+#: ../roundup/admin.py:805
+msgid "Too many arguments supplied"
+msgstr "Sie haben zuviele Argumente übergeben"
+
+#: ../roundup/admin.py:841
+#, python-format
+msgid "%(nodeid)4s: %(value)s"
+msgstr "%(nodeid)4s: %(value)s"
+
+#: ../roundup/admin.py:845
+msgid ""
+"Usage: table classname [property[,property]*]\n"
+"        List the instances of a class in tabular form.\n"
+"\n"
+"        Lists all instances of the given class. If the properties are not\n"
+"        specified, all properties are displayed. By default, the column\n"
+"        widths are the width of the largest value. The width may be\n"
+"        explicitly defined by defining the property as \"name:width\".\n"
+"        For example::\n"
+"\n"
+"          roundup> table priority id,name:10\n"
+"          Id Name\n"
+"          1  fatal-bug\n"
+"          2  bug\n"
+"          3  usability\n"
+"          4  feature\n"
+"\n"
+"        Also to make the width of the column the width of the label,\n"
+"        leave a trailing : without a width on the property. For example::\n"
+"\n"
+"          roundup> table priority id,name:\n"
+"          Id Name\n"
+"          1  fata\n"
+"          2  bug\n"
+"          3  usab\n"
+"          4  feat\n"
+"\n"
+"        will result in a the 4 character wide \"Name\" column.\n"
+"        "
+msgstr ""
+"Verwendung: table Klassenname [Eigenschaft[,Eigenschaft]*]\n"
+"        Listet die Einträge einer Klasse in tabelarischer Form.\n"
+"\n"
+"        Gibt eine Liste sämtlicher Instanzen einer Klasse aus.\n"
+"        Werden die Eigenschaften nicht explizit angegeben, so werden\n"
+"        alle angezeigt. Die Spaltenbreite wird automatisch nach dem \n"
+"        grössten Wert jeder Spalte berechnet, oder sie kann explizit\n"
+"        angegeben als \"Eigenschaft:Breite\"\n"
+"        Beispiel:\n"
+"\n"
+"          roundup> table priority id,name:10\n"
+"          Id Name\n"
+"          1  fatal-bug\n"
+"          2  bug\n"
+"          3  usability\n"
+"          4  feature\n"
+"\n"
+"        Um die Spaltenbreite auf die Grösse des Spaltentitels zu "
+"bechränken,\n"
+"        lassen Sie die Breitenangabe hinter dem : weg.\n"
+"        Beispiel:\n"
+"\n"
+"          roundup> table priority id,name:\n"
+"          Id Name\n"
+"          1  fata\n"
+"          2  bug\n"
+"          3  usab\n"
+"          4  feat\n"
+"\n"
+"        "
+
+#: ../roundup/admin.py:889
+#, python-format
+msgid "\"%(spec)s\" not name:width"
+msgstr "\"%(spec)s\" entspricht nicht dem Format Eigenschaft:Breite"
+
+#: ../roundup/admin.py:939
+msgid ""
+"Usage: history designator\n"
+"        Show the history entries of a designator.\n"
+"\n"
+"        Lists the journal entries for the node identified by the "
+"designator.\n"
+"        "
+msgstr ""
+"Verwendung: history Bezeichner\n"
+"        Zeigt den Verlauf eines Eintrages an.\n"
+"\n"
+"        Listet das Bearbeitungs-Journal des Eintrages mit dem angegebenen\n"
+"        Bezeichner auf.\n"
+"        "
+
+#: ../roundup/admin.py:960
+msgid ""
+"Usage: commit\n"
+"        Commit changes made to the database during an interactive session.\n"
+"\n"
+"        The changes made during an interactive session are not\n"
+"        automatically written to the database - they must be committed\n"
+"        using this command.\n"
+"\n"
+"        One-off commands on the command-line are automatically committed if\n"
+"        they are successful.\n"
+"        "
+msgstr ""
+"Verwendung: commit\n"
+"        Speichern der Datenbank-Änderungen.\n"
+"\n"
+"        Falls die Datenbank Transaktionen unterstützt, werden Änderungen\n"
+"        während einer Bearbeitungs-Session erst nach einem \"commit\" an "
+"die\n"
+"        Datenbank übermittelt.\n"
+"\n"
+"        Einzelbefehle über die Kommandozeile werden sofort in die Datenbank\n"
+"        geschrieben.\n"
+"        "
+
+#: ../roundup/admin.py:974
+msgid ""
+"Usage: rollback\n"
+"        Undo all changes that are pending commit to the database.\n"
+"\n"
+"        The changes made during an interactive session are not\n"
+"        automatically written to the database - they must be committed\n"
+"        manually. This command undoes all those changes, so a commit\n"
+"        immediately after would make no changes to the database.\n"
+"        "
+msgstr ""
+"Verwendung: rollback\n"
+"        Sämtliche nicht gespeicherte Änderungen werden verworfen.\n"
+"\n"
+"        Falls die Datenbank Transaktionen unterstützt, werden dadurch\n"
+"        sämtliche noch nicht gespeicherte Änderungen (siehe \"commit\")\n"
+"        verworfen.\n"
+"        "
+
+#: ../roundup/admin.py:986
+msgid ""
+"Usage: retire designator[,designator]*\n"
+"        Retire the node specified by designator.\n"
+"\n"
+"        This action indicates that a particular node is not to be retrieved\n"
+"        by the list or find commands, and its key value may be re-used.\n"
+"        "
+msgstr ""
+"Verwendung: retire Bezeichner[,Bezeichner]*\n"
+"        Verbirgt einen oder mehrere Einträge.\n"
+"\n"
+"        Das Verbergen eines Eintrages bewirkt, dass dieser bei einer Suche\n"
+"        nicht mehr angezeigt wird. Der Schlüssel des verborgenen Eintrages\n"
+"        kann zudem wiederverwendet werden.\n"
+"        "
+
+#: ../roundup/admin.py:1009
+msgid ""
+"Usage: restore designator[,designator]*\n"
+"        Restore the retired node specified by designator.\n"
+"\n"
+"        The given nodes will become available for users again.\n"
+"        "
+msgstr ""
+"Verwendung: restore Bezeichner[,Bezeichner]*\n"
+"        Ein oder mehrere verborgene Einträge werden wieder hergestellt.\n"
+"\n"
+"        Ein verborgener Eintrag wird wieder hergestellt und ist danach\n"
+"        für die Benutzer wieder sichtbar.\n"
+"        "
+
+#. grab the directory to export to
+#: ../roundup/admin.py:1031
+msgid ""
+"Usage: export [class[,class]] export_dir\n"
+"        Export the database to colon-separated-value files.\n"
+"\n"
+"        Optionally limit the export to just the names classes.\n"
+"\n"
+"        This action exports the current data from the database into\n"
+"        colon-separated-value files that are placed in the nominated\n"
+"        destination directory.\n"
+"        "
+msgstr ""
+"Verwendung: export [Klasse[,Klasse]] Exportverzeichnis\n"
+"        Exportiert die Datenbank in ein Verzeichnis mit CSV-Dateien.\n"
+"\n"
+"        Optional kann der Export auf gewisse Klassen beschränkt werden.\n"
+"\n"
+"        Die Daten werden als kommagetrennte Dateien in das angegebene\n"
+"        Exportverzeichnis geschrieben.\n"
+"        "
+
+#: ../roundup/admin.py:1084
+msgid ""
+"Usage: import import_dir\n"
+"        Import a database from the directory containing CSV files,\n"
+"        two per class to import.\n"
+"\n"
+"        The files used in the import are:\n"
+"\n"
+"        <class>.csv\n"
+"          This must define the same properties as the class (including\n"
+"          having a \"header\" line with those property names.)\n"
+"        <class>-journals.csv\n"
+"          This defines the journals for the items being imported.\n"
+"\n"
+"        The imported nodes will have the same nodeid as defined in the\n"
+"        import file, thus replacing any existing content.\n"
+"\n"
+"        The new nodes are added to the existing database - if you want to\n"
+"        create a new database using the imported data, then create a new\n"
+"        database (or, tediously, retire all the old data.)\n"
+"        "
+msgstr ""
+"Verwendung: import Importverzeichnis\n"
+"        Importiert Datensätze aus einem Verzeichnis mit CSV-Dateien\n"
+"\n"
+"        Folgende Dateien werden beim Import verwendet:\n"
+"\n"
+"        <Klasse>.csv\n"
+"          In dieser Datei sind die Daten zu den Einträgen einer Klasse.\n"
+"          Für sämtliche Eigenschaften der Klasse muss eine Spalte \n"
+"          exisitieren. In der ersten Zeile stehen die Eigenschaftsnamen.\n"
+"        <Klasse>-journals.csv\n"
+"          In dieser Datei wird der Bearbeitungs-Verlauf der Einträge\n"
+"          beschrieben.\n"
+"\n"
+"        Importierte Einträge übernehmen die ID's, welche in den Dateien\n"
+"        definiert sind. Existierende Einträge mit denselben ID's werden\n"
+"        überschrieben.\n"
+"        Die Einträge werden in die existierende Datenbank geschrieben.\n"
+"        Falls eine neue, leere Datenbank verwendet werden soll, so müssen\n"
+"        Sie diese zuerst erstellen (oder sämtliche bestehenden Inhalte \n"
+"        verbergen).\n"
+"        "
+
+#: ../roundup/admin.py:1152
+msgid ""
+"Usage: pack period | date\n"
+"\n"
+"        Remove journal entries older than a period of time specified or\n"
+"        before a certain date.\n"
+"\n"
+"        A period is specified using the suffixes \"y\", \"m\", and \"d\". "
+"The\n"
+"        suffix \"w\" (for \"week\") means 7 days.\n"
+"\n"
+"              \"3y\" means three years\n"
+"              \"2y 1m\" means two years and one month\n"
+"              \"1m 25d\" means one month and 25 days\n"
+"              \"2w 3d\" means two weeks and three days\n"
+"\n"
+"        Date format is \"YYYY-MM-DD\" eg:\n"
+"            2001-01-01\n"
+"\n"
+"        "
+msgstr ""
+"Verwendung: pack Periode | Datum\n"
+"        Entfernt den Bearbeitungsverlauf ab einem gewissen Datum.\n"
+"\n"
+"        Das Datum kann als rückläufige Periode spezifiziert werden:\n"
+"           \"y\", \"m\", and \"d\".         wobei \"w\" (Woche) für 7 Tage "
+"steht.\n"
+"\n"
+"        Beispiele:\n"
+"              \"3y\" steht für 3 Jahre\n"
+"              \"2y 1m\" steht für 2 Jahre und ein Monat\n"
+"              \"1m 25d\" steht für 1 Monat und 25 Tage\n"
+"              \"2w 3d\" steht für 2 Wochen und 3 Tage\n"
+"\n"
+"        Das Datumsformat lautet \"JJJJ-MM-TT\", z.B:\n"
+"            2001-06-27\n"
+"\n"
+"        "
+
+#: ../roundup/admin.py:1180
+msgid "Invalid format"
+msgstr "Ungültiges Format"
+
+#: ../roundup/admin.py:1190
+msgid ""
+"Usage: reindex [classname|designator]*\n"
+"        Re-generate a tracker's search indexes.\n"
+"\n"
+"        This will re-generate the search indexes for a tracker.\n"
+"        This will typically happen automatically.\n"
+"        "
+msgstr ""
+"Verwendung: reindex [Klasse|Bezeichner]*\n"
+"        Der Volltext-Index eines Trackers wird neu erstellt.\n"
+"\n"
+"        Der Volltext-Index wird neu generiert. Dieser Prozess geschieht \n"
+"        normalerweise automatisch.\n"
+"        "
+
+#: ../roundup/admin.py:1204
+#, python-format
+msgid "no such item \"%(designator)s\""
+msgstr "Der Eintrag \"%(designator)s\" existiert nicht"
+
+#: ../roundup/admin.py:1214
+msgid ""
+"Usage: security [Role name]\n"
+"        Display the Permissions available to one or all Roles.\n"
+"        "
+msgstr ""
+"Verwendung: security [Rollenname]\n"
+"        Zeigt die Berechtigungen einer oder aller Rollen an.\n"
+"        "
+
+#: ../roundup/admin.py:1222
+#, python-format
+msgid "No such Role \"%(role)s\""
+msgstr "Die Rolle \"%(role)s\" existiert nicht "
+
+#: ../roundup/admin.py:1228
+#, python-format
+msgid "New Web users get the Roles \"%(role)s\""
+msgstr "Neue Web-Benutzer erhalten die Rollen \"%(role)s\""
+
+#: ../roundup/admin.py:1230
+#, python-format
+msgid "New Web users get the Role \"%(role)s\""
+msgstr "Neue Web-Benutzer erhalten die Rolle \"%(role)s\""
+
+#: ../roundup/admin.py:1233
+#, python-format
+msgid "New Email users get the Roles \"%(role)s\""
+msgstr "Neue Email-Benutzer erhalten die Rollen \"%(role)s\""
+
+#: ../roundup/admin.py:1235
+#, python-format
+msgid "New Email users get the Role \"%(role)s\""
+msgstr "Neue Email-Benutzer erhalten die Rolle \"%(role)s\""
+
+#: ../roundup/admin.py:1238
+#, python-format
+msgid "Role \"%(name)s\":"
+msgstr "Rolle \"%(name)s\":"
+
+#: ../roundup/admin.py:1241
+#, python-format
+msgid " %(description)s (%(name)s for \"%(klass)s\" only)"
+msgstr "%(description)s (%(name)s einzig für \"%(klass)s\")"
+
+#: ../roundup/admin.py:1244
+#, python-format
+msgid " %(description)s (%(name)s)"
+msgstr " %(description)s (%(name)s)"
+
+#: ../roundup/admin.py:1273
+#, python-format
+msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
+msgstr "Der Befehl \"%(command)s\" existiert nicht (siehe \"help commands\")"
+
+#: ../roundup/admin.py:1279
+#, python-format
+msgid "Multiple commands match \"%(command)s\": %(list)s"
+msgstr "Zur Abkürzung \"%(command)s\" passen mehrere Befehle: %(list)s"
+
+#: ../roundup/admin.py:1286
+msgid "Enter tracker home: "
+msgstr "Tracker-Verzeichnis: "
+
+# ../roundup/admin.py:1263 :1269 :1289
+#: ../roundup/admin.py:1293 ../roundup/admin.py:1299 ../roundup/admin.py:1319
+#, python-format
+msgid "Error: %(message)s"
+msgstr "Fehler: %(message)s"
+
+#: ../roundup/admin.py:1307
+#, python-format
+msgid "Error: Couldn't open tracker: %(message)s"
+msgstr "Fehler: Die Tracker-Instanz konnte nicht geöffnet werden: %(message)s"
+
+#: ../roundup/admin.py:1332
+#, python-format
+msgid ""
+"Roundup %s ready for input.\n"
+"Type \"help\" for help."
+msgstr ""
+"Roundup %s ist bereit.\n"
+"Schreiben Sie \"help\", um zur Hilfe zu gelangen."
+
+#: ../roundup/admin.py:1337
+msgid "Note: command history and editing not available"
+msgstr "Bemerkung: Befehlsverlauf/-bearbeitung nicht verfügbar"
+
+#: ../roundup/admin.py:1341
+msgid "roundup> "
+msgstr "roundup> "
+
+#: ../roundup/admin.py:1343
+msgid "exit..."
+msgstr "beenden..."
+
+#: ../roundup/admin.py:1353
+msgid "There are unsaved changes. Commit them (y/N)? "
+msgstr "Es gibt noch ungespeicherte Änderungen. Änderungen speichern (y/N)?"
+
+#: ../roundup/backends/back_anydbm.py:2054
+#, python-format
+msgid "WARNING: invalid date tuple %r"
+msgstr "WARNUNG: ungültiges Datums-Tupel %r"
+
+#: ../roundup/backends/rdbms_common.py:1425
+msgid "create"
+msgstr "erstellt"
+
+#: ../roundup/backends/rdbms_common.py:1588
+msgid "unlink"
+msgstr "link gelöscht"
+
+#: ../roundup/backends/rdbms_common.py:1592
+msgid "link"
+msgstr "verlinkt"
+
+#: ../roundup/backends/rdbms_common.py:1702
+msgid "set"
+msgstr "geändert"
+
+#: ../roundup/backends/rdbms_common.py:1726
+msgid "retired"
+msgstr "verborgen"
+
+#: ../roundup/backends/rdbms_common.py:1756
+msgid "restored"
+msgstr "wiederhergestellt"
+
+#: ../roundup/cgi/actions.py:58
+#, python-format
+msgid "You do not have permission to %(action)s the %(classname)s class."
+msgstr ""
+"Sie haben keine Berechtigung um die Aktion %(action)s auf die Klasse%"
+"(classname)s anzuwenden."
+
+#: ../roundup/cgi/actions.py:89
+msgid "No type specified"
+msgstr "Typ nicht spezifiziert"
+
+#: ../roundup/cgi/actions.py:91
+msgid "No ID entered"
+msgstr "Keine ID spezifiziert"
+
+#: ../roundup/cgi/actions.py:97
+#, python-format
+msgid "\"%(input)s\" is not an ID (%(classname)s ID required)"
+msgstr "\"%(input)s\" ist keine ID (%(classname)s ID wird erwartet)"
+
+#: ../roundup/cgi/actions.py:117
+msgid "You may not retire the admin or anonymous user"
+msgstr "Sie können den Administrator oder den Gast-Benutzer nicht löschen"
+
+#: ../roundup/cgi/actions.py:124
+#, python-format
+msgid "%(classname)s %(itemid)s has been retired"
+msgstr "%(classname)s %(itemid)s wurde gelöscht"
+
+#: ../roundup/cgi/actions.py:279
+#, python-format
+msgid "Not enough values on line %(line)s"
+msgstr "Nicht genügend Werte auf Zeile %(line)s"
+
+#: ../roundup/cgi/actions.py:326
+msgid "Items edited OK"
+msgstr "Die Einträge wurden aktualisiert"
+
+#: ../roundup/cgi/actions.py:386
+#, python-format
+msgid "%(class)s %(id)s %(properties)s edited ok"
+msgstr "Eigenschaft \"%(properties)s\" bei \"%(class)s %(id)s\" bearbeitet"
+
+#: ../roundup/cgi/actions.py:389
+#, python-format
+msgid "%(class)s %(id)s - nothing changed"
+msgstr "%(class)s %(id)s - keine Änderungen"
+
+#: ../roundup/cgi/actions.py:401
+#, python-format
+msgid "%(class)s %(id)s created"
+msgstr "Der Eintrag \"%(class)s %(id)s\" wurde erstellt"
+
+#: ../roundup/cgi/actions.py:433
+#, python-format
+msgid "You do not have permission to edit %(class)s"
+msgstr ""
+"Sie haben keine Berechtigung die Einträge der Klasse \"%(class)s\" zu "
+"bearbeiten"
+
+#: ../roundup/cgi/actions.py:445
+#, python-format
+msgid "You do not have permission to create %(class)s"
+msgstr ""
+"Sie haben keine Berechtigung um Einträge der Klasse \"%(class)s\" zu "
+"erstellen"
+
+#: ../roundup/cgi/actions.py:468
+msgid "You do not have permission to edit user roles"
+msgstr "Sie haben keine Berechtigung Benutzer-Rollen zu ändern"
+
+#: ../roundup/cgi/actions.py:530
+#, python-format
+msgid "Edit Error: %s"
+msgstr "Fehler bei der Bearbeitung: %s"
+
+# ../roundup/cgi/actions.py:546 :556
+#: ../roundup/cgi/actions.py:561 ../roundup/cgi/actions.py:572
+#: ../roundup/cgi/actions.py:743 ../roundup/cgi/actions.py:762
+#, python-format
+msgid "Error: %s"
+msgstr "Fehler: %s"
+
+#: ../roundup/cgi/actions.py:598
+msgid ""
+"Invalid One Time Key!\n"
+"(a Mozilla bug may cause this message to show up erroneously, please check "
+"your email)"
+msgstr ""
+"Ungültiger Authentifizierungscode!\n"
+"(Ein Fehler in Mozilla kann diese Meldung hervorrufen, bitte prüfen Sie Ihr "
+"Email-Konto)"
+
+#: ../roundup/cgi/actions.py:640
+#, python-format
+msgid "Password reset and email sent to %s"
+msgstr "Ihr Passwort wurde zurückgesetzt und per Email an %s versandt"
+
+#: ../roundup/cgi/actions.py:649
+msgid "Unknown username"
+msgstr "Benutzername unbekannt"
+
+#: ../roundup/cgi/actions.py:657
+msgid "Unknown email address"
+msgstr "Email-Adresse unbekannt"
+
+#: ../roundup/cgi/actions.py:662
+msgid "You need to specify a username or address"
+msgstr "Sie müssen einen Benutzernamen oder eine Email-Adresse angeben"
+
+#: ../roundup/cgi/actions.py:687
+#, python-format
+msgid "Email sent to %s"
+msgstr "Eine Email wurde an %s versandt"
+
+#: ../roundup/cgi/actions.py:706
+msgid "You are now registered, welcome!"
+msgstr "Sie sind nun registriert. Willkommen!"
+
+#: ../roundup/cgi/actions.py:751
+msgid "It is not permitted to supply roles at registration."
+msgstr "Bei der Registrierung dürfen keine Rollen angegeben werden"
+
+#: ../roundup/cgi/actions.py:834
+msgid "You are logged out"
+msgstr "Sie wurden vom System abgemeldet"
+
+#: ../roundup/cgi/actions.py:845
+msgid "Username required"
+msgstr "Benutzername notwendig"
+
+#: ../roundup/cgi/actions.py:873 ../roundup/cgi/actions.py:877
+msgid "Invalid login"
+msgstr "Ungültiges Login"
+
+#: ../roundup/cgi/actions.py:883
+msgid "You do not have permission to login"
+msgstr "Sie haben keine Berechtigung sich anzumelden"
+
+#: ../roundup/cgi/cgitb.py:49
+#, python-format
+msgid ""
+"<h1>Templating Error</h1>\n"
+"<p><b>%(exc_type)s</b>: %(exc_value)s</p>\n"
+"<p class=\"help\">Debugging information follows</p>"
+msgstr ""
+"<h1>Templating Fehler</h1>\n"
+"<p><b>%(exc_type)s</b>: %(exc_value)s</p>\n"
+"<p class=\"help\">Es folgen Informationen zum Fehler</p>"
+
+#: ../roundup/cgi/cgitb.py:64
+#, python-format
+msgid "<li>\"%(name)s\" (%(info)s)</li>"
+msgstr "<li>\"%(name)s\" (%(info)s)</li>"
+
+#: ../roundup/cgi/cgitb.py:67
+#, python-format
+msgid "<li>Looking for \"%(name)s\", current path:<ol>%(path)s</ol></li>"
+msgstr "<li>Looking for \"%(name)s\", current path:<ol>%(path)s</ol></li>"
+
+#: ../roundup/cgi/cgitb.py:71
+#, python-format
+msgid "<li>In %s</li>"
+msgstr "<li>In %s</li>"
+
+#: ../roundup/cgi/cgitb.py:76
+#, python-format
+msgid "A problem occurred in your template \"%s\"."
+msgstr "Ein Problem ist im Template \"%s\" aufgetreten."
+
+#: ../roundup/cgi/cgitb.py:84
+#, python-format
+msgid ""
+"\n"
+"<li>While evaluating the %(info)r expression on line %(line)d\n"
+"<table class=\"otherinfo\" style=\"font-size: 90%%\">\n"
+" <tr><th colspan=\"2\" class=\"header\">Current variables:</th></tr>\n"
+" %(globals)s\n"
+" %(locals)s\n"
+"</table></li>\n"
+msgstr ""
+"\n"
+"<li>Beim Ausführen von %(info)r auf Zeile %(line)d\n"
+"<table class=\"otherinfo\" style=\"font-size: 90%%\">\n"
+" <tr><th colspan=\"2\" class=\"header\">Aktuelle Variablen:</th></tr>\n"
+" %(globals)s\n"
+" %(locals)s\n"
+"</table></li>\n"
+
+#: ../roundup/cgi/cgitb.py:103
+msgid "Full traceback:"
+msgstr "Vollständiger Traceback:"
+
+#: ../roundup/cgi/cgitb.py:116
+#, python-format
+msgid "<font size=+1><strong>%(exc_type)s</strong>: %(exc_value)s</font>"
+msgstr "<font size=+1><strong>%(exc_type)s</strong>: %(exc_value)s</font>"
+
+#: ../roundup/cgi/cgitb.py:120
+msgid ""
+"<p>A problem occurred while running a Python script. Here is the sequence of "
+"function calls leading up to the error, with the most recent (innermost) "
+"call first. The exception attributes are:"
+msgstr ""
+"<p>Ein Problem trat auf, als ein Python-Script ausgeführt wurde. Hier sehen "
+"Sie die Aufrufe, welche zu einem Fehler führten. Der letzten Aufruf erscheint "
+"zuoberst. Der Fehler hat folgende Attribute: "
+
+#: ../roundup/cgi/cgitb.py:129
+msgid "&lt;file is None - probably inside <tt>eval</tt> or <tt>exec</tt>&gt;"
+msgstr "&lt;file ist None - Wahrscheinlich in einem <tt>eval</tt> oder einem "
+"<tt>exec</tt>&gt;"
+
+#: ../roundup/cgi/cgitb.py:138
+#, python-format
+msgid "in <strong>%s</strong>"
+msgstr "in <strong>%s</strong>"
+
+# ../roundup/cgi/cgitb.py:145 :151
+#: ../roundup/cgi/cgitb.py:172 ../roundup/cgi/cgitb.py:178
+msgid "<em>undefined</em>"
+msgstr "<em>nicht definiert</em>"
+
+#: ../roundup/cgi/client.py:291
+msgid "Form Error: "
+msgstr "Formular-Fehler: "
+
+#: ../roundup/cgi/client.py:344
+#, python-format
+msgid "Unrecognized charset: %r"
+msgstr "Charset-Codierung nicht erkannt: %r"
+
+#: ../roundup/cgi/client.py:446
+msgid "Anonymous users are not allowed to use the web interface"
+msgstr ""
+"Gast-Benutzer haben nicht die Berechtigung, das Web-Interface zu benutzen."
+
+#: ../roundup/cgi/client.py:597
+msgid "You are not allowed to view this file."
+msgstr "Sie haben nicht die Berechtigung, diese Seite anzuzeigen."
+
+#: ../roundup/cgi/client.py:689
+#, python-format
+msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
+msgstr "%(starttag)sBenötigte Zeit: %(seconds)fs%(endtag)s\n"
+
+#: ../roundup/cgi/client.py:693
+#, python-format
+msgid ""
+"%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
+"items: %(get_items)f secs. Filtering: %(filtering)f secs.%(endtag)s\n"
+msgstr ""
+"%(starttag)sCache benutzt: %(cache_hits)d, verfehlt: %(cache_misses)d. " 
+"Einträge laden: %(get_items)fs; filtern: %(filtering)fs.%(endtag)s\n"
+
+#: ../roundup/cgi/form_parser.py:283
+#, python-format
+msgid "link \"%(key)s\" value \"%(value)s\" not a designator"
+msgstr ""
+"Der Wert \"%(value)s\" ist kein gültiger Bezeichner für die Verknüpfung \"%"
+"(key)s\""
+
+#: ../roundup/cgi/form_parser.py:290
+#, python-format
+msgid "%(class)s %(property)s is not a link or multilink property"
+msgstr "%(class)s %(property)s ist weder ein Link noch ein Mehrfachlink"
+
+#: ../roundup/cgi/form_parser.py:312
+#, python-format
+msgid ""
+"You have submitted a %(action)s action for the property \"%(property)s\" "
+"which doesn't exist"
+msgstr "Die Aktion %(action)s gilt nicht für die Eigenschaft \"%(property)s\" "
+
+# ../roundup/cgi/form_parser.py:331 :357
+#: ../roundup/cgi/form_parser.py:331 ../roundup/cgi/form_parser.py:357
+#, python-format
+msgid "You have submitted more than one value for the %s property"
+msgstr "Sie haben mehr als einen Wert für die Eigenschaft \"%s\" übermittelt"
+
+# ../roundup/cgi/form_parser.py:354 :360
+#: ../roundup/cgi/form_parser.py:354 ../roundup/cgi/form_parser.py:360
+msgid "Password and confirmation text do not match"
+msgstr "Die beiden Passwort-Felder stimmen nicht überein"
+
+#: ../roundup/cgi/form_parser.py:395
+#, python-format
+msgid "property \"%(propname)s\": \"%(value)s\" not currently in list"
+msgstr "Der Wert \"%(value)s\" ist nicht in der Liste für \"%(propname)s\""
+
+#: ../roundup/cgi/form_parser.py:509
+#, python-format
+msgid "Required %(class)s property %(property)s not supplied"
+msgid_plural "Required %(class)s properties %(property)s not supplied"
+msgstr[0] ""
+"Die Eigenschaft \"%(property)s\" muss für die Klasse \"%(class)s\" angegeben "
+"werden"
+msgstr[1] ""
+"Die Eigenschaften \"%(property)s\" müssen für die Klasse \"%(class)s\" "
+"angegeben werden"
+
+#: ../roundup/cgi/form_parser.py:529
+msgid "File is empty"
+msgstr "Die ausgewählte Datei ist leer"
+
+#: ../roundup/cgi/templating.py:68
+#, python-format
+msgid "You are not allowed to %(action)s items of class %(class)s"
+msgstr ""
+"Sie haben keine Berechtigung, um die Aktion  \"%(action)s\" auf Einträge der "
+"Klasse \"%(class)s\" anzuwenden"
+
+#: ../roundup/cgi/templating.py:612
+msgid "(list)"
+msgstr "(Liste)"
+
+#: ../roundup/cgi/templating.py:646
+msgid "Submit New Entry"
+msgstr "Eintrag speichern"
+
+#: ../roundup/cgi/templating.py:656
+msgid "New node - no history"
+msgstr "Neuer Eintrag - Noch kein Verlauf"
+
+#: ../roundup/cgi/templating.py:756
+msgid "Submit Changes"
+msgstr "Speichern"
+
+#: ../roundup/cgi/templating.py:837
+msgid "<em>The indicated property no longer exists</em>"
+msgstr "<em>Die gewählte Eigenschaft existiert nicht mehr</em>"
+
+#: ../roundup/cgi/templating.py:838
+#, python-format
+msgid "<em>%s: %s</em>\n"
+msgstr "<em>%s: %s</em>\n"
+
+#: ../roundup/cgi/templating.py:851
+#, python-format
+msgid "The linked class %(classname)s no longer exists"
+msgstr "Die verlinkte Klasse \"%(classname)s\" existiert nicht mehr"
+
+# ../roundup/cgi/templating.py:905 :926
+#: ../roundup/cgi/templating.py:884 ../roundup/cgi/templating.py:905
+msgid "<strike>The linked node no longer exists</strike>"
+msgstr "<strike>Der verknüpfte Eintrag existiert nicht mehr</strike>"
+
+#: ../roundup/cgi/templating.py:944
+msgid "No"
+msgstr "Nein"
+
+#: ../roundup/cgi/templating.py:944
+msgid "Yes"
+msgstr "Ja"
+
+#: ../roundup/cgi/templating.py:955
+#, python-format
+msgid "%s: (no value)"
+msgstr "%s: (kein Wert)"
+
+#: ../roundup/cgi/templating.py:967
+msgid ""
+"<strong><em>This event is not handled by the history display!</em></strong>"
+msgstr ""
+"<strong><em>Ereignis kann nicht im Verlauf angezeigt werden!</em></strong>"
+
+#: ../roundup/cgi/templating.py:979
+msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
+msgstr "<tr><td colspan=4><strong>Notiz:</strong></td></tr>"
+
+#: ../roundup/cgi/templating.py:988
+msgid "History"
+msgstr "Verlauf"
+
+#: ../roundup/cgi/templating.py:990
+msgid "<th>Date</th>"
+msgstr "<th>Datum</th>"
+
+#: ../roundup/cgi/templating.py:991
+msgid "<th>User</th>"
+msgstr "<th>Benutzer</th>"
+
+#: ../roundup/cgi/templating.py:992
+msgid "<th>Action</th>"
+msgstr "<th>Aktion</th>"
+
+#: ../roundup/cgi/templating.py:993
+msgid "<th>Args</th>"
+msgstr "<th>Argumente</th>"
+
+#: ../roundup/cgi/templating.py:1234
+msgid "*encrypted*"
+msgstr "*verschlüsselt*"
+
+#: ../roundup/cgi/templating.py:1412
+msgid ""
+"default value for DateHTMLProperty must be either DateHTMLProperty or string "
+"date representation."
+msgstr ""
+"Der voreingestellte Wert einer DateHTML-Eigenschaft muss entweder ein\n"
+"DateHTML Objekt sein oder ein Datum repräsentieren."
+
+#: ../roundup/cgi/templating.py:1600
+#, python-format
+msgid "<option %svalue=\"-1\">- no selection -</option>"
+msgstr "<option %svalue=\"-1\">- keine Auswahl -</option>"
+
+#: ../roundup/date.py:180
+#, python-format
+msgid "Not a date spec: %s"
+msgstr "Kein gültiges Datum: %s"
+
+#: ../roundup/date.py:231
+#, python-format
+msgid "%r not a date spec (%s)"
+msgstr "%r ist kein gültiges Datum (%s)"
+
+#: ../roundup/date.py:522
+msgid ""
+"Not an interval spec: [+-] [#y] [#m] [#w] [#d] [[[H]H:MM]:SS] [date spec]"
+msgstr ""
+"Fehler im Zeitperioden-Format: [+-] [#y] [#m] [#w] [#d] [[[H]H:MM]:SS] [date "
+"spec]"
+
+#: ../roundup/date.py:541
+msgid "Not an interval spec: [+-] [#y] [#m] [#w] [#d] [[[H]H:MM]:SS]"
+msgstr ""
+"Fehler im Intervall-Format: [+-] [#y] [#m] [#w] [#d] [[[H]H:MM]:SS] [date "
+"spec]"
+
+#: ../roundup/date.py:678
+#, python-format
+msgid "%(number)s year"
+msgid_plural "%(number)s years"
+msgstr[0] "%(number)s Jahr"
+msgstr[1] "%(number)s Jahren"
+
+#: ../roundup/date.py:682
+#, python-format
+msgid "%(number)s month"
+msgid_plural "%(number)s months"
+msgstr[0] "%(number)s Monat"
+msgstr[1] "%(number)s Monaten"
+
+#: ../roundup/date.py:686
+#, python-format
+msgid "%(number)s week"
+msgid_plural "%(number)s weeks"
+msgstr[0] "%(number)s Woche"
+msgstr[1] "%(number)s Wochen"
+
+#: ../roundup/date.py:690
+#, python-format
+msgid "%(number)s day"
+msgid_plural "%(number)s days"
+msgstr[0] "%(number)s Tag"
+msgstr[1] "%(number)s Tagen"
+
+#: ../roundup/date.py:694
+msgid "tomorrow"
+msgstr "Morgen"
+
+#: ../roundup/date.py:696
+msgid "yesterday"
+msgstr "Gestern"
+
+#: ../roundup/date.py:699
+#, python-format
+msgid "%(number)s hour"
+msgid_plural "%(number)s hours"
+msgstr[0] "%(number)s Stunde"
+msgstr[1] "%(number)s Stunden"
+
+#: ../roundup/date.py:703
+msgid "an hour"
+msgstr "eine Stunde"
+
+#: ../roundup/date.py:705
+msgid "1 1/2 hours"
+msgstr "1 1/2 Stunden"
+
+#: ../roundup/date.py:707
+#, python-format
+msgid "1 %(number)s/4 hours"
+msgid_plural "1 %(number)s/4 hours"
+msgstr[0] "1 %(number)s/4 Stunden"
+msgstr[1] "1 %(number)s/4 Stunden"
+
+#: ../roundup/date.py:711
+msgid "in a moment"
+msgstr "in Kürze"
+
+#: ../roundup/date.py:713
+msgid "just now"
+msgstr "Soeben"
+
+#: ../roundup/date.py:716
+msgid "1 minute"
+msgstr "1 Minute"
+
+#: ../roundup/date.py:719
+#, python-format
+msgid "%(number)s minute"
+msgid_plural "%(number)s minutes"
+msgstr[0] "%(number)s Minute"
+msgstr[1] "%(number)s Minuten"
+
+#: ../roundup/date.py:722
+msgid "1/2 an hour"
+msgstr "1/2 Stunde"
+
+#: ../roundup/date.py:724
+#, python-format
+msgid "%(number)s/4 hour"
+msgid_plural "%(number)s/4 hours"
+msgstr[0] "%(number)s/4 Stunden"
+msgstr[1] "%(number)s/4 Stunden"
+
+#: ../roundup/date.py:728
+#, python-format
+msgid "%s ago"
+msgstr "vor %s"
+
+#: ../roundup/date.py:730
+#, python-format
+msgid "in %s"
+msgstr "in %s"
+
+#: ../roundup/init.py:132
+#, python-format
+msgid ""
+"WARNING: directory '%s'\n"
+"\tcontains old-style template - ignored"
+msgstr ""
+"WARNUNG: Das Verzeichnis '%s'\n"
+"\tenthält Templates im alten Format, die ignoriert werden."
+
+#: ../roundup/roundupdb.py:141
+msgid "files"
+msgstr "Dateien"
+
+#: ../roundup/roundupdb.py:141
+msgid "messages"
+msgstr "Meldungen"
+
+#: ../roundup/roundupdb.py:141
+msgid "nosy"
+msgstr "Interessenten"
+
+#: ../roundup/roundupdb.py:141
+msgid "superseder"
+msgstr "Übergeordnet"
+
+#: ../roundup/roundupdb.py:141
+msgid "title"
+msgstr "Titel"
+
+#: ../roundup/roundupdb.py:142
+msgid "assignedto"
+msgstr "Zugewiesen"
+
+#: ../roundup/roundupdb.py:142
+msgid "priority"
+msgstr "Prioriät"
+
+#: ../roundup/roundupdb.py:142
+msgid "status"
+msgstr "Status"
+
+#: ../roundup/roundupdb.py:142
+msgid "topic"
+msgstr "Thema"
+
+#: ../roundup/roundupdb.py:145
+msgid "activity"
+msgstr "Aktivität"
+
+#. following properties are common for all hyperdb classes
+#. they are listed here to keep things in one place
+#: ../roundup/roundupdb.py:145
+msgid "actor"
+msgstr "Akteur"
+
+#: ../roundup/roundupdb.py:145
+msgid "creation"
+msgstr "Erstellungsdatum"
+
+#: ../roundup/roundupdb.py:145
+msgid "creator"
+msgstr "Ersteller"
+
+#: ../roundup/scripts/roundup_demo.py:32
+#, python-format
+msgid "Enter directory path to create demo tracker [%s]: "
+msgstr "Verzeichnis für Tracker-Demo eingeben [%s]: "
+
+#: ../roundup/scripts/roundup_gettext.py:22
+#, python-format
+msgid "Usage: %(program)s <tracker home>"
+msgstr "Verwendung: %(program)s <Tracker Verzeichnis>"
+
+#: ../roundup/scripts/roundup_gettext.py:37
+#, python-format
+msgid "No tracker templates found in directory %s"
+msgstr "Keine Tracker-Vorlage gefunden im Verzeichnis %s"
+
+#: ../roundup/scripts/roundup_mailgw.py:36
+#, python-format
+msgid ""
+"Usage: %(program)s [-v] [-c] [[-C class] -S field=value]* <instance home> "
+"[method]\n"
+"\n"
+"Options:\n"
+" -v: print version and exit\n"
+" -c: default class of item to create (else the tracker's "
+"MAIL_DEFAULT_CLASS)\n"
+" -C / -S: see below\n"
+"\n"
+"The roundup mail gateway may be called in one of four ways:\n"
+" . with an instance home as the only argument,\n"
+" . with both an instance home and a mail spool file,\n"
+" . with both an instance home and a POP/APOP server account, or\n"
+" . with both an instance home and a IMAP/IMAPS server account.\n"
+"\n"
+"It also supports optional -C and -S arguments that allows you to set a\n"
+"fields for a class created by the roundup-mailgw. The default class if\n"
+"not specified is msg, but the other classes: issue, file, user can\n"
+"also be used. The -S or --set options uses the same\n"
+"property=value[;property=value] notation accepted by the command line\n"
+"roundup command or the commands that can be given on the Subject line\n"
+"of an email message.\n"
+"\n"
+"It can let you set the type of the message on a per email address basis.\n"
+"\n"
+"PIPE:\n"
+" In the first case, the mail gateway reads a single message from the\n"
+" standard input and submits the message to the roundup.mailgw module.\n"
+"\n"
+"UNIX mailbox:\n"
+" In the second case, the gateway reads all messages from the mail spool\n"
+" file and submits each in turn to the roundup.mailgw module. The file is\n"
+" emptied once all messages have been successfully handled. The file is\n"
+" specified as:\n"
+"   mailbox /path/to/mailbox\n"
+"\n"
+"POP:\n"
+" In the third case, the gateway reads all messages from the POP server\n"
+" specified and submits each in turn to the roundup.mailgw module. The\n"
+" server is specified as:\n"
+"    pop username:password at server\n"
+" The username and password may be omitted:\n"
+"    pop username at server\n"
+"    pop server\n"
+" are both valid. The username and/or password will be prompted for if\n"
+" not supplied on the command-line.\n"
+"\n"
+"APOP:\n"
+" Same as POP, but using Authenticated POP:\n"
+"    apop username:password at server\n"
+"\n"
+"IMAP:\n"
+" Connect to an IMAP server. This supports the same notation as that of\n"
+" POP mail.\n"
+"    imap username:password at server\n"
+" It also allows you to specify a specific mailbox other than INBOX using\n"
+" this format:\n"
+"    imap username:password at server mailbox\n"
+"\n"
+"IMAPS:\n"
+" Connect to an IMAP server over ssl.\n"
+" This supports the same notation as IMAP.\n"
+"    imaps username:password at server [mailbox]\n"
+"\n"
+msgstr ""
+"Verwendung: %(program)s [-v] [[-C Klasse] -S Eigenschaft=Wert]* <Tracker-"
+"Verzeichnis> [Methode]\n"
+"\n"
+"Optionen:\n"
+" -v: Versionsnummer ausgeben und beenden\n"
+" -c: Vorgegebene Klasse beim Erstellen eines Eintrages (sonst: MAIL_DEFAULT_CLASS)\n"
+" -C / -S: siehe Unten\n"
+"\n"
+"Das Roundup Mailgateway kann auf vier verschiedene Arten aufgerufen werden:\n"
+" . mit einem Tracker-Verzeichnis als einziges Argument,\n"
+" . mit einem Tracker-Verzeichnis und einer Mailbox Datei,\n"
+" . mit einem Tracker-Verzeichnis und einem POP/APOP Konto, oder\n"
+" . mit einem Tracker-Verzeichnis und einem IMAP/IMAPS Konto.\n"
+"\n"
+"Optional kann mit -C die Klasse des zu erstellenden Eintrages spezifiziert \n"
+"werden. Zudem können Sie mit -S oder --set Eigenschaften der Einträge\n"
+"als Eigenschaft=Wert[;Eigenschaft=Wert]* setzen, analog zum Roundup-\n"
+"Kommandozeilen Programm, resp. zur Syntax in der Betreffszeile einer Email.\n"
+"Voreingestellt ist die Klasse \"msg\", aber auch Klassen wie \"issue\",\n"
+"\"user\" oder \"file\" können verwendet werden.\n"
+"\n"
+"Sie können dadurch mehrere Email-Kontos für einen Tracker verwenden und\n"
+"unterschiedliche Eintragstypen aus den Meldungen erstellen.\n"
+"\n"
+"PIPE:\n"
+" Das Mail Gateway liest eine Meldung vom Standard-Input und übergibt die\n"
+" Meldung an das Modul roundup.mailgw.\n"
+"\n"
+"UNIX Mailbox:\n"
+" Die angegebene Mailbox-Datei wird ausgelesen und alle Meldungen werden\n"
+" an das Modul roundup.mailgw übergeben. Nach erfolgreicher Verarbeitung \n"
+" wird die Mail-Spool Datei geleert.\n"
+" Die Mailbox-Datei wird folgendermassen angegeben:  mailbox /pfad/zur/"
+"mailbox\n"
+"\n"
+"POP:\n"
+" Das Gateway liest alle Meldungen vom POP3-Konto und leitet sie weiter an \n"
+" das Modul roundup.mailgw. \n"
+" Das Konto wird folgendermassen angegeben:\n"
+"    pop benutzername:passwort at server\n"
+" Benutzername und Passwort können weggelassen werden:\n"
+"    pop benutzername at server\n"
+"    pop server\n"
+" In diesem Fall werden die Anmeldungs-Daten zur Laufzeit erfragt.\n"
+"\n"
+"APOP:\n"
+" Wie POP aber unter Verwendung von authentifiziertem POP:\n"
+"    apop benutzername:passwort at server\n"
+"\n"
+"IMAP:\n"
+" Verbindung mit einem IMAP-Server. Die Syntax entspricht der POP-\n"
+" Spezifikation:\n"
+"    imap benutzername:passwort at server\n"
+" Um eine andere Mailbox anstelle von \"INBOX\" zu verwenden, benutzen Sie:\n"
+"    imap benutzername:passwort at server mailbox\n"
+"\n"
+"IMAPS:\n"
+" Verbindung zu einem IMAP-Server über eine sichere SSL-Verbindung.\n"
+" Die Syntax entspricht der IMAP-Spezifikation:\n"
+"    imaps benutzername:passwort at server [mailbox]\n"
+"\n"
+
+#: ../roundup/scripts/roundup_mailgw.py:147
+msgid "Error: not enough source specification information"
+msgstr "Sie haben nicht genügend Angaben zur Mail-Quelle gemacht"
+
+#: ../roundup/scripts/roundup_mailgw.py:157
+msgid "Error: pop specification not valid"
+msgstr "Fehler: pop Optionen ungültig"
+
+#: ../roundup/scripts/roundup_mailgw.py:164
+msgid "Error: apop specification not valid"
+msgstr "Fehler: apop Optionen ungültig"
+
+#: ../roundup/scripts/roundup_mailgw.py:178
+msgid ""
+"Error: The source must be either \"mailbox\", \"pop\", \"apop\", \"imap\" or "
+"\"imaps\""
+msgstr ""
+"Fehler: Als Mail-Quelle muss \"mailbox\", \"pop\", \"apop\", \"imap\" oder "
+"\"imaps\" gewählt werden"
+
+#: ../roundup/scripts/roundup_server.py:140
+msgid ""
+"<html><head><title>Roundup trackers index</title></head>\n"
+"<body><h1>Roundup trackers index</h1><ol>\n"
+msgstr ""
+"<html><head><title>Roundup Tracker-Liste</title></head>\n"
+"<body><h1>Roundup Tracker-Liste</h1><ol>\n"
+
+#: ../roundup/scripts/roundup_server.py:242
+#, python-format
+msgid "Error: %s: %s"
+msgstr "Fehler: %s: %s"
+
+#: ../roundup/scripts/roundup_server.py:252
+msgid "WARNING: ignoring \"-g\" argument, not root"
+msgstr ""
+"WARNUNG: die Option \"-g\" wird ignoriert, da Sie nicht Administrator sind"
+
+#: ../roundup/scripts/roundup_server.py:258
+msgid "Can't change groups - no grp module"
+msgstr "Die Gruppe kann nicht gewechselt werden - das grp Modul fehlt"
+
+#: ../roundup/scripts/roundup_server.py:267
+#, python-format
+msgid "Group %(group)s doesn't exist"
+msgstr "Die Gruppe %(group)s existiert nicht"
+
+#: ../roundup/scripts/roundup_server.py:278
+msgid "Can't run as root!"
+msgstr "Dieser Prozess kann nicht unter dem Administrator (\"root\") laufen!"
+
+#: ../roundup/scripts/roundup_server.py:281
+msgid "WARNING: ignoring \"-u\" argument, not root"
+msgstr ""
+"WARNUNG: die Option \"-u\" wird ignoriert, da Sie nicht Administrator sind"
+
+#: ../roundup/scripts/roundup_server.py:286
+msgid "Can't change users - no pwd module"
+msgstr "Der Benutzer kann nicht gewechselt werden - das pwd Modul fehlt"
+
+#: ../roundup/scripts/roundup_server.py:295
+#, python-format
+msgid "User %(user)s doesn't exist"
+msgstr "Der Benutzer %(user)s existiert nicht"
+
+#: ../roundup/scripts/roundup_server.py:417
+#, python-format
+msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
+msgstr "Der Multiprozess-Modus \"%s\" ist nicht verfügbar, Einprozess-Modus"
+"aktiviert"
+
+#: ../roundup/scripts/roundup_server.py:440
+#, python-format
+msgid "Unable to bind to port %s, port already in use."
+msgstr "Start des Servers auf Port %s schlug fehl. Port bereits verwendet."
+
+#: ../roundup/scripts/roundup_server.py:507
+msgid ""
+" -c <Command>  Windows Service options.\n"
+"               If you want to run the server as a Windows Service, you\n"
+"               must use configuration file to specify tracker homes.\n"
+"               Logfile option is required to run Roundup Tracker service.\n"
+"               Typing \"roundup-server -c help\" shows Windows Services\n"
+"               specifics."
+msgstr ""
+" -c <Befehl>   Windows Service Optionen.\n"
+"               Um den Roundup-Server als Windows Service zu starten,\n"
+"               benutzen Sie eine Server-Konfiguration, in der die Tracker-\n"
+"               Instanzen angegeben werden.\n"
+"               Zudem müssen Sie die Logfile-Option aktivieren.\n"
+"               \"roundup-server -c help\" zeigt eine weitere Hilfe zum Thema."
+
+#: ../roundup/scripts/roundup_server.py:514
+msgid ""
+" -u <UID>      runs the Roundup web server as this UID\n"
+" -g <GID>      runs the Roundup web server as this GID\n"
+" -d <PIDfile>  run the server in the background and write the server's PID\n"
+"               to the file indicated by PIDfile. The -l option *must* be\n"
+"               specified if -d is used."
+msgstr ""
+" -u <UID>      Startet den Roundup-Server mit dieser Benutzer-Nummer\n"
+" -g <GID>      Startet den Roundup-Server mit dieser Gruppen-Nummer\n"
+" -d <PIDDatei> Startet den Server als Hintergrundprozess und schreibt\n"
+"               die Prozess-ID in die Datei PIDDatei\n"
+"               Die Option -l muss dann auch angegeben werden."
+
+#: ../roundup/scripts/roundup_server.py:521
+#, python-format
+msgid ""
+"%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
+"\n"
+"Options:\n"
+" -v            print the Roundup version number and exit\n"
+" -h            print this text and exit\n"
+" -S            create or update configuration file and exit\n"
+" -C <fname>    use configuration file <fname>\n"
+" -n <name>     set the host name of the Roundup web server instance\n"
+" -p <port>     set the port to listen on (default: %(port)s)\n"
+" -l <fname>    log to the file indicated by fname instead of stderr/stdout\n"
+" -N            log client machine names instead of IP addresses (much "
+"slower)\n"
+" -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
+"               Allowed values: %(mp_types)s.\n"
+"%(os_part)s\n"
+"\n"
+"Long options:\n"
+" --version          print the Roundup version number and exit\n"
+" --help             print this text and exit\n"
+" --save-config      create or update configuration file and exit\n"
+" --config <fname>   use configuration file <fname>\n"
+" All settings of the [main] section of the configuration file\n"
+" also may be specified in form --<name>=<value>\n"
+"\n"
+"Examples:\n"
+"\n"
+" roundup-server -S -C /opt/roundup/etc/roundup-server.ini \\\n"
+"    -n localhost -p 8917 -l /var/log/roundup.log \\\n"
+"    support=/var/spool/roundup-trackers/support\n"
+"\n"
+" roundup-server -C /opt/roundup/etc/roundup-server.ini\n"
+"\n"
+" roundup-server support=/var/spool/roundup-trackers/support\n"
+"\n"
+" roundup-server -d /var/run/roundup.pid -l /var/log/roundup.log \\\n"
+"    support=/var/spool/roundup-trackers/support\n"
+"\n"
+"Configuration file format:\n"
+"   Roundup Server configuration file has common .ini file format.\n"
+"   Configuration file created with 'roundup-server -S' contains\n"
+"   detailed explanations for each option.  Please see that file\n"
+"   for option descriptions.\n"
+"\n"
+"How to use \"name=tracker home\":\n"
+"   These arguments set the tracker home(s) to use. The name is how the\n"
+"   tracker is identified in the URL (it's the first part of the URL path).\n"
+"   The tracker home is the directory that was identified when you did\n"
+"   \"roundup-admin init\". You may specify any number of these name=home\n"
+"   pairs on the command-line. Make sure the name part doesn't include\n"
+"   any url-unsafe characters like spaces, as these confuse IE.\n"
+msgstr ""
+"%(message)s"
+"Benutzung: roundup-server [Optionen] [Tracker-Name=Tracker-Verzeichnis]*\n"
+"\n"
+"Optionen:\n"
+" -v            Versionsnummer ausgeben und beenden\n"
+" -h            Diese Hilfe ausgeben und beenden\n"
+" -S            Konfiguration erstellen oder aktualiseren und beenden\n"
+" -C <Datei>    Konfiguration in <Datei> verwenden\n"
+" -n            Hostname des Serverprozesses bestimmen\n"
+" -p            Port bestimmen (Voreinstellung: %(port)s)\n"
+" -l            Logdatei bestimmen (anstelle \"stderr\" / \"stdout\")\n"
+" -N            Domainnamen in der Logdatei auflösen (viel langsamer)\n"
+" -t <Modus>    Multiprozess-Modus (Voreinstellung: %(mp_def)s).\n"
+"               Verfügbare Modi: %(mp_types)s.\n"
+"%(os_part)s\n"
+"\n"
+"Lange Optionen:\n"
+" --version          Roundup Versionsnummer ausgeben und beenden\n"
+" --help             Diese Hilfe ausgeben und beenden\n"
+" --save-config      Konfiguration erstellen oder aktualiseren und beenden\n"
+" --config <fname>   Konfiguration <Datei> verwenden\n"
+" Die Einstellungen in der Sektion [main] der Konfigurationsdatei können Sie\n"
+" auch in der Form --<Name>=<Wert> angegeben.\n"
+"\n"
+"Beispiele:\n"
+"\n"
+" roundup-server -S -C /opt/roundup/etc/roundup-server.ini \\\n"
+"    -n localhost -p 8917 -l /var/log/roundup.log \\\n"
+"    support=/var/spool/roundup-trackers/support\n"
+"\n"
+" roundup-server -C /opt/roundup/etc/roundup-server.ini\n"
+"\n"
+" roundup-server support=/var/spool/roundup-trackers/support\n"
+"\n"
+" roundup-server -d /var/run/roundup.pid -l /var/log/roundup.log \\\n"
+"    support=/var/spool/roundup-trackers/support\n"
+"\n"
+"Konfigurations-Format:\n"
+"   Roundup Server benutzt das standardisierte .ini Format.\n"
+"   Konfigurationen, welche mit 'roundup-server -S' erstellt werden, \n"
+"   enthalten detaillierte Erklärungen zu jeder Option. Bitte konsultieren\n"
+"   Sie diese Datei für weitere Angaben.\n"
+"\n"
+"Tracker-Name=Tracker-Verzeichnis:\n"
+"   Gibt an, welche Tracker-Instanz(en) verwendet werden. Der Tracker-Name\n"
+"   bestimmt den URL-Pfad im Web. Das Tracker-Verzeichnis gibt an, in \n"
+"   welchem Verzeichnis die Tracker-Konfiguration gespeichert wurde.\n"
+"   Sie können mehrere Tracker-Instanzen auf der Kommandozeile angeben oder\n"
+"   alternativ die Variable TRACKER_HOMES in der roundup-server Datei \n"
+"   anpassen. \n"
+"   ACHTUNG: Der Tracker-Name darf keine Sonderzeichen enthalten, welche in \n"
+"   URLs Probleme bereiten könnten. Am besten verwenden Sie nur Buchstaben, \n"
+"   Zahlen und \"-_\".\n"
+
+#: ../roundup/scripts/roundup_server.py:669
+msgid "Instances must be name=home"
+msgstr "Instanzen müssen als Tracker-Name=Tracker-Verzeichnis angegeben werden"
+
+#: ../roundup/scripts/roundup_server.py:683
+#, python-format
+msgid "Configuration saved to %s"
+msgstr "Konfiguration in der Datei %s gespeichert"
+
+#: ../roundup/scripts/roundup_server.py:694
+msgid "Sorry, you can't run the server as a daemon on this Operating System"
+msgstr ""
+"Auf diesem Betriebssystem kann der Server nicht als Hintergrundprozess laufen"
+
+#: ../roundup/scripts/roundup_server.py:706
+#, python-format
+msgid "Roundup server started on %(HOST)s:%(PORT)s"
+msgstr "Der Roundup-Server wurde unter %(HOST)s:%(PORT)s gestartet"
+
+#: ../templates/classic/html/_generic.collision.html:4
+#: ../templates/minimal/html/_generic.collision.html:4
+msgid "${class} Edit Collision - ${tracker}"
+msgstr "Kollision bei der Bearbeitung - ${tracker}"
+
+#: ../templates/classic/html/_generic.collision.html:7
+#: ../templates/minimal/html/_generic.collision.html:7
+msgid "${class} Edit Collision"
+msgstr "Kollision bei der Bearbeitung"
+
+#: ../templates/classic/html/_generic.collision.html:14
+#: ../templates/minimal/html/_generic.collision.html:14
+msgid ""
+"\n"
+"  There has been a collision. Another user updated this node\n"
+"  while you were editing. Please <a href='${context}'>reload</a>\n"
+"  the node and review your edits.\n"
+msgstr ""
+"\n"
+"  Eine Kollision wurde festgestellt. Während Ihrer Bearbeitung\n"
+"  hat ein anderer Benutzer diesen Eintrag aktualisiert. Bitte   <a "
+"href='${context}'>laden Sie diese Seite neu</a> \n"
+"  und fügen Sie Ihre Änderungen erneut ein.\n"
+
+#: ../templates/classic/html/_generic.help.html:9
+#: ../templates/minimal/html/_generic.help.html:9
+msgid "${property} help - ${tracker}"
+msgstr "Hilfe zu \"${property}\" - ${tracker}"
+
+#: ../templates/classic/html/_generic.help.html:30
+#: ../templates/minimal/html/_generic.help.html:30
+msgid " Cancel "
+msgstr " Abbrechen "
+
+#: ../templates/classic/html/_generic.help.html:33
+#: ../templates/minimal/html/_generic.help.html:33
+msgid " Apply "
+msgstr " Bestätigen "
+
+#: ../templates/classic/html/_generic.help.html:40
+#: ../templates/classic/html/issue.index.html:67
+#: ../templates/minimal/html/_generic.help.html:40
+msgid "&lt;&lt; previous"
+msgstr "&lt;&lt; zurück"
+
+#: ../templates/classic/html/_generic.help.html:50
+#: ../templates/classic/html/issue.index.html:75
+#: ../templates/minimal/html/_generic.help.html:50
+msgid "${start}..${end} out of ${total}"
+msgstr "${start}..${end} von ${total}"
+
+#: ../templates/classic/html/_generic.help.html:54
+#: ../templates/classic/html/issue.index.html:78
+#: ../templates/minimal/html/_generic.help.html:54
+msgid "next &gt;&gt;"
+msgstr "Weiter &gt;&gt;"
+
+#: ../templates/classic/html/_generic.index.html:6
+#: ../templates/classic/html/_generic.item.html:4
+#: ../templates/minimal/html/_generic.index.html:6
+#: ../templates/minimal/html/_generic.item.html:4
+msgid "${class} editing - ${tracker}"
+msgstr "Klasse bearbeiten - ${tracker}"
+
+#: ../templates/classic/html/_generic.index.html:9
+#: ../templates/classic/html/_generic.item.html:7
+#: ../templates/minimal/html/_generic.index.html:9
+#: ../templates/minimal/html/_generic.item.html:7
+msgid "${class} editing"
+msgstr "\"${class}\" bearbeiten"
+
+#: ../templates/classic/html/_generic.index.html:14
+#: ../templates/classic/html/_generic.item.html:12
+#: ../templates/classic/html/file.item.html:9
+#: ../templates/classic/html/issue.index.html:10
+#: ../templates/classic/html/user.index.html:9
+#: ../templates/minimal/html/_generic.index.html:14
+#: ../templates/minimal/html/_generic.item.html:12
+#: ../templates/minimal/html/user.index.html:9
+#: ../templates/minimal/html/user.item.html:18
+#: ../templates/minimal/html/user.register.html:14
+msgid "You are not allowed to view this page."
+msgstr "Sie haben nicht die Berechtigung, diese Seite anzuzeigen."
+
+#: ../templates/classic/html/_generic.index.html:22
+#: ../templates/minimal/html/_generic.index.html:22
+msgid ""
+"<p class=\"form-help\"> You may edit the contents of the ${classname} class "
+"using this form. Commas, newlines and double quotes (\") must be handled "
+"delicately. You may include commas and newlines by enclosing the values in "
+"double-quotes (\"). Double quotes themselves must be quoted by doubling "
+"(\"\"). </p> <p class=\"form-help\"> Multilink properties have their "
+"multiple values colon (\":\") separated (... ,\"one:two:three\", ...) </p> "
+"<p class=\"form-help\"> Remove entries by deleting their line. Add new "
+"entries by appending them to the table - put an X in the id column. </p>"
+msgstr ""
+"<p class=\"form-help\"> Sie können die Einträge der Klasse \"${classname}\" "
+"mit diesem Formular bearbeiten. Kommas, Zeilenschaltungen und "
+"Anführungszeichen (\") mit Vorsicht verwenden. Kommas und Zeilenschaltungen "
+"dürfen nur Anführungszeichen (\") verwendet werden. Um Anführungszeichen in "
+"Werten zu verwenden, müssen Sie verdoppelt werden (\"\"). </p> <p class="
+"\"form-help\"> Mehrfachlinks werden durch Doppeltpunkt (\":\") getrennt "
+"(... ,\"eins:zwei:drei\", ...) </p> <p class=\"form-help\"> Einträge können "
+"gelöscht werden, indem Sie Zeilen entfernen. Fügen Sie Zeilen ein für neue "
+"Einträge und geben Sie bei der ID-Spalte ein X an. </p>"
+
+#: ../templates/classic/html/_generic.index.html:44
+#: ../templates/minimal/html/_generic.index.html:44
+msgid "Edit Items"
+msgstr "Einträge bearbeiten"
+
+#: ../templates/classic/html/file.index.html:4
+msgid "List of files - ${tracker}"
+msgstr "Dateiliste - ${tracker}"
+
+#: ../templates/classic/html/file.index.html:5
+msgid "List of files"
+msgstr "Dateiliste"
+
+#: ../templates/classic/html/file.index.html:10
+msgid "Download"
+msgstr "Herunterladen"
+
+#: ../templates/classic/html/file.index.html:11
+#: ../templates/classic/html/file.item.html:23
+#: ../templates/classic/html/file.item.html:51
+msgid "Content Type"
+msgstr "Inhaltstyp"
+
+#: ../templates/classic/html/file.index.html:12
+msgid "Uploaded By"
+msgstr "Hochgeladen von"
+
+#: ../templates/classic/html/file.index.html:13
+#: ../templates/classic/html/msg.item.html:38
+msgid "Date"
+msgstr "Datum"
+
+#: ../templates/classic/html/file.item.html:2
+msgid "File display - ${tracker}"
+msgstr "Datei anzeigen - ${tracker}"
+
+#: ../templates/classic/html/file.item.html:4
+msgid "File display"
+msgstr "Datei anzeigen"
+
+#: ../templates/classic/html/file.item.html:19
+#: ../templates/classic/html/file.item.html:47
+#: ../templates/classic/html/user.item.html:34
+#: ../templates/classic/html/user.register.html:17
+msgid "Name"
+msgstr "Name"
+
+#: ../templates/classic/html/file.item.html:41
+msgid "download"
+msgstr "herunterladen"
+
+#: ../templates/classic/html/home.classlist.html:2
+#: ../templates/minimal/html/home.classlist.html:2
+msgid "List of classes - ${tracker}"
+msgstr "Klassenliste - ${tracker}"
+
+#: ../templates/classic/html/home.classlist.html:4
+#: ../templates/minimal/html/home.classlist.html:4
+msgid "List of classes"
+msgstr "Klassenliste"
+
+#: ../templates/classic/html/issue.index.html:4
+msgid "List of issues - ${tracker}"
+msgstr "Aufgabenliste - ${tracker}"
+
+#: ../templates/classic/html/issue.index.html:6
+msgid "List of issues"
+msgstr "Aufgabenliste"
+
+#: ../templates/classic/html/issue.index.html:17
+#: ../templates/classic/html/issue.item.html:38
+msgid "Priority"
+msgstr "Priorität"
+
+#: ../templates/classic/html/issue.index.html:18
+msgid "ID"
+msgstr "ID"
+
+#: ../templates/classic/html/issue.index.html:19
+msgid "Creation"
+msgstr "Erstellungsdatum"
+
+#: ../templates/classic/html/issue.index.html:20
+msgid "Activity"
+msgstr "Aktivität"
+
+#: ../templates/classic/html/issue.index.html:21
+msgid "Actor"
+msgstr "Akteur"
+
+#: ../templates/classic/html/issue.index.html:22
+msgid "Topic"
+msgstr "Thema"
+
+#: ../templates/classic/html/issue.index.html:23
+#: ../templates/classic/html/issue.item.html:33
+msgid "Title"
+msgstr "Titel"
+
+#: ../templates/classic/html/issue.index.html:24
+#: ../templates/classic/html/issue.item.html:40
+msgid "Status"
+msgstr "Status"
+
+#: ../templates/classic/html/issue.index.html:25
+msgid "Creator"
+msgstr "Ersteller"
+
+#: ../templates/classic/html/issue.index.html:26
+msgid "Assigned&nbsp;To"
+msgstr "Zugewiesen"
+
+#: ../templates/classic/html/issue.index.html:90
+msgid "Download as CSV"
+msgstr "Als CSV-Datei herunterladen"
+
+#: ../templates/classic/html/issue.index.html:98
+msgid "Sort on:"
+msgstr "Sortieren:"
+
+#: ../templates/classic/html/issue.index.html:101
+#: ../templates/classic/html/issue.index.html:118
+msgid "- nothing -"
+msgstr "- nichts -"
+
+#: ../templates/classic/html/issue.index.html:109
+#: ../templates/classic/html/issue.index.html:126
+msgid "Descending:"
+msgstr "Absteigend:"
+
+#: ../templates/classic/html/issue.index.html:115
+msgid "Group on:"
+msgstr "Gruppieren:"
+
+#: ../templates/classic/html/issue.index.html:132
+msgid "Redisplay"
+msgstr "Aktualisieren"
+
+#: ../templates/classic/html/issue.item.html:7
+msgid "Issue ${id}: ${title} - ${tracker}"
+msgstr "Aufgabe ${id}: ${title} - ${tracker}"
+
+#: ../templates/classic/html/issue.item.html:10
+msgid "New Issue - ${tracker}"
+msgstr "Neue Aufgabe - ${tracker}"
+
+#: ../templates/classic/html/issue.item.html:14
+msgid "New Issue"
+msgstr "Neue Aufgabe"
+
+#: ../templates/classic/html/issue.item.html:16
+msgid "New Issue Editing"
+msgstr "Neue Aufgabe bearbeiten"
+
+#: ../templates/classic/html/issue.item.html:19
+msgid "Issue${id}"
+msgstr "Aufgabe${id}"
+
+#: ../templates/classic/html/issue.item.html:22
+msgid "Issue${id} Editing"
+msgstr "Aufgabe${id} bearbeiten"
+
+#: ../templates/classic/html/issue.item.html:45
+msgid "Superseder"
+msgstr "Übergeordnete Aufgabe"
+
+#: ../templates/classic/html/issue.item.html:50
+msgid "View: ${link}"
+msgstr "Anzeigen: ${link}"
+
+#: ../templates/classic/html/issue.item.html:54
+msgid "Nosy List"
+msgstr "Interessenten"
+
+#: ../templates/classic/html/issue.item.html:63
+msgid "Assigned To"
+msgstr "Zugewiesen"
+
+#: ../templates/classic/html/issue.item.html:65
+msgid "Topics"
+msgstr "Themen"
+
+#: ../templates/classic/html/issue.item.html:73
+msgid "Change Note"
+msgstr "Änderungsnotiz"
+
+#: ../templates/classic/html/issue.item.html:81
+msgid "File"
+msgstr "Datei"
+
+#: ../templates/classic/html/issue.item.html:100
+msgid ""
+"<table class=\"form\"> <tr> <td>Note:&nbsp;</td> <th class=\"required"
+"\">highlighted</th> <td>&nbsp;fields are required.</td> </tr> </table>"
+msgstr ""
+"<table class=\"form\"> <tr> <td>Bemerkungen:&nbsp;</td> <th class=\"required"
+"\">Fett markierte</th> <td>&nbsp;Felder sind immer auszufüllen. </td> </tr> "
+"</table>"
+
+#: ../templates/classic/html/issue.item.html:114
+msgid ""
+"Created on <b>${creation}</b> by <b>${creator}</b>, last changed <b>"
+"${activity}</b> by <b>${actor}</b>."
+msgstr ""
+"Erstellt am <b>${creation}</b> durch <b>${creator}</b>, geändert am <b>"
+"${activity}</b> durch <b>${actor}</b>."
+
+#: ../templates/classic/html/issue.item.html:118
+#: ../templates/classic/html/msg.item.html:51
+msgid "Files"
+msgstr "Dateien"
+
+#: ../templates/classic/html/issue.item.html:120
+#: ../templates/classic/html/msg.item.html:53
+msgid "File name"
+msgstr "Dateiname"
+
+#: ../templates/classic/html/issue.item.html:121
+#: ../templates/classic/html/msg.item.html:54
+msgid "Uploaded"
+msgstr "Hochgeladen"
+
+#: ../templates/classic/html/issue.item.html:122
+msgid "Type"
+msgstr "Typ"
+
+#: ../templates/classic/html/issue.item.html:123
+#: ../templates/classic/html/query.edit.html:30
+msgid "Edit"
+msgstr "Bearbeiten"
+
+#: ../templates/classic/html/issue.item.html:124
+msgid "Remove"
+msgstr "Verbergen"
+
+#: ../templates/classic/html/issue.item.html:144
+#: ../templates/classic/html/issue.item.html:165
+#: ../templates/classic/html/query.edit.html:50
+msgid "remove"
+msgstr "Nein"
+
+#: ../templates/classic/html/issue.item.html:151
+#: ../templates/classic/html/msg.index.html:9
+msgid "Messages"
+msgstr "Meldungen"
+
+#: ../templates/classic/html/issue.item.html:155
+msgid "msg${id} (view)"
+msgstr "msg${id} (betrachten)"
+
+#: ../templates/classic/html/issue.item.html:156
+msgid "Author: ${author}"
+msgstr "Autor: ${author}"
+
+#: ../templates/classic/html/issue.item.html:158
+msgid "Date: ${date}"
+msgstr "Datum: ${date}"
+
+#: ../templates/classic/html/issue.search.html:2
+msgid "Issue searching - ${tracker}"
+msgstr "Aufgaben suchen - ${tracker}"
+
+#: ../templates/classic/html/issue.search.html:4
+msgid "Issue searching"
+msgstr "Aufgaben suchen"
+
+#: ../templates/classic/html/issue.search.html:25
+msgid "Filter on"
+msgstr "Filtern"
+
+#: ../templates/classic/html/issue.search.html:26
+msgid "Display"
+msgstr "Anzeigen"
+
+#: ../templates/classic/html/issue.search.html:27
+msgid "Sort on"
+msgstr "Sortieren"
+
+#: ../templates/classic/html/issue.search.html:28
+msgid "Group on"
+msgstr "Gruppieren"
+
+#: ../templates/classic/html/issue.search.html:32
+msgid "All text*:"
+msgstr "Volltext*:"
+
+#: ../templates/classic/html/issue.search.html:40
+msgid "Title:"
+msgstr "Titel:"
+
+#: ../templates/classic/html/issue.search.html:50
+msgid "Topic:"
+msgstr "Thema:"
+
+#: ../templates/classic/html/issue.search.html:58
+msgid "ID:"
+msgstr "ID:"
+
+#: ../templates/classic/html/issue.search.html:66
+msgid "Creation Date:"
+msgstr "Erstellungsdatum:"
+
+#: ../templates/classic/html/issue.search.html:77
+msgid "Creator:"
+msgstr "Ersteller:"
+
+#: ../templates/classic/html/issue.search.html:79
+msgid "created by me"
+msgstr "Durch mich erstellt"
+
+#: ../templates/classic/html/issue.search.html:88
+msgid "Activity:"
+msgstr "Aktivität:"
+
+#: ../templates/classic/html/issue.search.html:99
+msgid "Actor:"
+msgstr "Akteur:"
+
+#: ../templates/classic/html/issue.search.html:101
+msgid "done by me"
+msgstr "durch mich"
+
+#: ../templates/classic/html/issue.search.html:112
+msgid "Priority:"
+msgstr "Priorität:"
+
+#: ../templates/classic/html/issue.search.html:114
+#: ../templates/classic/html/issue.search.html:130
+msgid "not selected"
+msgstr "Nicht gewählt"
+
+#: ../templates/classic/html/issue.search.html:125
+msgid "Status:"
+msgstr "Status:"
+
+#: ../templates/classic/html/issue.search.html:128
+msgid "not resolved"
+msgstr "Ungelöst"
+
+#: ../templates/classic/html/issue.search.html:143
+msgid "Assigned to:"
+msgstr "Zugewiesen:"
+
+#: ../templates/classic/html/issue.search.html:146
+msgid "assigned to me"
+msgstr "Mir zugewiesen"
+
+#: ../templates/classic/html/issue.search.html:148
+msgid "unassigned"
+msgstr "Nicht zugewiesen"
+
+#: ../templates/classic/html/issue.search.html:158
+msgid "Pagesize:"
+msgstr "Pro Seite:"
+
+#: ../templates/classic/html/issue.search.html:164
+msgid "Start With:"
+msgstr "Starten bei:"
+
+#: ../templates/classic/html/issue.search.html:170
+msgid "Sort Descending:"
+msgstr "Absteigend sortieren:"
+
+#: ../templates/classic/html/issue.search.html:177
+msgid "Group Descending:"
+msgstr "Absteigend gruppieren:"
+
+#: ../templates/classic/html/issue.search.html:184
+msgid "Query name**:"
+msgstr "Speichern unter**:"
+
+#: ../templates/classic/html/issue.search.html:194
+#: ../templates/classic/html/page.html:47
+msgid "Search"
+msgstr "Suchen"
+
+#: ../templates/classic/html/issue.search.html:198
+msgid ""
+"*: The \"all text\" field will look in message bodies and issue titles<br> "
+"**: If you supply a name, the query will be saved off and available as a "
+"link in the sidebar"
+msgstr ""
+"*: Das Feld \"Volltext\" durchsucht Titel von Aufgaben und Meldungstexte<br> "
+"**: Geben Sie einen Namen für diese Abfrage ein, um sie in der Seitenleiste "
+"zu speichern. "
+
+#: ../templates/classic/html/keyword.item.html:3
+msgid "Keyword editing - ${tracker}"
+msgstr "Stichwort bearbeiten - ${tracker}"
+
+#: ../templates/classic/html/keyword.item.html:5
+msgid "Keyword editing"
+msgstr "Stichwort bearbeiten"
+
+#: ../templates/classic/html/keyword.item.html:11
+msgid "Existing Keywords"
+msgstr "Vorhandene Stichworte"
+
+#: ../templates/classic/html/keyword.item.html:20
+msgid ""
+"To edit an existing keyword (for spelling or typing errors), click on its "
+"entry above."
+msgstr "Um ein bestehendes Stichwort zu bearbeiten, klicken Sie darauf."
+
+#: ../templates/classic/html/keyword.item.html:27
+msgid "To create a new keyword, enter it below and click \"Submit New Entry\"."
+msgstr ""
+"Um ein neues Stichwort hinzufügen, tragen Sie es hier ein und klicken Sie "
+"auf \"Eintrag speichern\"."
+
+#: ../templates/classic/html/keyword.item.html:37
+msgid "Keyword"
+msgstr "Stichwort"
+
+#: ../templates/classic/html/msg.index.html:3
+msgid "List of messages - ${tracker}"
+msgstr "Meldungsliste - ${tracker}"
+
+#: ../templates/classic/html/msg.index.html:5
+msgid "Message listing"
+msgstr "Meldungsliste"
+
+#: ../templates/classic/html/msg.item.html:6
+msgid "Message ${id} - ${tracker}"
+msgstr "Meldung ${id} - ${tracker}"
+
+#: ../templates/classic/html/msg.item.html:9
+msgid "New Message - ${tracker}"
+msgstr "Neue Meldung - ${tracker}"
+
+#: ../templates/classic/html/msg.item.html:13
+msgid "New Message"
+msgstr "Neue Meldung"
+
+#: ../templates/classic/html/msg.item.html:15
+msgid "New Message Editing"
+msgstr "Neue Meldung bearbeiten"
+
+#: ../templates/classic/html/msg.item.html:18
+msgid "Message${id}"
+msgstr "Message${id}"
+
+#: ../templates/classic/html/msg.item.html:21
+msgid "Message${id} Editing"
+msgstr "Meldung${id} bearbeiten"
+
+#: ../templates/classic/html/msg.item.html:28
+msgid "Author"
+msgstr "Autor"
+
+#: ../templates/classic/html/msg.item.html:33
+msgid "Recipients"
+msgstr "Empfänger"
+
+#: ../templates/classic/html/msg.item.html:44
+msgid "Content"
+msgstr "Inhalt"
+
+#: ../templates/classic/html/page.html:28
+msgid "<b>Your Queries</b> (<a href=\"query?@template=edit\">edit</a>)"
+msgstr "<b>Abfragen</b> (<a href=\"query?@template=edit\">bearbeiten</a>)"
+
+#: ../templates/classic/html/page.html:39
+msgid "Issues"
+msgstr "Aufgaben"
+
+#: ../templates/classic/html/page.html:41
+#: ../templates/classic/html/page.html:60
+msgid "Create New"
+msgstr "Neuer Eintrag"
+
+#: ../templates/classic/html/page.html:43
+msgid "Show Unassigned"
+msgstr "Nicht zugewiesen"
+
+#: ../templates/classic/html/page.html:45
+msgid "Show All"
+msgstr "Alle anzeigen"
+
+#: ../templates/classic/html/page.html:48
+msgid "Show issue:"
+msgstr "Aufgabe zeigen:"
+
+#: ../templates/classic/html/page.html:58
+msgid "Keywords"
+msgstr "Stichworte"
+
+#: ../templates/classic/html/page.html:64
+msgid "Edit Existing"
+msgstr "Bearbeiten"
+
+#: ../templates/classic/html/page.html:70
+#: ../templates/minimal/html/page.html:48
+msgid "Administration"
+msgstr "Administration"
+
+#: ../templates/classic/html/page.html:72
+#: ../templates/minimal/html/page.html:49
+msgid "Class List"
+msgstr "Klassenliste"
+
+#: ../templates/classic/html/page.html:76
+#: ../templates/minimal/html/page.html:51
+msgid "User List"
+msgstr "Benutzerliste"
+
+#: ../templates/classic/html/page.html:78
+#: ../templates/minimal/html/page.html:54
+msgid "Add User"
+msgstr "Benutzer hinzufügen"
+
+#: ../templates/classic/html/page.html:85
+#: ../templates/classic/html/page.html:89
+#: ../templates/minimal/html/page.html:30
+msgid "Login"
+msgstr "Anmelden"
+
+#: ../templates/classic/html/page.html:91
+#: ../templates/classic/html/user.register.html:63
+#: ../templates/minimal/html/page.html:33
+#: ../templates/minimal/html/user.register.html:58
+msgid "Register"
+msgstr "Registrieren"
+
+#: ../templates/classic/html/page.html:94
+msgid "Lost&nbsp;your&nbsp;login?"
+msgstr "Passwort&nbsp;vergessen?"
+
+#: ../templates/classic/html/page.html:99
+msgid "Hello, ${user}"
+msgstr "Guten Tag, ${user}"
+
+#: ../templates/classic/html/page.html:101
+msgid "Your Issues"
+msgstr "Ihre Aufgaben"
+
+#: ../templates/classic/html/page.html:102
+#: ../templates/minimal/html/page.html:40
+msgid "Your Details"
+msgstr "Ihr Konto"
+
+#: ../templates/classic/html/page.html:104
+#: ../templates/minimal/html/page.html:42
+msgid "Logout"
+msgstr "Abmelden"
+
+#: ../templates/classic/html/page.html:108
+msgid "Help"
+msgstr "Hilfe"
+
+#: ../templates/classic/html/page.html:109
+msgid "Roundup docs"
+msgstr "Roundup Handbuch"
+
+#: ../templates/classic/html/page.html:160
+msgid "don't care"
+msgstr "egal"
+
+#: ../templates/classic/html/page.html:162
+msgid "------------"
+msgstr "------------"
+
+#: ../templates/classic/html/page.html:188
+msgid "no value"
+msgstr "kein Wert"
+
+#: ../templates/classic/html/query.edit.html:4
+msgid "\"Your Queries\" Editing - ${tracker}"
+msgstr "\"Abfragen\" berabeiten - ${tracker}"
+
+#: ../templates/classic/html/query.edit.html:6
+msgid "\"Your Queries\" Editing"
+msgstr "\"Abfragen\" berabeiten"
+
+#: ../templates/classic/html/query.edit.html:11
+msgid "You are not allowed to edit queries."
+msgstr "Sie haben keine Berechtigung um Abfragen zu bearbeiten."
+
+#: ../templates/classic/html/query.edit.html:28
+msgid "Query"
+msgstr "Abfrage"
+
+#: ../templates/classic/html/query.edit.html:29
+msgid "Include in \"Your Queries\""
+msgstr "Unter \"Abfragen\" aufführen"
+
+#: ../templates/classic/html/query.edit.html:31
+msgid "Private to you?"
+msgstr "Nur für Sie?"
+
+#: ../templates/classic/html/query.edit.html:44
+msgid "leave out"
+msgstr "Nein"
+
+#: ../templates/classic/html/query.edit.html:45
+msgid "include"
+msgstr "Ja"
+
+#: ../templates/classic/html/query.edit.html:49
+msgid "leave in"
+msgstr "Ja"
+
+#: ../templates/classic/html/query.edit.html:54
+msgid "[query is retired]"
+msgstr "[Abfrage ist verborgen]"
+
+#: ../templates/classic/html/query.edit.html:67
+msgid "edit"
+msgstr "bearbeiten"
+
+#: ../templates/classic/html/query.edit.html:71
+msgid "yes"
+msgstr "ja"
+
+#: ../templates/classic/html/query.edit.html:73
+msgid "no"
+msgstr "nein"
+
+#: ../templates/classic/html/query.edit.html:79
+msgid "Delete"
+msgstr "Löschen"
+
+#: ../templates/classic/html/query.edit.html:90
+msgid "[not yours to edit]"
+msgstr "[nicht Ihr Eintrag]"
+
+#: ../templates/classic/html/query.edit.html:96
+msgid "Save Selection"
+msgstr "Auswahl speichern"
+
+#: ../templates/classic/html/user.forgotten.html:3
+msgid "Password reset request - ${tracker}"
+msgstr "Passwort zurücksetzen - ${tracker}"
+
+#: ../templates/classic/html/user.forgotten.html:5
+msgid "Password reset request"
+msgstr "Passwort zurücksetzen"
+
+#: ../templates/classic/html/user.forgotten.html:9
+msgid ""
+"You have two options if you have forgotten your password. If you know the "
+"email address you registered with, enter it below."
+msgstr ""
+"Um Ihr Passwort zurückzusetzen, geben Sie entweder die Email-Adresse an, mit "
+"welcher Sie sich registriert haben..."
+
+#: ../templates/classic/html/user.forgotten.html:16
+msgid "Email Address:"
+msgstr "Email-Adresse"
+
+#: ../templates/classic/html/user.forgotten.html:24
+#: ../templates/classic/html/user.forgotten.html:34
+msgid "Request password reset"
+msgstr "Passwort zurücksetzen"
+
+#: ../templates/classic/html/user.forgotten.html:30
+msgid "Or, if you know your username, then enter it below."
+msgstr "... oder Ihren Benutzernamen."
+
+#: ../templates/classic/html/user.forgotten.html:33
+msgid "Username:"
+msgstr "Benutzername:"
+
+#: ../templates/classic/html/user.forgotten.html:39
+msgid ""
+"A confirmation email will be sent to you - please follow the instructions "
+"within it to complete the reset process."
+msgstr ""
+"Danach wird ein Bestätigungs-Email verschickt. Bitte folgen Sie den "
+"Anweisungen im Email, um ihr Passwort zurückzusetzen."
+
+#: ../templates/classic/html/user.index.html:3
+#: ../templates/minimal/html/user.index.html:3
+msgid "User listing - ${tracker}"
+msgstr "Benutzerliste - ${tracker}"
+
+#: ../templates/classic/html/user.index.html:5
+#: ../templates/minimal/html/user.index.html:5
+msgid "User listing"
+msgstr "Benutzerliste"
+
+#: ../templates/classic/html/user.index.html:14
+#: ../templates/minimal/html/user.index.html:14
+msgid "Username"
+msgstr "Benutzername"
+
+#: ../templates/classic/html/user.index.html:15
+msgid "Real name"
+msgstr "Name"
+
+#: ../templates/classic/html/user.index.html:16
+#: ../templates/classic/html/user.item.html:65
+#: ../templates/classic/html/user.register.html:45
+msgid "Organisation"
+msgstr "Organisation"
+
+#: ../templates/classic/html/user.index.html:17
+#: ../templates/minimal/html/user.index.html:15
+msgid "Email address"
+msgstr "Email-Adresse"
+
+#: ../templates/classic/html/user.index.html:18
+msgid "Phone number"
+msgstr "Telefonnummer"
+
+#: ../templates/classic/html/user.index.html:19
+msgid "Retire"
+msgstr "Verbergen"
+
+#: ../templates/classic/html/user.index.html:32
+msgid "retire"
+msgstr "verbergen"
+
+#: ../templates/classic/html/user.item.html:7
+msgid "User ${id}: ${title} - ${tracker}"
+msgstr "Benutzer ${id}: ${title} - ${tracker}"
+
+#: ../templates/classic/html/user.item.html:10
+msgid "New User - ${tracker}"
+msgstr "Neuer Benutzer - ${tracker}"
+
+#: ../templates/classic/html/user.item.html:14
+#: ../templates/minimal/html/user.item.html:6
+msgid "New User"
+msgstr "Neuer Benutzer"
+
+#: ../templates/classic/html/user.item.html:16
+#: ../templates/minimal/html/user.item.html:8
+msgid "New User Editing"
+msgstr "Neuen Benutzer bearbeiten"
+
+#: ../templates/classic/html/user.item.html:19
+#: ../templates/minimal/html/user.item.html:11
+msgid "User${id}"
+msgstr "Benutzer${id}"
+
+#: ../templates/classic/html/user.item.html:22
+#: ../templates/minimal/html/user.item.html:14
+msgid "User${id} Editing"
+msgstr "Benutzer${id} bearbeiten"
+
+#: ../templates/classic/html/user.item.html:38
+#: ../templates/classic/html/user.register.html:21
+#: ../templates/minimal/html/user.item.html:27
+#: ../templates/minimal/html/user.item.html:67
+#: ../templates/minimal/html/user.register.html:26
+msgid "Login Name"
+msgstr "Benutzername"
+
+#: ../templates/classic/html/user.item.html:42
+#: ../templates/classic/html/user.register.html:25
+#: ../templates/minimal/html/user.item.html:31
+#: ../templates/minimal/html/user.register.html:30
+msgid "Login Password"
+msgstr "Passwort"
+
+#: ../templates/classic/html/user.item.html:46
+#: ../templates/classic/html/user.register.html:29
+#: ../templates/minimal/html/user.item.html:35
+#: ../templates/minimal/html/user.register.html:34
+msgid "Confirm Password"
+msgstr "Passwort bestätigen"
+
+#: ../templates/classic/html/user.item.html:50
+#: ../templates/classic/html/user.register.html:33
+#: ../templates/minimal/html/user.item.html:39
+#: ../templates/minimal/html/user.register.html:38
+msgid "Roles"
+msgstr "Rollen"
+
+#: ../templates/classic/html/user.item.html:56
+msgid "(to give the user more than one role, enter a comma,separated,list)"
+msgstr "Verwenden,Sie,Kommas, um einem Benutzer mehrere Rollen zuzuteilen"
+
+#: ../templates/classic/html/user.item.html:61
+#: ../templates/classic/html/user.register.html:41
+msgid "Phone"
+msgstr "Telefon"
+
+#: ../templates/classic/html/user.item.html:69
+msgid "Timezone"
+msgstr "Zeitzone"
+
+#: ../templates/classic/html/user.item.html:73
+msgid "(this is a numeric hour offset, the default is ${zone})"
+msgstr "Zeitverschiebung in Stunden - Voreinstellung: ${zone}"
+
+#: ../templates/classic/html/user.item.html:78
+#: ../templates/classic/html/user.register.html:49
+#: ../templates/minimal/html/user.item.html:47
+#: ../templates/minimal/html/user.item.html:71
+#: ../templates/minimal/html/user.register.html:46
+msgid "E-mail address"
+msgstr "Email-Adresse"
+
+#: ../templates/classic/html/user.item.html:82
+#: ../templates/classic/html/user.register.html:53
+#: ../templates/minimal/html/user.item.html:51
+#: ../templates/minimal/html/user.register.html:50
+msgid "Alternate E-mail addresses<br>One address per line"
+msgstr "Alternative Email-Adressen<br>Eine pro Zeile"
+
+#: ../templates/classic/html/user.register.html:4
+#: ../templates/classic/html/user.register.html:7
+#: ../templates/minimal/html/user.register.html:4
+#: ../templates/minimal/html/user.register.html:7
+msgid "Registering with ${tracker}"
+msgstr "Registrieren für ${tracker}"
+
+#: ../templates/classic/html/user.rego_progress.html:4
+#: ../templates/minimal/html/user.rego_progress.html:4
+msgid "Registration in progress - ${tracker}"
+msgstr "Die Registration is am laufen - ${tracker}"
+
+#: ../templates/classic/html/user.rego_progress.html:6
+#: ../templates/minimal/html/user.rego_progress.html:6
+msgid "Registration in progress..."
+msgstr "Die Registration ist am Gange..."
+
+#: ../templates/classic/html/user.rego_progress.html:10
+#: ../templates/minimal/html/user.rego_progress.html:10
+msgid ""
+"You will shortly receive an email to confirm your registration. To complete "
+"the registration process, visit the link indicated in the email."
+msgstr ""
+"Sie werden in Kürze ein Bestätigungs-Email erhalten. Um die Registrierung "
+"abzuschliessen, klicken Sie auf den Link im Email."
+
+#: ../templates/minimal/html/home.html:2
+msgid "Tracker home - ${tracker}"
+msgstr "Tracker Start - $ {tracker}"
+
+#: ../templates/minimal/html/home.html:4
+msgid "Tracker home"
+msgstr "Tracker Start"
+
+#: ../templates/minimal/html/home.html:16
+msgid "Please select from one of the menu options on the left."
+msgstr "Bitte wählen Sie links eine Menu-Option."
+
+#: ../templates/minimal/html/home.html:19
+msgid "Please log in or register."
+msgstr "Bitte anmelden oder registrieren"
+
+#: ../templates/minimal/html/page.html:38
+msgid "Hello,<br>${user}"
+msgstr "Guten Tag,<br>${user}"
+
+#: ../templates/minimal/html/user.item.html:3
+msgid "User editing - ${tracker}"
+msgstr "Benutzer bearbeiten - ${tracker}"

Added: tracker/vendor/roundup/current/locale/en.po
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/locale/en.po	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,20 @@
+# English message file for Roundup Issue Tracker
+#
+# $Id: en.po,v 1.2 2004/11/20 11:54:32 a1s Exp $
+#
+# roundup.pot revision 1.9
+#
+# Currently Roundup has no strings that need english translation.
+# This file is a dummy needed to provide the user with english UI
+# if 'en' is the first item in locale preference list and the list
+# also contains existing Roundup locale name.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Roundup 0.7.0\n"
+"Report-Msgid-Bugs-To: roundup-devel at lists.sourceforge.net\n"
+"POT-Creation-Date: 2004-07-13 13:24+0300\n"
+"PO-Revision-Date: 2004-11-20 13:47+0200\n"
+"Language-Team: English\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=us-ascii\n"

Added: tracker/vendor/roundup/current/locale/es_AR.po
==============================================================================
--- (empty file)
+++ tracker/vendor/roundup/current/locale/es_AR.po	Sun Nov  5 21:30:25 2006
@@ -0,0 +1,2978 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR See Roundup README.txt
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Roundup 0.8.4\n"
+"Report-Msgid-Bugs-To: roundup-devel at lists.sourceforge.net\n"
+"POT-Creation-Date: 2005-07-05 09:37+0300\n"
+"PO-Revision-Date: 2005-08-01 10:57:00-0300\n"
+"Last-Translator: Ramiro Morales <rm0 at gmx.net>\n"
+"Language-Team: Spanish Translators <roundup-devel at lists.sourceforge.net>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+# ../roundup/admin.py:85 :955 :1004 :1026
+#: ../roundup/admin.py:85
+#: ../roundup/admin.py:962
+#: ../roundup/admin.py:1011
+#: ../roundup/admin.py:1033
+#, python-format
+msgid "no such class \"%(classname)s\""
+msgstr "la clase \"%(classname)s\" no existe"
+
+# ../roundup/admin.py:95 :99
+#: ../roundup/admin.py:95
+#: ../roundup/admin.py:99
+#, python-format
+msgid "argument \"%(arg)s\" not propname=value"
+msgstr "el argumento \"%(arg)s\" no es de la forma nombrepropiedad=valor"
+
+#: ../roundup/admin.py:112
+#, python-format
+msgid ""
+"Problem: %(message)s\n"
+"\n"
+msgstr ""
+"Problema: %(message)s\n"
+"\n"
+
+#: ../roundup/admin.py:113
+#, python-format
+msgid ""
+"%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
+"\n"
+"Options:\n"
+" -i instance home  -- specify the issue tracker \"home directory\" to administer\n"
+" -u                -- the user[:password] to use for commands\n"
+" -d                -- print full designators not just class id numbers\n"
+" -c                -- when outputting lists of data, comma-separate them.\n"
+"                      Same as '-S \",\"'.\n"
+" -S <string>       -- when outputting lists of data, string-separate them\n"
+" -s                -- when outputting lists of data, space-separate them.\n"
+"                      Same as '-S \" \"'.\n"
+"\n"
+" Only one of -s, -c or -S can be specified.\n"
+"\n"
+"Help:\n"
+" roundup-admin -h\n"
+" roundup-admin help                       -- this help\n"
+" roundup-admin help <command>             -- command-specific help\n"
+" roundup-admin help all                   -- all available help\n"
+msgstr ""
+"%(message)sUso: roundup-admin [opciones] [<comando> <argumentos>]\n"
+"\n"
+"Opciones:\n"
+" -i base de instancia  -- especifica el \"directorio base\" del issue tracker\n"
+"                          sobre el cual se va a actuar\n"
+" -u                    -- usuario[:contraseña] a usarse para los comandos\n"
+" -d                    -- imprime designadores completos, no solamente números\n"
+"                          de identificación de clases\n"
+" -c                    -- separa los elementos con comas cuando se generan listas de\n"
+"                          salida.\n"
+"                          Equivalente a '-S \",\"'.\n"
+" -S <string>           -- separa los elementos con cadenas cuando se generan listas\n"
+"                          de salida\n"
+" -s                    -- separa los elementos con espacios cuando se generan listas\n"
+"                          de salida\n"
+"                          Equivalente a '-S \" \"'.\n"
+"\n"
+" Sólo puede especificarse una de las opciones -s, -c o -S.\n"
+"\n"
+"Ayuda:\n"
+" roundup-admin -h\n"
+" roundup-admin help                       -- esta ayuda\n"
+" roundup-admin help <comando>             -- ayuda específica a un comando\n"
+" roundup-admin help all                   -- toda la ayuda disponible\n"
+
+#: ../roundup/admin.py:138
+msgid "Commands:"
+msgstr "Comandos:"
+
+#: ../roundup/admin.py:145
+msgid ""
+"Commands may be abbreviated as long as the abbreviation\n"
+"matches only one command, e.g. l == li == lis == list."
+msgstr ""
+"Los comandos pueden ser abreviados siempre y cuando la abreviación\n"
+"coincida con sólo un comando, ej. l == li == lis == list."
+
+#: ../roundup/admin.py:175
+msgid ""
+"\n"
+"All commands (except help) require a tracker specifier. This is just\n"
+"the path to the roundup tracker you're working with. A roundup tracker\n"
+"is where roundup keeps the database and configuration file that defines\n"
+"an issue tracker. It may be thought of as the issue tracker's \"home\n"
+"directory\". It may be specified in the environment variable TRACKER_HOME\n"
+"or on the command line as \"-i tracker\".\n"
+"\n"
+"A designator is a classname and a nodeid concatenated, eg. bug1, user10, ...\n"
+"\n"
+"Property values are represented as strings in command arguments and in the\n"
+"printed results:\n"
+" . Strings are, well, strings.\n"
+" . Date values are printed in the full date format in the local time zone,\n"
+"   and accepted in the full format or any of the partial formats explained\n"
+"   below.\n"
+" . Link values are printed as node designators. When given as an argument,\n"
+"   node designators and key strings are both accepted.\n"
+" . Multilink values are printed as lists of node designators joined\n"
+"   by commas.  When given as an argument, node designators and key\n"
+"   strings are both accepted; an empty string, a single node, or a list\n"
+"   of nodes joined by commas is accepted.\n"
+"\n"
+"When property values must contain spaces, just surround the value with\n"
+"quotes, either ' or \". A single space may also be backslash-quoted. If a\n"
+"value must contain a quote character, it must be backslash-quoted or inside\n"
+"quotes. Examples:\n"
+"           hello world      (2 tokens: hello, world)\n"
+"           \"hello world\"    (1 token: hello world)\n"
+"           \"Roch'e\" Compaan (2 tokens: Roch'e Compaan)\n"
+"           Roch\\'e Compaan  (2 tokens: Roch'e Compaan)\n"
+"           address=\"1 2 3\"  (1 token: address=1 2 3)\n"
+"           \\\\               (1 token: \\)\n"
+"           \\n"
+"\\r\\t           (1 token: a newline, carriage-return and tab)\n"
+"\n"
+"When multiple nodes are specified to the roundup get or roundup set\n"
+"commands, the specified properties are retrieved or set on all the listed\n"
+"nodes.\n"
+"\n"
+"When multiple results are returned by the roundup get or roundup find\n"
+"commands, they are printed one per line (default) or joined by commas (with\n"
+"the -c) option.\n"
+"\n"
+"Where the command changes data, a login name/password is required. The\n"
+"login may be specified as either \"name\" or \"name:password\".\n"
+" . ROUNDUP_LOGIN environment variable\n"
+" . the -u command-line option\n"
+"If either the name or password is not supplied, they are obtained from the\n"
+"command-line.\n"
+"\n"
+"Date format examples:\n"
+"  \"2000-04-17.03:45\" means <Date 2000-04-17.08:45:00>\n"
+"  \"2000-04-17\" means <Date 2000-04-17.00:00:00>\n"
+"  \"01-25\" means <Date yyyy-01-25.00:00:00>\n"
+"  \"08-13.22:13\" means <Date yyyy-08-14.03:13:00>\n"
+"  \"11-07.09:32:43\" means <Date yyyy-11-07.14:32:43>\n"
+"  \"14:25\" means <Date yyyy-mm-dd.19:25:00>\n"
+"  \"8:47:11\" means <Date yyyy-mm-dd.13:47:11>\n"
+"  \".\" means \"right now\"\n"
+"\n"
+"Command help:\n"
+msgstr ""
+"\n"
+"Todos los comandos (excepto ayuda) requieren un especificador de tracker. Este es\n"
+"simplemente la ruta al tracker roundup con el que se está trabajando. Un\n"
+"tracker roundup es donde roundup mantiene la base de datos y el archivo de\n"
+"configuración que define un issue tracker. Puede pensarse en el mismo como el\n"
+"\"directorio personal\" del issue tracker. Puede especificarse en la variable\n"
+"de entorno TRACKER_HOME o en la línea de comandos como \"-i tracker\".\n"
+"\n"
+"Un designador es un nombre de clase y un id de nodo concatenados, ej. bug1, user10, ...\n"
+"\n"
+"Los valores de propiedades se representan como cadenas en argumentos de comandos y en\n"
+"resultados visualizados:\n"
+" . Las cadenas son, ahem, cadenas.\n"
+" . Los valores de fechas se imprimen en el formato de fecha completo y en el huso\n"
+"   horario local y se aceptan en el formato completo o cualquiera de los\n"
+"   formatos parciales descriptos mas abajo.\n"
+" . Los valores Link se imprimen como designadores de nodos. Cuando se pasan como\n"
+"   argumentos, se aceptan tanto los designadores de nodos como las cadenas clave.\n"
+" . Los valores Multilink se imprimen como listas de designadores de nodos unidos por\n"
+"   comas. Cuando se pasan como argumentos, se aceptan tanto los designadores de\n"
+"   nodos como las cadenas clave; tambien se aceptan una cadena vacía, un nodo\n"
+"   individual, o una lista de nodos unidos por comas.\n"
+"\n"
+"Cuando los valores de las propiedades deben contener espacios, simplemente\n"
+"escriba el valor entre comillas simples (') o dobles (\"). Un caracter espacio\n"
+"individual puede ser tambien representado prefijándolo con un caracter barra\n"
+"invertida (\\). Si un valor debe incluir un caracter comillas, debe prefijarse\n"
+"el mismo con un caracter barra invertida o escribirse entre comillas. Ejemplos:\n"
+"           hello world      (2 unidades: hello, world)\n"
+"           \"hello world\"    (1 unidad: hello world)\n"
+"           \"Roch'e\" Compaan (2 unidades: Roch'e Compaan)\n"
+"           Roch\\'e Compaan  (2 unidades: Roch'e Compaan)\n"
+"           address=\"1 2 3\"  (1 unidad: address=1 2 3)\n"
+"           \\\\               (1 unidad: \\)\n"
+"           \\n"
+"\\r\\t           (1 unidad: una línea nueva, retorno de carro y tabulación)\n"
+"\n"
+"Cuando se especifican múltiples nodos a los comandos roundup get y roundup set,\n"
+"los valores de las propiedades especificadas son recuperados o asignados en\n"
+"todos los nodos listados.\n"
+"\n"
+"Cuando los comandos roundup get o roundup find retornan múltiples resultados\n"
+"los mismos son impresos uno por línea (comportamiento por omisión) o unidos\n"
+"por comas (con la opción -c).\n"
+"\n"
+"Cuando un comando modifica algún dato, es obligatorio el uso de nombre de\n"
+"usuario/contraseña. Esta información puede especificarse como \"nombre\" o\n"
+"\"nombre:contraseña\" en\n"
+" . La variable de entorno ROUNDUP_LOGIN\n"
+" . La opción de línea de comandos -u\n"
+"Si no se proveen ya sea el nombre de usuario o la contraseña, los mismos se\n"
+"obtendrán de la línea de comandos.\n"
+"\n"
+"Ejemplos de formatos de fecha:\n"
+"  \"2000-04-17.03:45\" significa <Date 2000-04-17.08:45:00>\n"
+"  \"2000-04-17\" significa <Date 2000-04-17.00:00:00>\n"
+"  \"01-25\" significa <Date yyyy-01-25.00:00:00>\n"
+"  \"08-13.22:13\" significa <Date yyyy-08-14.03:13:00>\n"
+"  \"11-07.09:32:43\" significa <Date yyyy-11-07.14:32:43>\n"
+"  \"14:25\" significa <Date yyyy-mm-dd.19:25:00>\n"
+"  \"8:47:11\" significa <Date yyyy-mm-dd.13:47:11>\n"
+"  \".\" significa \"right now\"\n"
+"\n"
+"Ayuda del comando:\n"
+
+#: ../roundup/admin.py:238
+#, python-format
+msgid "%s:"
+msgstr ""
+
+#: ../roundup/admin.py:243
+msgid ""
+"Usage: help topic\n"
+"        Give help about topic.\n"
+"\n"
+"        commands  -- list commands\n"
+"        <command> -- help specific to a command\n"
+"        initopts  -- init command options\n"
+"        all       -- all available help\n"
+"        "
+msgstr ""
+"Uso: help tópico\n"
+"      Visualiza ayuda acerca del tópico.\n"
+"\n"
+"      commands  -- lista los comandos\n"
+"      <comando> -- ayuda específica a un comando\n"
+"      initopts  -- opciones del comando init\n"
+"      all       -- toda la ayuda disponible\n"
+"      "
+
+#: ../roundup/admin.py:266
+#, python-format
+msgid "Sorry, no help for \"%(topic)s\""
+msgstr "Lo siento, no hay ayuda para \"%(topic)s\""
+
+# ../roundup/admin.py:338 :387
+#: ../roundup/admin.py:338
+#: ../roundup/admin.py:387
+msgid "Templates:"
+msgstr "Plantillas:"
+
+# ../roundup/admin.py:341 :398
+#: ../roundup/admin.py:341
+#: ../roundup/admin.py:398
+msgid "Back ends:"
+msgstr "Motor de almacenamiento"
+
+#: ../roundup/admin.py:344
+msgid ""
+"Usage: install [template [backend [admin password]]]\n"
+"        Install a new Roundup tracker.\n"
+"\n"
+"        The command will prompt for the tracker home directory\n"
+"        (if not supplied through TRACKER_HOME or the -i option).\n"
+"        The template, backend and admin password may be specified\n"
+"        on the command-line as arguments, in that order.\n"
+"\n"
+"        The initialise command must be called after this command in order\n"
+"        to initialise the tracker's database. You may edit the tracker's\n"
+"        initial database contents before running that command by editing\n"
+"        the tracker's dbinit.py module init() function.\n"
+"\n"
+"        See also initopts help.\n"
+"        "
+msgstr ""
+"Uso: install [plantilla [backend [contraseña admin]]]\n"
+"      Instala un nuevo tracker Roundup.\n"
+"\n"
+"      El comando preguntará el directorio base del tracker\n"
+"      (si el mismo no se provee vía TRACKER_HOME o la opción -i).\n"
+"      La plantilla, el backend y la contraseña de admin pueden especificarse\n"
+"      en la línea de comandos como argumentos, en ese orden.\n"
+"\n"
+"      Luego de este comando debe usarse el comando initialise con el objetivo\n"
+"      de inicializar la base de datos del tracker. Ud. puede editar los contenidos\n"
+"      iniciales de la base de datos del tracker antes de ejecutar dicho comando\n"
+"      editando la funcion init() del módulo dbinit.py del tracker.\n"
+"\n"
+"      Vea también initopts help.\n"
+"      "
+
+# ../roundup/admin.py:360 :442 :503 :582 :632 :688 :709 :737 :808 :875 :946
+# :994 :1016 :1043 :1106 :1173
+#: ../roundup/admin.py:360
+#: ../roundup/admin.py:447
+#: ../roundup/admin.py:508
+#: ../roundup/admin.py:587
+#: ../roundup/admin.py:637
+#: ../roundup/admin.py:695
+#: ../roundup/admin.py:716
+#: ../roundup/admin.py:744
+#: ../roundup/admin.py:815
+#: ../roundup/admin.py:882
+#: ../roundup/admin.py:953
+#: ../roundup/admin.py:1001
+#: ../roundup/admin.py:1023
+#: ../roundup/admin.py:1050
+#: ../roundup/admin.py:1117
+#: ../roundup/admin.py:1184
+msgid "Not enough arguments supplied"
+msgstr "No se proveyó una cantidad suficiente de argumentos"
+
+#: ../roundup/admin.py:366
+#, python-format
+msgid "Instance home parent directory \"%(parent)s\" does not exist"
+msgstr "El directorio padre \"%(parent)s\" del directorio base de la instancia no existe"
+
+#: ../roundup/admin.py:374
+#, python-format
+msgid ""
+"WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
+"If you re-install it, you will lose all the data!\n"
+"Erase it? Y/N: "
+msgstr ""
+"ATENCIÓN: Aparentemente ya existe un tracker en \"%(tracker_home)s\"!\n"
+"Si Ud. lo reinstala, perderá toda la información relacionada al mismo!\n"
+"Elimino la misma? Y/N: "
+
+#: ../roundup/admin.py:389
+msgid "Select template [classic]: "
+msgstr "Seleccione la plantilla [classic]: "
+
+#: ../roundup/admin.py:400
+msgid "Select backend [anydbm]: "
+msgstr "Selecccione el motor de almacenamiento [anydbm]: "
+
+#: ../roundup/admin.py:409
+#, python-format
+msgid ""
+"\n"
+"---------------------------------------------------------------------------\n"
+" You should now edit the tracker configuration file:\n"
+"   %(config_file)s"
+msgstr ""
+"\n"
+"---------------------------------------------------------------------------\n"
+" Ud. debe ahora editar el archivo de configuración del tracker:\n"
+"   %(config_file)s"
+
+#: ../roundup/admin.py:419
+msgid " ... at a minimum, you must set following options:"
+msgstr " ... como mínimo, debe configurar las siguientes opciones:"
+
+#: ../roundup/admin.py:424
+#, python-format
+msgid ""
+"\n"
+" If you wish to modify the database schema,\n"
+" you should also edit the schema file:\n"
+"   %(database_config_file)s\n"
+" You may also change the database initialisation file:\n"
+"   %(database_init_file)s\n"
+" ... see the documentation on customizing for more information.\n"
+"\n"
+" You MUST run the \"roundup-admin initialise\" command once you've performed\n"
+" the above steps.\n"
+"---------------------------------------------------------------------------\n"
+msgstr ""
+"\n"
+" Si desea modificar el esquema de la base de datos,\n"
+" debe tambien editar el archivo de esquema:\n"
+"   %(database_config_file)s\n"
+" Puede también cambiar el archivo de inicialización de la base de datos:\n"
+"   %(database_init_file)s\n"
+" ... vea la documentación sobre personalización si desea más información.\n"
+"\n"
+" Ud. DEBE ejecutar el comando \"roundup-admin initialise\" una vez que haya\n"
+" completado los pasos arriba descriptos.\n"
+"---------------------------------------------------------------------------\n"
+
+#: ../roundup/admin.py:442
+msgid ""
+"Usage: genconfig <filename>\n"
+"        Generate a new tracker config file (ini style) with default values\n"
+"        in <filename>.\n"
+"        "
+msgstr ""
+"Uso: genconfig <archivo>\n"
+"      Genera un nuevo archivo de configuración de tracker (en formato ini) con\n"
+"      valores por defecto en el archivo <archivo>.\n"
+"      "
+
+#. password
+#: ../roundup/admin.py:452
+msgid ""
+"Usage: initialise [adminpw]\n"
+"        Initialise a new Roundup tracker.\n"
+"\n"
+"        The administrator details will be set at this step.\n"
+"\n"
+"        Execute the tracker's initialisation function dbinit.init()\n"
+"        "
+msgstr ""
+"Uso: initialise [contraseña-admin]\n"
+"      Inicializa un nuevo tracker Roundup.\n"
+"\n"
+"      Es en este paso cuando se configuran los detalles del usuario administrador.\n"
+"\n"
+"      Ejecuta la función de inicialización dbinit.init() del tracker\n"
+"      "
+
+#: ../roundup/admin.py:466
+msgid "Admin Password: "
+msgstr "Contraseña de administración: "
+
+#: ../roundup/admin.py:467
+msgid "       Confirm: "
+msgstr "       Confirmar: "
+
+#: ../roundup/admin.py:471
+msgid "Instance home does not exist"
+msgstr "El directorio base de la instancia no existe"
+
+#: ../roundup/admin.py:475
+msgid "Instance has not been installed"
+msgstr "La instancia no ha sido instalada"
+
+#: ../roundup/admin.py:480
+msgid ""
+"WARNING: The database is already initialised!\n"
+"If you re-initialise it, you will lose all the data!\n"
+"Erase it? Y/N: "
+msgstr ""
+"ATENCIÓN: La base de datos ya ha sido inicializada!\n"
+"Si la reinicializa, perderá toda la información!\n"
+"Eliminar la misma? Y/N: "
+
+#: ../roundup/admin.py:501
+msgid ""
+"Usage: get property designator[,designator]*\n"
+"        Get the given property of one or more designator(s).\n"
+"\n"
+"        Retrieves the property value of the nodes specified\n"
+"        by the designators.\n"
+"        "
+msgstr ""
+"Uso: get propiedad designador[,designador]*\n"
+"      Retorna la propiedad especificada de uno o mas designadores.\n"
+"\n"
+"      Recupera el valor de la propiedad de los nodos especificados\n"
+"      por los designadores.\n"
+"      "
+
+# ../roundup/admin.py:536 :551
+#: ../roundup/admin.py:541
+#: ../roundup/admin.py:556
+#, python-format
+msgid "property %s is not of type Multilink or Link so -d flag does not apply."
+msgstr "la propiededad %s no es de tipo Multilink o Link asi que el modificador -d no puede usarse."
+
+# ../roundup/admin.py:559 :957 :1006 :1028
+#: ../roundup/admin.py:564
+#: ../roundup/admin.py:964
+#: ../roundup/admin.py:1013
+#: ../roundup/admin.py:1035
+#, python-format
+msgid "no such %(classname)s node \"%(nodeid)s\""
+msgstr "no existe nodo de clase %(classname)s llamado  \"%(nodeid)s\""
+
+#: ../roundup/admin.py:566
+#, python-format
+msgid "no such %(classname)s property \"%(propname)s\""
+msgstr "no existe propiedad de clase %(classname)s llamado  \"%(propname)s\""
+
+#: ../roundup/admin.py:575
+msgid ""
+"Usage: set items property=value property=value ...\n"
+"        Set the given properties of one or more items(s).\n"
+"\n"
+"        The items are specified as a class or as a comma-separated\n"
+"        list of item designators (ie \"designator[,designator,...]\").\n"
+"\n"
+"        This command sets the properties to the values for all designators\n"
+"        given. If the value is missing (ie. \"property=\") then the property\n"
+"        is un-set. If the property is a multilink, you specify the linked\n"
+"        ids for the multilink as comma-separated numbers (ie \"1,2,3\").\n"
+"        "
+msgstr ""
+"Uso: set items propiedad=valor propiedad=valor ...\n"
+"      Establece las propiedades especificadas de uno o más ítems.\n"
+"\n"
+"      Los ítems se especifican como una clase o como una lista de designadores\n"
+"      de ítems (\"designador[,designador,...]\") separados por comas.\n"
+"\n"
+"      Este comando establece valores de las propiedades para todos los\n"
+"      designadores especificados. Si los valores no se especifican (\"propiedad=\")\n"
+"      entonces la propiedad se elimina. Si la propiedad es del tipo multilink, deben\n"
+"      especificarse los identificadores asociados como números separados por comas\n"
+"      (\"1,2,3\").\n"
+"      "
+
+#: ../roundup/admin.py:629
+msgid ""
+"Usage: find classname propname=value ...\n"
+"        Find the nodes of the given class with a given link property value.\n"
+"\n"
+"        Find the nodes of the given class with a given link property value.\n"
+"        The value may be either the nodeid of the linked node, or its key\n"
+"        value.\n"
+"        "
+msgstr ""
+"Uso: find nombreclase nombreprop=valor ...\n"
+"      Busca los nodos de la clase especificada que poseen un cierto valor de propiedad.\n"
+"\n"
+"      Busca los nodos de la clase especificada que poseen un cierto valor de propiedad.\n"
+"      El valor puede ser el identificador de nodo del nodo enlazado o su valor clave.\n"
+"      "
+
+# ../roundup/admin.py:675 :828 :840 :894
+#: ../roundup/admin.py:682
+#: ../roundup/admin.py:835
+#: ../roundup/admin.py:847
+#: ../roundup/admin.py:901
+#, python-format
+msgid "%(classname)s has no property \"%(propname)s\""
+msgstr "%(classname)s no posee la propiedad \"%(propname)s\""
+
+#: ../roundup/admin.py:689
+msgid ""
+"Usage: specification classname\n"
+"        Show the properties for a classname.\n"
+"\n"
+"        This lists the properties for a given class.\n"
+"        "
+msgstr ""
+"Uso: specification nombreclase\n"
+"      Muestra las propiedades para un nombre de clase.\n"
+"\n"
+"      Visualiza las propiedades para una cierta clase.\n"
+"      "
+
+#: ../roundup/admin.py:704
+#, python-format
+msgid "%(key)s: %(value)s (key property)"
+msgstr "%(key)s: %(value)s (propiedad de clave)"
+
+#: ../roundup/admin.py:706
+#, python-format
+msgid "%(key)s: %(value)s"
+msgstr ""
+
+#: ../roundup/admin.py:709
+msgid ""
+"Usage: display designator[,designator]*\n"
+"        Show the property values for the given node(s).\n"
+"\n"
+"        This lists the properties and their associated values for the given\n"
+"        node.\n"
+"        "
+msgstr ""
+"Uso: display designador[,designador]*\n"
+"      Muestra los valores de propiedeades para el/los nodo(s) especificados(s).\n"
+"\n"
+"      Lista las propiedades y sus valores asociados para el nodo especificado.\n"
+"      "
+
+#: ../roundup/admin.py:733
+#, python-format
+msgid "%(key)s: %(value)r"
+msgstr ""
+
+#: ../roundup/admin.py:736
+msgid ""
+"Usage: create classname property=value ...\n"
+"        Create a new entry of a given class.\n"
+"\n"
+"        This creates a new entry of the given class using the property\n"
+"        name=value arguments provided on the command line after the \"create\"\n"
+"        command.\n"
+"        "
+msgstr ""
+"Uso: create nombreclase propiedad=valor ...\n"
+"      Crea una nueva entrada de una clase especificada.\n"
+"\n"
+"      Crea una nueva entrada de la clase especificada usando los argumentos nombre=valor\n"
+"      provistos en la línea de comandos luego del comando \"create\" para establecer\n"
+"      valores de propiedad(es).      "
+
+#: ../roundup/admin.py:763
+#, python-format
+msgid "%(propname)s (Password): "
+msgstr "%(propname)s (Contraseña): "
+
+#: ../roundup/admin.py:765
+#, python-format
+msgid "   %(propname)s (Again): "
+msgstr "   %(propname)s (Nuevamente): "
+
+#: ../roundup/admin.py:767
+msgid "Sorry, try again..."
+msgstr "Lo lamento, intente nuevamente..."
+
+#: ../roundup/admin.py:771
+#, python-format
+msgid "%(propname)s (%(proptype)s): "
+msgstr ""
+
+#: ../roundup/admin.py:789
+#, python-format
+msgid "you must provide the \"%(propname)s\" property."
+msgstr "debe proveer la propiedad \"%(propname)s\"."
+
+#: ../roundup/admin.py:800
+msgid ""
+"Usage: list classname [property]\n"
+"        List the instances of a class.\n"
+"\n"
+"        Lists all instances of the given class. If the property is not\n"
+"        specified, the  \"label\" property is used. The label property is\n"
+"        tried in order: the key, \"name\", \"title\" and then the first\n"
+"        property, alphabetically.\n"
+"\n"
+"        With -c, -S or -s print a list of item id's if no property\n"
+"        specified.  If property specified, print list of that property\n"
+"        for every class instance.\n"
+"        "
+msgstr ""
+"Uso: list nombreclase [propiedad]\n"
+"      Lista las instancias de una clase.\n"
+"\n"
+"      Lista todas las instancias de la clase especificada. Si no se\n"
+"      especifica la propiedad, se usará la propiedad \"etiqueta\". La propiedad\n"
+"      etiqueta es obtenida siguiendo el siguiente orden: \"name\", \"title\"\n"
+"      y luego la primera propiedad en orden alfabético.\n"
+"\n"
+"      Cuando se usa -c, -S o -s imprime una lista de ids de items si no se ha especificado\n"
+"      propiedad. Si se ha especificado propiedad, imprime una lista de dicha propiedad\n"
+"      para cada instancia de la clase.\n"
+"      "
+
+#: ../roundup/admin.py:813
+msgid "Too many arguments supplied"
+msgstr "Demasiados argumentos"
+
+#: ../roundup/admin.py:849
+#, python-format
+msgid "%(nodeid)4s: %(value)s"
+msgstr ""
+
+#: ../roundup/admin.py:853
+msgid ""
+"Usage: table classname [property[,property]*]\n"
+"        List the instances of a class in tabular form.\n"
+"\n"
+"        Lists all instances of the given class. If the properties are not\n"
+"        specified, all properties are displayed. By default, the column\n"
+"        widths are the width of the largest value. The width may be\n"
+"        explicitly defined by defining the property as \"name:width\".\n"
+"        For example::\n"
+"\n"
+"          roundup> table priority id,name:10\n"
+"          Id Name\n"
+"          1  fatal-bug\n"
+"          2  bug\n"
+"          3  usability\n"
+"          4  feature\n"
+"\n"
+"        Also to make the width of the column the width of the label,\n"
+"        leave a trailing : without a width on the property. For example::\n"
+"\n"
+"          roundup> table priority id,name:\n"
+"          Id Name\n"
+"          1  fata\n"
+"          2  bug\n"
+"          3  usab\n"
+"          4  feat\n"
+"\n"
+"        will result in a the 4 character wide \"Name\" column.\n"
+"        "
+msgstr ""
+"Uso: table nombreclase [propiedad[,propiedad]*]\n"
+"      Lista las instancias de una clase en formato tabular.\n"
+"\n"
+"      Lista todas las instancias de la clase especificada. Si no se especifican\n"
+"      las propiedades, se visualizan todas las propiedades. Por omisión, los anchos\n"
+"      de las columnas son iguales a los anchos de valores mayores respectivos. Es\n"
+"      posible definir el ancho de columna de una propiedad definiendo la misma en la\n"
+"      forma \"nombre:ancho\".\n"
+"      Por ejemplo::\n"
+"\n"
+"        roundup> table priority id,name:10\n"
+"        Id Name\n"
+"        1  fatal-bug\n"
+"        2  bug\n"
+"        3  usability\n"
+"        4  feature\n"
+"\n"
+"      también, para obtener un ancho de columna igual al ancho de la etiqueta,\n"
+"      deje un : al final sin un valor de ancho de la propiedad. Por ejemplo::\n"
+"\n"
+"        roundup> table priority id,name:\n"
+"        Id Name\n"
+"        1  fata\n"
+"        2  bug\n"
+"        3  usab\n"
+"        4  feat\n"
+"\n"
+"      dará como resultado una columna \"Name\" con un ancho de 4 caracteres.\n"
+"      "
+
+#: ../roundup/admin.py:897
+#, python-format
+msgid "\"%(spec)s\" not name:width"
+msgstr "\"%(spec)s\" no es de la forma nombre:longitud"
+
+#: ../roundup/admin.py:947
+msgid ""
+"Usage: history designator\n"
+"        Show the history entries of a designator.\n"
+"\n"
+"        Lists the journal entries for the node identified by the designator.\n"
+"        "
+msgstr ""
+"Uso: history designador\n"
+"      Muestra las entradas en la historia de un designador.\n"
+"\n"
+"      Lista las entradas del journal para el nodo identificado por el designador.\n"
+"      "
+
+#: ../roundup/admin.py:968
+msgid ""
+"Usage: commit\n"
+"        Commit changes made to the database during an interactive session.\n"
+"\n"
+"        The changes made during an interactive session are not\n"
+"        automatically written to the database - they must be committed\n"
+"        using this command.\n"
+"\n"
+"        One-off commands on the command-line are automatically committed if\n"
+"        they are successful.\n"
+"        "
+msgstr ""
+"Uso: commit\n"
+"      Almacena definitivamente cambios realizados a la base de datos durante\n"
+"      una sesión interactiva.\n"
+"\n"
+"      Los cambios realizados durante una sesión interactiva no son automáticamente\n"
+"      escritos en la base de datos - los mismos deben ser escritos usando este comando\n"
+"\n"
+"      Comandos individuales realizados desde la línea de comandos son automáticamente\n"
+"      escritos si resultan exitosos.\n"
+"      "
+
+#: ../roundup/admin.py:982
+msgid ""
+"Usage: rollback\n"
+"        Undo all changes that are pending commit to the database.\n"
+"\n"
+"        The changes made during an interactive session are not\n"
+"        automatically written to the database - they must be committed\n"
+"        manually. This command undoes all those changes, so a commit\n"
+"        immediately after would make no changes to the database.\n"
+"        "
+msgstr ""
+"Uso: rollback\n"
+"      Deshace todos los cambios que están pendientes de ser escritos\n"
+"      definitivamente en la base de datos.\n"
+"\n"
+"      Los cambios hechos durante una sesión interactiva no son automáticamente\n"
+"      escritos en la base de datos - los mismos deben ser grabados manualmente.\n"
+"      Este comando deshace todos dichos cambios, de manera que un comando commit\n"
+"      inmediatamente posterior no introduciría cambios en la base de datos.\n"
+"      "
+
+#: ../roundup/admin.py:994
+msgid ""
+"Usage: retire designator[,designator]*\n"
+"        Retire the node specified by designator.\n"
+"\n"
+"        This action indicates that a particular node is not to be retrieved\n"
+"        by the list or find commands, and its key value may be re-used.\n"
+"        "
+msgstr ""
+"Uso: retire designador[,designador]*\n"
+"      Retira el nodo especificado por designador.\n"
+"\n"
+"      Esta acción indica que un nodo particular no se obtendrá cuando se\n"
+"      usen los comandos list y find, y que su valor clave podrá ser reusado.\n"
+"      "
+
+#: ../roundup/admin.py:1017
+msgid ""
+"Usage: restore designator[,designator]*\n"
+"        Restore the retired node specified by designator.\n"
+"\n"
+"        The given nodes will become available for users again.\n"
+"        "
+msgstr ""
+"Uso: restore designador[,designador]*\n"
+"      Restaura el nodo retirado especificado por designador.\n"
+"\n"
+"      Los nodos especificados volverán a estar nuevamente disponibles para los usuarios.\n"
+"      "
+
+#. grab the directory to export to
+#: ../roundup/admin.py:1039
+msgid ""
+"Usage: export [class[,class]] export_dir\n"
+"        Export the database to colon-separated-value files.\n"
+"\n"
+"        Optionally limit the export to just the names classes.\n"
+"\n"
+"        This action exports the current data from the database into\n"
+"        colon-separated-value files that are placed in the nominated\n"
+"        destination directory.\n"
+"        "
+msgstr ""
+"Uso: export [clase[,clase]] export_dir\n"
+"      Exporta la base de datos a archivos de valores separados por comas.\n"
+"\n"
+"      Opcionalmente limita la exportación sólo a las clases especificadas.\n"
+"\n"
+"      Esta acción exporta los datos actuales desde la base de datos a\n"
+"      archivos de valores separados por comas que se colocarán en el directorio\n"
+"      de destino especificado (export_dir).\n"
+"      "
+
+#: ../roundup/admin.py:1097
+msgid ""
+"Usage: import import_dir\n"
+"        Import a database from the directory containing CSV files,\n"
+"        two per class to import.\n"
+"\n"
+"        The files used in the import are:\n"
+"\n"
+"        <class>.csv\n"
+"          This must define the same properties as the class (including\n"
+"          having a \"header\" line with those property names.)\n"
+"        <class>-journals.csv\n"
+"          This defines the journals for the items being imported.\n"
+"\n"
+"        The imported nodes will have the same nodeid as defined in the\n"
+"        import file, thus replacing any existing content.\n"
+"\n"
+"        The new nodes are added to the existing database - if you want to\n"
+"        create a new database using the imported data, then create a new\n"
+"        database (or, tediously, retire all the old data.)\n"
+"        "
+msgstr ""
+"Uso: import import_dir\n"
+"      Importa una base de datos desde el directorio conteniendo archivos CSV,\n"
+"      dos por cada clase a importar.\n"
+"\n"
+"      Los archivos usados en la importación son::\n"
+"\n"
+"      <clase>.csv\n"
+"        Este debe definir las mismas propiedades que la clase (esto incluye la\n"
+"        existencia de una línea \"encabezado\" con los nombre de dichas propiedades.)\n"
+"      <clase>-journals.csv\n"
+"        Este define los journals para los items que se están importando.\n"
+"\n"
+"        Los nodos importados tendrán los mismos id´s que los nodos según se encontraban\n"
+"        definidos en el arvhivo importado, por lo tanto reemplazarán todo contenido\n"
+"        preexistente.\n"
+"\n"
+"        Los nuevos nodos son agregados a la base de datos existente - si Ud. desea\n"
+"        crear una base de datos nueva usando los datos importados, entonces puede\n"
+"        crear una nueva base de datos (o, tediosamente, retirar toda los datos viejos.)\n"
+"        "
+
+#: ../roundup/admin.py:1166
+msgid ""
+"Usage: pack period | date\n"
+"\n"
+"        Remove journal entries older than a period of time specified or\n"
+"        before a certain date.\n"
+"\n"
+"        A period is specified using the suffixes \"y\", \"m\", and \"d\". The\n"
+"        suffix \"w\" (for \"week\") means 7 days.\n"
+"\n"
+"              \"3y\" means three years\n"
+"              \"2y 1m\" means two years and one month\n"
+"              \"1m 25d\" means one month and 25 days\n"
+"              \"2w 3d\" means two weeks and three days\n"
+"\n"
+"        Date format is \"YYYY-MM-DD\" eg:\n"
+"            2001-01-01\n"
+"\n"
+"        "
+msgstr ""
+"Uso: pack período |fecha\n"
+"\n"
+"      Elimina entradas de journal mas viejas que un período de tiempo\n"
+"      especificado o anteriores a cierta fecha.\n"
+"\n"
+"      Un período se especifica usando los sufijos \"y\", \"m\", and \"d\". El\n"
+"      sufijo \"w\" (por \"week\") significa 7 días.\n"
+"\n"
+"            \"3y\" significa tres años\n"
+"            \"2y 1m\" significa dos años y un mes\n"
+"            \"1m 25d\" significa un mes y 25 días\n"
+"            \"2w 3d\" significa dos semanas y tres días\n"
+"\n"
+"      El formato de fecha es \"YYYY-MM-DD\" ej.:\n"
+"          2001-01-01\n"
+"\n"
+"      "
+
+#: ../roundup/admin.py:1194
+msgid "Invalid format"
+msgstr "Formato inválido"
+
+#: ../roundup/admin.py:1204
+msgid ""
+"Usage: reindex [classname|designator]*\n"
+"        Re-generate a tracker's search indexes.\n"
+"\n"
+"        This will re-generate the search indexes for a tracker.\n"
+"        This will typically happen automatically.\n"
+"        "
+msgstr ""
+"Uso: reindex [nombreclase|designador]*\n"
+"      Regenera los índices de búsqueda de un tracker.\n"
+"\n"
+"      Este comando regenerará los índices de búsqueda de un tracker.\n"
+"      Es un comando que por lo general se ejecuta automáticamente.\n"
+"      "
+
+#: ../roundup/admin.py:1218
+#, python-format
+msgid "no such item \"%(designator)s\""
+msgstr "no existe un ítem llamado \"%(designator)s\""
+
+#: ../roundup/admin.py:1228
+msgid ""
+"Usage: security [Role name]\n"
+"        Display the Permissions available to one or all Roles.\n"
+"        "
+msgstr ""
+"Uso: security [Nombre de rol]\n"
+"      Muestra los permisos disponibles para uno o todos los Roles.\n"
+"      "
+
+#: ../roundup/admin.py:1236
+#, python-format
+msgid "No such Role \"%(role)s\""
+msgstr "No existe un Rol llamado \"%(role)s\""
+
+#: ../roundup/admin.py:1242
+#, python-format
+msgid "New Web users get the Roles \"%(role)s\""
+msgstr "Los nuevos usuarios creados vía Web obtiene los Roles \"%(role)s\""
+
+#: ../roundup/admin.py:1244
+#, python-format
+msgid "New Web users get the Role \"%(role)s\""
+msgstr "Los nuevos usuarios creados vía Web obtienen el Rol \"%(role)s\""
+
+#: ../roundup/admin.py:1247
+#, python-format
+msgid "New Email users get the Roles \"%(role)s\""
+msgstr "Los nuevos usuarios creados vía e-mail obtienen los Roles  \"%(role)s\""
+
+#: ../roundup/admin.py:1249
+#, python-format
+msgid "New Email users get the Role \"%(role)s\""
+msgstr "Los nuevos usuarios creados vía e-mail obtienen el Rol \"%(role)s\""
+
+#: ../roundup/admin.py:1252
+#, python-format
+msgid "Role \"%(name)s\":"
+msgstr "Rol \"%(name)s\":"
+
+#: ../roundup/admin.py:1257
+#, python-format
+msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)"
+msgstr " %(description)s (%(name)s para \"%(klass)s\": %(properties)s solamente)"
+
+#: ../roundup/admin.py:1260
+#, python-format
+msgid " %(description)s (%(name)s for \"%(klass)s\" only)"
+msgstr " %(description)s (%(name)s para \"%(klass)s\" solamente)"
+
+#: ../roundup/admin.py:1263
+#, python-format
+msgid " %(description)s (%(name)s)"
+msgstr ""
+
+#: ../roundup/admin.py:1292
+#, python-format
+msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
+msgstr "Comando desconocido \"%(command)s\" (tipee \"help commands\" para obtener una lista)"
+
+#: ../roundup/admin.py:1298
+#, python-format
+msgid "Multiple commands match \"%(command)s\": %(list)s"
+msgstr "Coinciden mas de un comando \"%(command)s\": %(list)s"
+
+#: ../roundup/admin.py:1305
+msgid "Enter tracker home: "
+msgstr "Ingrese directorio base del tracker: "
+
+# ../roundup/admin.py:1296 :1302 :1322
+#: ../roundup/admin.py:1312
+#: ../roundup/admin.py:1318
+#: ../roundup/admin.py:1338
+#, python-format
+msgid "Error: %(message)s"
+msgstr ""
+
+#: ../roundup/admin.py:1326
+#, python-format
+msgid "Error: Couldn't open tracker: %(message)s"
+msgstr "Error: No se pudo abrir el tracker: %(message)s"
+
+#: ../roundup/admin.py:1351
+#, python-format
+msgid ""
+"Roundup %s ready for input.\n"
+"Type \"help\" for help."
+msgstr ""
+"Roundup %s listo para comandos.\n"
+"Tipee \"help\" para ayuda."
+
+#: ../roundup/admin.py:1356
+msgid "Note: command history and editing not available"
+msgstr "Nota: historia y edición de comandos no disponible"
+
+#: ../roundup/admin.py:1360
+msgid "roundup> "
+msgstr ""
+
+#: ../roundup/admin.py:1362
+msgid "exit..."
+msgstr "salir..."
+
+#: ../roundup/admin.py:1372
+msgid "There are unsaved changes. Commit them (y/N)? "
+msgstr "Hay cambios sin guardar. Debo guardar los mismos (y/N)? "
+
+#: ../roundup/backends/back_anydbm.py:2061
+#, python-format
+msgid "WARNING: invalid date tuple %r"
+msgstr "ATENCIÓN: tuple de fecha inválido %r"
+
+#: ../roundup/backends/rdbms_common.py:1431
+msgid "create"
+msgstr "crear"
+
+#: ../roundup/backends/rdbms_common.py:1597
+msgid "unlink"
+msgstr "desenlazar"
+
+#: ../roundup/backends/rdbms_common.py:1601
+msgid "link"
+msgstr "enlazar"
+
+#: ../roundup/backends/rdbms_common.py:1720
+msgid "set"
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:1744
+msgid "retired"
+msgstr "retirado"
+
+#: ../roundup/backends/rdbms_common.py:1774
+msgid "restored"
+msgstr "restaurado"
+
+#: ../roundup/cgi/actions.py:58
+#, python-format
+msgid "You do not have permission to %(action)s the %(classname)s class."
+msgstr "Ud. no posee los permisos necesarios para %(action)s la clase %(classname)s."
+
+#: ../roundup/cgi/actions.py:89
+msgid "No type specified"
+msgstr "No se especificó un tipo"
+
+#: ../roundup/cgi/actions.py:91
+msgid "No ID entered"
+msgstr "No se ingresó un ID"
+
+#: ../roundup/cgi/actions.py:97
+#, python-format
+msgid "\"%(input)s\" is not an ID (%(classname)s ID required)"
+msgstr "\"%(input)s\" no es un ID (se requieren IDs %(classname)s)"
+
+#: ../roundup/cgi/actions.py:117
+msgid "You may not retire the admin or anonymous user"
+msgstr "Ni el usuario admin ni el usuario anónimo pueden ser retirados"
+
+#: ../roundup/cgi/actions.py:124
+#, python-format
+msgid "%(classname)s %(itemid)s has been retired"
+msgstr "%(classname)s %(itemid)s ha sido retirado"
+
+# ../roundup/cgi/actions.py:163 :191
+#: ../roundup/cgi/actions.py:163
+#: ../roundup/cgi/actions.py:191
+msgid "You do not have permission to edit queries"
+msgstr "Ud. no posee los permisos necesarios para editar consultas"
+
+# ../roundup/cgi/actions.py:169 :197
+#: ../roundup/cgi/actions.py:169
+#: ../roundup/cgi/actions.py:197
+msgid "You do not have permission to store queries"
+msgstr "Ud. no posee los permisos necesarios para grabar consultas"
+
+#: ../roundup/cgi/actions.py:286
+#, python-format
+msgid "Not enough values on line %(line)s"
+msgstr "No hay valores suficientes en la línea %(line)s"
+
+#: ../roundup/cgi/actions.py:333
+msgid "Items edited OK"
+msgstr "Items editados exitosamente"
+
+#: ../roundup/cgi/actions.py:393
+#, python-format
+msgid "%(class)s %(id)s %(properties)s edited ok"
+msgstr "%(properties)s de %(class)s %(id)s editados exitosamente"
+
+#: ../roundup/cgi/actions.py:396
+#, python-format
+msgid "%(class)s %(id)s - nothing changed"
+msgstr "%(class)s %(id)s - sin modificaciones"
+
+#: ../roundup/cgi/actions.py:408
+#, python-format
+msgid "%(class)s %(id)s created"
+msgstr "%(class)s %(id)s creado"
+
+#: ../roundup/cgi/actions.py:440
+#, python-format
+msgid "You do not have permission to edit %(class)s"
+msgstr "Ud. no posee los permisos necesarios para editar %(class)s"
+
+#: ../roundup/cgi/actions.py:452
+#, python-format
+msgid "You do not have permission to create %(class)s"
+msgstr "Ud. no posee los permisos necesarios para crear %(class)s"
+
+#: ../roundup/cgi/actions.py:475
+msgid "You do not have permission to edit user roles"
+msgstr "Ud. no posee los permisos necesarios para editar roles de usuario"
+
+#: ../roundup/cgi/actions.py:519
+#, python-format
+msgid "Edit Error: someone else has edited this %s (%s). View <a target=\"new\" href=\"%s%s\">their changes</a> in a new window."
+msgstr "Error de edición: Alguien más ha editado este %s (%s). Vea los <a target=\"new\" href=\"%s%s\">cambios</a> que dicha persona ha realizado en una ventana aparte."
+
+#: ../roundup/cgi/actions.py:548
+#, python-format
+msgid "Edit Error: %s"
+msgstr "Error de edición: %s"
+
+# ../roundup/cgi/actions.py:579 :590 :761 :780
+#: ../roundup/cgi/actions.py:579
+#: ../roundup/cgi/actions.py:590
+#: ../roundup/cgi/actions.py:761
+#: ../roundup/cgi/actions.py:780
+#, python-format
+msgid "Error: %s"
+msgstr ""
+
+#: ../roundup/cgi/actions.py:616
+msgid ""
+"Invalid One Time Key!\n"
+"(a Mozilla bug may cause this message to show up erroneously, please check your email)"
+msgstr ""
+"One Time Key inválida!\n"
+"(un bug de Mozilla puede ser el causante de que se visualice este mensaje en forma errónea, por favor verifique su casilla de e-mail)"
+
+#: ../roundup/cgi/actions.py:658
+#, python-format
+msgid "Password reset and email sent to %s"
+msgstr "Contraseña reinicializada y mensaje de e-mail enviado a %s"
+
+#: ../roundup/cgi/actions.py:667
+msgid "Unknown username"
+msgstr "Usuario desconocido"
+
+#: ../roundup/cgi/actions.py:675
+msgid "Unknown email address"
+msgstr "Dirección de e-mail desconocida"
+
+#: ../roundup/cgi/actions.py:680
+msgid "You need to specify a username or address"
+msgstr "Debe especificar un nombre de usuario o dirección de e-mail"
+
+#: ../roundup/cgi/actions.py:705
+#, python-format
+msgid "Email sent to %s"
+msgstr "Se ha enviado un mensaje de e-mail a %s"
+
+#: ../roundup/cgi/actions.py:724
+msgid "You are now registered, welcome!"
+msgstr "Ud. se ha registrado exitosamente, bienvenido!"
+
+#: ../roundup/cgi/actions.py:769
+msgid "It is not permitted to supply roles at registration."
+msgstr "No está permitido especificar roles en el momento del registro."
+
+#: ../roundup/cgi/actions.py:852
+msgid "You are logged out"
+msgstr "Ha salido del sistema exitosamente"
+
+#: ../roundup/cgi/actions.py:869
+msgid "Username required"
+msgstr "Se requiere el ingreso de un nombre de usuario"
+
+# ../roundup/cgi/actions.py:891 :895
+#: ../roundup/cgi/actions.py:897
+#: ../roundup/cgi/actions.py:901
+msgid "Invalid login"
+msgstr "nombre de usuario ó contraseña inválidos"
+
+#: ../roundup/cgi/actions.py:907
+msgid "You do not have permission to login"
+msgstr "Ud. no tiene permiso para ingresar al sistema"
+
+#: ../roundup/cgi/cgitb.py:49
+#, python-format
+msgid ""
+"<h1>Templating Error</h1>\n"
+"<p><b>%(exc_type)s</b>: %(exc_value)s</p>\n"
+"<p class=\"help\">Debugging information follows</p>"
+msgstr ""
+"<h1>Error de Templating</h1>\n"
+"<p><b>%(exc_type)s</b>: %(exc_value)s</p>\n"
+"<p class=\"help\">Información de depuración:</p>"
+
+#: ../roundup/cgi/cgitb.py:64
+#, python-format
+msgid "<li>\"%(name)s\" (%(info)s)</li>"
+msgstr ""
+
+#: ../roundup/cgi/cgitb.py:67
+#, python-format
+msgid "<li>Looking for \"%(name)s\", current path:<ol>%(path)s</ol></li>"
+msgstr "<li>Buscando \"%(name)s\", ruta actual:<ol>%(path)s</ol></li>"
+
+#: ../roundup/cgi/cgitb.py:71
+#, python-format
+msgid "<li>In %s</li>"
+msgstr "<li>En %s</li>"
+
+#: ../roundup/cgi/cgitb.py:76
+#, python-format
+msgid "A problem occurred in your template \"%s\"."
+msgstr "Ha ocurrido un problema en su template \"%s\"."
+
+#: ../roundup/cgi/cgitb.py:84
+#, python-format
+msgid ""
+"\n"
+"<li>While evaluating the %(info)r expression on line %(line)d\n"
+"<table class=\"otherinfo\" style=\"font-size: 90%%\">\n"
+" <tr><th colspan=\"2\" class=\"header\">Current variables:</th></tr>\n"
+" %(globals)s\n"
+" %(locals)s\n"
+"</table></li>\n"
+msgstr ""
+"\n"
+"<li>Cuando se evaluaba la expresión %(info)r en la línea %(line)d\n"
+"<table class=\"otherinfo\" style=\"font-size: 90%%\">\n"
+" <tr><th colspan=\"2\" class=\"header\">Variables activas:</th></tr>\n"
+" %(globals)s\n"
+" %(locals)s\n"
+"</table></li>\n"
+
+#: ../roundup/cgi/cgitb.py:103
+msgid "Full traceback:"
+msgstr "Traza completa"
+
+#: ../roundup/cgi/cgitb.py:116
+#, python-format
+msgid "<font size=+1><strong>%(exc_type)s</strong>: %(exc_value)s</font>"
+msgstr ""
+
+#: ../roundup/cgi/cgitb.py:120
+msgid "<p>A problem occurred while running a Python script. Here is the sequence of function calls leading up to the error, with the most recent (innermost) call first. The exception attributes are:"
+msgstr "<p>Ha ocurrido un problema ejecutando un script Python. Esta es la secuencia de llamadas a funciones que llevaron al error, con la llamada mas reciente (la mas anidada) ubicada primera. Los atributos de la excepción son:"
+
+#: ../roundup/cgi/cgitb.py:129
+msgid "&lt;file is None - probably inside <tt>eval</tt> or <tt>exec</tt>&gt;"
+msgstr "&lt;file es None - probablemente dentro de <tt>eval</tt> or <tt>exec</tt>&gt;"
+
+#: ../roundup/cgi/cgitb.py:138
+#, python-format
+msgid "in <strong>%s</strong>"
+msgstr "en <strong>%s</strong>"
+
+# ../roundup/cgi/cgitb.py:172 :178
+#: ../roundup/cgi/cgitb.py:172
+#: ../roundup/cgi/cgitb.py:178
+msgid "<em>undefined</em>"
+msgstr "<em>indefinido/a</em>"
+
+#: ../roundup/cgi/client.py:297
+msgid "Form Error: "
+msgstr "Error de formulario"
+
+#: ../roundup/cgi/client.py:350
+#, python-format
+msgid "Unrecognized charset: %r"
+msgstr "Conjunto de caracteres desconocido: %r"
+
+#: ../roundup/cgi/client.py:453
+msgid "Anonymous users are not allowed to use the web interface"
+msgstr "Los usuarios anonimos no tienen permitido usar esta interfaz Web"
+
+#: ../roundup/cgi/client.py:604
+msgid "You are not allowed to view this file."
+msgstr "Ud. no tiene permitido ver este archivo"
+
+#: ../roundup/cgi/client.py:696
+#, python-format
+msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
+msgstr "%(starttag)sTiempo transcurrido: %(seconds)fs%(endtag)s\n"
+
+#: ../roundup/cgi/client.py:700
+#, python-format
+msgid "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading items: %(get_items)f secs. Filtering: %(filtering)f secs.%(endtag)s\n"
+msgstr "%(starttag)sAciertos Cache: %(cache_hits)d, no aciertos %(cache_misses)d. Cargando items: %(get_items)f secs. Filtrado: %(filtering)f secs.%(endtag)s\n"
+
+#: ../roundup/cgi/form_parser.py:283
+#, python-format
+msgid "link \"%(key)s\" value \"%(value)s\" not a designator"
+msgstr "el enlace \"%(key)s\" valor \"%(value)s\" no es un designador"
+
+#: ../roundup/cgi/form_parser.py:290
+#, python-format
+msgid "%(class)s %(property)s is not a link or multilink property"
+msgstr "%(property)s de %(class)s no es una propiedad enlace o multilink"
+
+#: ../roundup/cgi/form_parser.py:312
+#, python-format
+msgid "You have submitted a %(action)s action for the property \"%(property)s\" which doesn't exist"
+msgstr "Ha ingresado una acción %(action)s para la propiedad \"%(property)s\" que no existe"
+
+# ../roundup/cgi/form_parser.py:331 :357
+#: ../roundup/cgi/form_parser.py:331
+#: ../roundup/cgi/form_parser.py:357
+#, python-format
+msgid "You have submitted more than one value for the %s property"
+msgstr "Ha ingresado más de un valor para la propiedad %s"
+
+# ../roundup/cgi/form_parser.py:354 :360
+#: ../roundup/cgi/form_parser.py:354
+#: ../roundup/cgi/form_parser.py:360
+msgid "Password and confirmation text do not match"
+msgstr "La contraseña y el texto de confirmación no coinciden"
+
+#: ../roundup/cgi/form_parser.py:395
+#, python-format
+msgid "property \"%(propname)s\": \"%(value)s\" not currently in list"
+msgstr "propiedad \"%(propname)s\": \"%(value)s\" no se encuentra en este momento en la lista"
+
+#: ../roundup/cgi/form_parser.py:509
+#, python-format
+msgid "Required %(class)s property %(property)s not supplied"
+msgid_plural "Required %(class)s properties %(property)s not supplied"
+msgstr[0] "La propiedad %(property)s de la clase %(class)s es obligatoria y no se ha provisto"
+msgstr[1] "Las propiedades %(property)s de la clase %(class)s son obligatorias y no se han provisto"
+
+#: ../roundup/cgi/form_parser.py:532
+msgid "File is empty"
+msgstr "El archivo está vacío"
+
+#: ../roundup/cgi/templating.py:69
+#, python-format
+msgid "You are not allowed to %(action)s items of class %(class)s"
+msgstr "Ud. no tiene permitido %(action)s items de la clase %(class)s"
+
+#: ../roundup/cgi/templating.py:623
+msgid "(list)"
+msgstr "(lista)"
+
+#: ../roundup/cgi/templating.py:687
+msgid "Submit New Entry"
+msgstr "Crear nuevo elemento"
+
+# ../roundup/cgi/templating.py:673 :792 :1166 :1187 :1231 :1253 :1287 :1326
+# :1377 :1394 :1470 :1490 :1503 :1520 :1530 :1580 :1755
+#: ../roundup/cgi/templating.py:701
+#: ../roundup/cgi/templating.py:820
+#: ../roundup/cgi/templating.py:1194
+#: ../roundup/cgi/templating.py:1215
+#: ../roundup/cgi/templating.py:1259
+#: ../roundup/cgi/templating.py:1281
+#: ../roundup/cgi/templating.py:1315
+#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1405
+#: ../roundup/cgi/templating.py:1422
+#: ../roundup/cgi/templating.py:1498
+#: ../roundup/cgi/templating.py:1518
+#: ../roundup/cgi/templating.py:1531
+#: ../roundup/cgi/templating.py:1563
+#: ../roundup/cgi/templating.py:1573
+#: ../roundup/cgi/templating.py:162