[med-svn] [python-clips] 05/07: New upstream version 1.0.7.348+clips

Andreas Tille tille at debian.org
Thu Oct 5 17:58:24 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository python-clips.

commit 4575f096922c8e70f0da26ef5a91a47280ddc718
Author: Andreas Tille <tille at debian.org>
Date:   Thu Oct 5 19:47:38 2017 +0200

    New upstream version 1.0.7.348+clips
---
 CLIPSSrc.zip                            |   Bin 0 -> 1084659 bytes
 FAQ                                     |   351 +
 README                                  |   292 +
 clips/__init__.py                       |    56 +
 clips/_clips_wrap.py                    |  4347 +++++++
 clips/_license.py                       |   362 +
 clips_or.c                              |   421 +
 clips_or.h                              |    37 +
 clipsmodule.c                           | 19650 ++++++++++++++++++++++++++++++
 clipsmodule.h                           |   119 +
 debian/changelog                        |    18 -
 debian/compat                           |     1 -
 debian/control                          |    23 -
 debian/copyright                        |    64 -
 debian/get-orig-source                  |    32 -
 debian/patches/reproducible-build.patch |    14 -
 debian/patches/series                   |     1 -
 debian/rules                            |    19 -
 debian/source/format                    |     1 -
 debian/watch                            |     2 -
 doc/appendix.tex                        |   731 ++
 doc/contents.tex                        |   702 ++
 doc/copyright.tex                       |     6 +
 doc/defs.tex                            |    24 +
 doc/intro.tex                           |   537 +
 doc/license.tex                         |    14 +
 doc/license.txt                         |   356 +
 doc/objects.tex                         |  1837 +++
 doc/pyclips.tex                         |    71 +
 doc/zebra.clp                           |   210 +
 loptr.c                                 |   194 +
 optpatch/classexm.h-01.v6.23-test.diff  |    20 +
 optpatch/cstrccom.c-01.v6.23-bgfx.diff  |    21 +
 optpatch/dffnxpsr.c-01.v6.23-bgfx.diff  |    37 +
 optpatch/envrnmnt.c-01.v6.23-test.diff  |   105 +
 optpatch/envrnmnt.c-01.v6.24-test.diff  |   114 +
 optpatch/evaluatn.h-01.v6.23-ia64.diff  |    32 +
 optpatch/evaluatn.h-01.v6.24-ia64.diff  |    17 +
 optpatch/factmngr.c-01.v6.23-test.diff  |    10 +
 optpatch/factqury.c-01.v6.23-bgfx.diff  |   154 +
 optpatch/factqury.h-01.v6.23-bgfx.diff  |    20 +
 optpatch/genrcpsr.c-01.v6.23-bgfx.diff  |    22 +
 optpatch/memalloc.c-01.v6.23-test.diff  |    33 +
 optpatch/memalloc.c-01.v6.24-test.diff  |    24 +
 optpatch/objrtmch.c-01.v6.24-bgfx.diff  |    79 +
 setup.py                                |   941 ++
 testsuite/test_00.py                    |    56 +
 testsuite/test_class.py                 |   394 +
 testsuite/test_cycnlst.py               |   613 +
 testsuite/test_fact.py                  |   411 +
 testsuite/test_funcgenr.py              |   163 +
 testsuite/test_module.py                |   207 +
 testsuite/test_print.py                 |   258 +
 testsuite/test_remove.py                |   127 +
 testsuite/test_retpass.py               |    70 +
 testsuite/test_toplev.py                |   192 +
 testsuite/test_zz_submitted.py          |   115 +
 testsuite/tests.py                      |    25 +
 58 files changed, 34577 insertions(+), 175 deletions(-)

diff --git a/CLIPSSrc.zip b/CLIPSSrc.zip
new file mode 100644
index 0000000..da285a8
Binary files /dev/null and b/CLIPSSrc.zip differ
diff --git a/FAQ b/FAQ
new file mode 100644
index 0000000..c3d2724
--- /dev/null
+++ b/FAQ
@@ -0,0 +1,351 @@
+===================================================
+These are some of the questions asked about PyCLIPS
+===================================================
+
+
+
+Q: How can I track what constructs or commands are sent to CLIPS?
+
+A: There is actually no way to inspect the "history" of commands that
+have been sent to the underlying CLIPS engine. In fact, unlike similar
+projects, PyCLIPS does not limit its interaction with CLIPS to sending
+commands to the engine. What PyCLIPS mostly does is to call the intrinsic
+low-level CLIPS API to access and modify the engine state. However the
+underlying engine keeps its ability to produce a possibly (even too
+densely) detailed trace file. See the documentation for the DebugConfig
+object in the manual in order to learn how to produce a trace file with
+the desired detail, and the CLIPS manual if you are uncertain about what
+entities or actions can be "watched" and for what purpose.
+
+
+
+Q: How can I verify when a CLIPS subprogram has finished running?
+
+A: When the Run() function is invoked without arguments, it just
+returns control to the calling Python program when it has finished
+running. In most cases this is sufficient, but sometimes it might be
+useful to divide execution in steps, eg. when the CLIPS subprogram
+is known to take a long time to finish and there is the need to give
+some feedback to the user. In this case you can just decide to perform
+a certain number of steps repeatedly until no rules are fired anymore,
+as the Run command accepts a "limit" integer argument which must be the
+maximum number of rules to execute. An example follows:
+
+    STEPS = 5
+    import clips
+    define_some_rules()
+    clips.Reset()
+    assert_some_facts()
+    while not clips.Run(STEPS) < STEPS:
+        give_some_feedback()
+        possibly_consider_activations()
+    print_result()
+
+Run() returns the number of fired rules, so it eventually becomes less
+than expected (zero if no rules are fired anymore) and this means that
+the CLIPS subprogram has finished. At any step the calling program can
+take into consideration the newly activated rules, giving also more
+granularity to the process.
+
+
+
+Q: How can salience be declared using the BuildRule() function?
+
+A: Salience declaration is part of the LHS of the rule, so it is legal to
+declare salience in the LHS. The implementation of BuildRule() relies on
+the more general Build() function: the construct is converted to a string
+and then sent to the CLIPS engine via the same low-level call that Build()
+invokes, while immediately looking up for the newly created rule and
+returning it as an object. Unfortunately there is currently no way to
+set the salience of a rule after building it (eg. as a property of the
+returned Rule object). An example follows:
+
+    r = clips.BuildRule("duck-rule",
+        """(declare (salience 99))
+           (duck)
+        """, "(assert (quack))")
+
+Of course PyCLIPS does not rely on multi-line strings and spacing, as its
+main delimiter is the bracket. The above example uses multiple lines only
+for sake of readability.
+
+
+
+Q: How do I access Activation objects?
+
+A: There is actually no ready-made Activation list. The documentation
+states that Activation objects cannot be created by the user, and can
+only be retrieved from the system. In fact it would make no sense to
+create an Activation object, as it occurs only when, before (or
+within) a Run(), a certain rule is likely to be fired. Also, being
+Activations mainly a sort of "temporary" objects, they have no name...
+hence the absence of a "list of activations" (the <Entity>List()
+functions, with few exceptions, just provide lists of *names*).
+However, the possibility to walk through the list of current
+activations is provided by the "iteration functions":
+
+InitialActivation() (returns the first activation as an *object*)
+Activation.Next() (returns the activation that follows as an object).
+
+
+
+Q: How do I specifically see errors that happen in the CLIPS engine?
+
+A: There are several ways, actually. One can be directly reading what
+the engine reports on TraceStream and ErrorStream, by explicitly using
+their Read() method. The easiest way I have found (it's time consuming,
+though) is to clips.DebugConfig.WatchAll() to activate all trace
+output and clips.DebugConfig.DribbleOn("my_trace.log"). When an error
+occurs in CLIPS, everything about it will be written to the file
+specified in DebugConfig.DribbleOn(), and it becomes easier to spot
+it correctly.
+
+
+
+Q: Why does PyCLIPS function Xxx differ from CLIPS statement xxx?
+
+A: It might be a bug, of course. But sometimes such differences depend
+on the implementation of PyCLIPS as a layer between Python and the API
+that CLIPS exposes to the C language. PyCLIPS does not necessarily
+behave like the CLIPS shell itself, however it's possible to directly
+interact with the underlying CLIPS engine in a very similar way using
+the SendCommand() function. There is a limitation for SendCommand(),
+though: it only examines the first part of the command, that is either
+the first symbol or the first expression enclosed in the outermost
+brackets. This means that issuing a command like:
+
+    clips.SendCommand("(assert (spam)) and egg")
+
+will only send the command "(assert (spam))" to CLIPS, and forget the
+rest. But SendCommand() closely mimics the behaviour of the CLIPS
+shell, and if you try to supply the same command to CLIPS, you will
+notice exactly the same reaction.
+
+
+
+Q: Can I use PyCLIPS as a CLIPS shell?
+
+A: The module has not been created for this task. However, there are all
+the commands and utility functions (namely SendCommand and I/O "streams")
+to allow creating a simple shell. Probably I will post the script I use
+as a CLIPS shell from within the Python interactive interpreter. Anyway
+it should be quite easy to create a small script that, in an "endless"
+loop, does something like:
+
+    while True:
+        s = read_user_input()
+        clips.SendCommand(s)
+        o = clips.StdoutStream.Read()
+        e = clips.ErrorStream.Read()
+        sys.stdout.write(o)
+        sys.stderr.write(e)
+
+possibly enhancing it to read more information from other streams and to
+perform some more tests on user input.
+
+
+
+Q: Are PyCLIPS functions blocking?
+
+A: Yes, definitely. The underlying CLIPS engine has to be treated as a
+single resource - although it can handle multiple separate environments -
+thus "real" concurrent access is not possible. Multiple threads can use
+the resource, but they are implicitly blocked by the Python interpreter
+itself when they try to access the PyCLIPS low-level layer. As a side
+effect, also the Run() function could cause a Python program to release
+control to the interpreter after a long time. It wouldn't be safe to
+reimplement PyCLIPS in a way that allows the Python interpreter to access
+the engine while a time-consuming function (such as the Run() function)
+is executing, as CLIPS has not been designed for multithreading. However
+if your problem is the lack of responsiveness specifically during a Run()
+you can refer to the second "Answered Question" above for a *partial*
+solution.
+
+
+
+Q: The setup script complains, that it cannot find "Python.h"...
+
+A: This is very common, it happened to me too. I thought I was smart but
+forgot to install the Python development packages on my Linux machine.
+Normally these packages are named like "python-devel" or "python-dev",
+and are absolutely necessary to build Python modules and extensions. One
+possible reason can also be that you are using an embedded version of
+Python: in this case it would be better to install a standalone Python
+interpreter, same version as the embedded one, and use it to build the
+module. After doing that, you should copy the 'clips' subdirectory from
+its 'site-packages' to your embedded Python 'site-packages': this should,
+in most cases, allow you to call PyCLIPS from an embedded Python release.
+I don't know how to link PyCLIPS with Python in a custom build: probably
+it's quite easy... if anyone finds out how to do it, please give me some
+information about it.
+
+
+
+Q: Can I use PyCLIPS for interactive sessions?
+
+A: Yes, but you can't use clips.StdinStream and clips.StdoutStream in an
+effective way. Ok, if you structure your CLIPS subprogram very carefully
+and pay special attention to the execution order you might also be able
+to use the default CLIPS streams to provide input from an hypothetical
+user, but the quickest way to achieve a result is to let Python do the
+I/O job using a Python function:
+
+    def clips_raw_input(prompt):
+        return clips.String(raw_input(prompt))
+    clips.RegisterPythonFunction(clips_raw_input, "raw-input")
+
+this function will let Python interact with the user, such as in the
+following session:
+
+    >>> import clips
+    >>> def clips_raw_input(prompt):
+            return clips.String(raw_input(prompt))
+    >>> clips.RegisterPythonFunction(clips_raw_input, "raw-input")
+    >>> r1 = clips.BuildRule(
+        "name-rule",
+        "(initial-fact)",
+        """(bind ?user-name (python-call raw-input "Your Name? "))
+           (assert (user-name-is ?user-name))""")
+    >>> clips.Reset()
+    >>> clips.Run()
+    Your Name? Francesco
+    1
+    >>> clips.PrintFacts()
+    f-0     (initial-fact)
+    f-1     (user-name-is "Francesco")
+    For a total of 2 facts.
+    >>> 
+
+Of course you can use raw_input, but you can also pop up a dialog box
+or whatever else to retrieve input from the interactive session, using
+virtually all Python possibilities.
+
+
+
+Q: How is clips.Eval() different from clips.SendCommand()?
+
+A: SendCommand() is a function that has been provided to closely emulate
+a CLIPS shell environment. In fact, CLIPS does not provide this when used
+as a library, it has been coded implementing the same operations that are
+performed in the CLIPS command loop, except for the input part of course.
+This allows also to issue some commands that fail when called using the
+Eval() function. For an example, consider the following session:
+
+    >>> t = clips.BuildTemplate("car", "(slot make)(slot model)")
+    >>> f0 = t.BuildFact()
+    >>> f0.Slots['make'] = clips.Symbol('Chevy')
+    >>> f0.Slots['model'] = clips.Symbol('Prizm')
+    >>> f0.Assert()
+    >>> clips.PrintFacts()
+    f-0     (car (make Chevy) (model Prizm))
+    For a total of 1 fact.
+    >>> clips.Eval("(modify 0 (make Geo))")
+    Traceback (most recent call last):
+     File "<pyshell#20>", line 1, in -toplevel-
+       clips.Eval("(modify 0 (make Geo))")
+     File ".../_clips_wrap.py", line 3227, in Eval
+    ClipsError: C10: unable to evaluate expression
+    >>> print clips.ErrorStream.Read().strip()
+    [TMPLTFUN1] Fact-indexes can only be used by modify as a top level command.
+    >>>
+
+Whereas, if you use SendCommand(), the same expression actually becomes a
+top level command, and it is executed in the expected way:
+
+    >>> clips.SendCommand("(modify 0 (make Geo))")
+    >>> clips.PrintFacts()
+    f-1     (car (make Geo) (model Prizm))
+    For a total of 1 fact.
+    >>>
+
+There are other actions that behave differently when "evaluated" compared
+to when executed at the CLIPS shell prompt or within a Load() call: the
+SendCommand() function can also be used as a shortcut in these cases.
+
+
+
+Q: How can I return a boolean value from Python to CLIPS?
+
+A: Some users have noticed that, while many "basic" types (mostly numbers
+and strings) are automatically converted to their CLIPS counterpart when
+calling an external Python function, the 'bool' type is not. There is a
+reason for this behaviour, that is the absence of a real boolean type in
+the base classes of CLIPS. CLIPS uses the "special" SYMBOLs 'TRUE' and
+FALSE as if they were booleans, but they remain SYMBOLs.
+
+The issue is partially covered by letting the value clips.Symbol('FALSE')
+to actually evaluate to a False boolean. In this way, whenever a CLIPS
+function called from Python returns that particular SYMBOL, it is seen
+as False only in tests, while not loosing its SYMBOL nature.
+
+However it seemed too arbitrary to convert a Python 'bool' to one of the
+two discussed SYMBOLs. In fact, the documentation states that it should
+not been taken for granted that PyCLIPS does all the conversion job, and
+that especially Python functions that return values back to CLIPS must be
+carefully written, and possibly return values wrapped in CLIPS types.
+
+For functions that return booleans, this is even more needed: Python has
+a peculiar way to treat many things as True or False, depending on their
+values: an empty string is False, a non-empty one is True, for instance.
+
+A solution to this issue could be to write a wrapper function in order to
+let test functions return the correct SYMBOL value to CLIPS:
+
+    def clips_test_wrapper(f):
+       def wf(*a, **kwa):
+               if f(*a, **kwa):
+                   return clips.Symbol("TRUE")
+               else:
+                   return clips.Symbol("FALSE")
+       wf.__name__ = f.__name__    # explanation is below
+       return wf
+
+The reason why we rewrite the __name__ attribute of the returned function
+is that in this way the function registration utility will register the
+wrapper function with the original name. An example follows:
+
+    >>> def py_true():
+           return True
+    >>> clips.RegisterPythonFunction(clips_test_wrapper(py_true))
+    >>> clips.Eval("(python-call py_true)")
+    <Symbol 'TRUE'>
+    >>>
+
+To unregister the function we only need to supply either the name of the
+function as it is known to CLIPS or any function whose __name__ attribute
+corresponds to this, such as the wrapped function or the original one.
+
+
+
+Q: Is there a way to find a fact given its index?
+
+A: There is not a direct way, but you can traverse the list of existing
+facts to come up to the one that has the required index. The following
+is an example of function that uses this technique:
+
+    def FindFactByIndex(idx):
+        f = clips.InitialFact()
+        while f is not None and f.Index != idx:
+            f = f.Next()
+        return f
+
+This can easily be implemented in an environment-aware way. Of course
+the given implementation has a linear cost with respect to the total
+number of facts (which could be unknown, and significantly big), but
+at the moment and with the current CLIPS API, there is no other way to
+achieve the same goal more efficiently.
+
+
+
+Q: Can I use Python objects as data within the CLIPS engine?
+
+A: Not for now. There are other ways to deal with this: for instance
+you can create a dictionary containing the objects you'd like to be
+managed by the CLIPS subsystem mapped to strings, and then use the
+strings to reference the objects. It's not unlikely that there will be
+the possibility to use generic Python objects directly in one of the
+next releases.
+
+
+
+$Id: FAQ 335 2008-01-13 01:50:50Z Franz $
\ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..d3697eb
--- /dev/null
+++ b/README
@@ -0,0 +1,292 @@
+PyCLIPS - a Python module to integrate CLIPS into Python
+(c) 2002-2008 Francesco Garosi/JKS
+
+Version 1.0 (release)
+
+
+
+RELEASE NOTES
+=============
+
+This is a C module embedding CLIPS functionality. To build it, you need to
+download the source code for CLIPS, which can be found on its web site, at
+
+    http://clipsrules.sourceforge.net/
+
+(you must follow the link to the download page). Please note that the ZIP
+version of the source archive is needed, since the setup procedure unpacks
+it by itself. Recent versions of PyCLIPS will try to connect to SourceForge
+automatically to download the latest source package supported by PyCLIPS,
+but in case it does not work you will have to download it manually. If the
+source package is provided, no attempt to connect to the internet will be
+made.
+
+The module fully embeds the CLIPS engine, with COOL (Clips Object Oriented
+Language) and environments support. It does not require a CLIPS installation
+to function. It also supports the file formats produced (and interpreted) by
+CLIPS itself. Documentation is provided in source (TeX) format, as a PDF
+file and as an HTML tarball.
+
+This is a new stable release of the 1.0 branch. Not all the approved
+enhancements have been completed, but all basic module functionality appears
+to be working and stable. The test suite is also almost complete and helps
+to find possible flaws and weaknesses. From now on I will try to enhance the
+module with additional (optional) packages, keeping the base version as
+close as possible to the 1.0 stable branch. This release is named 1.0.X.Y
+where X is a number indicating the patch level (previously it was preceded
+by an 'R') and Y is an incremental value. The change in version numbering
+has been introduced in order to disambiguate the version string, so that
+setuptools can better decide whether or not to replace a package.
+
+Further beta releases will be named 1.1_nn, where the integer number nn will
+increase until the final 1.1 version is reached. The release policies are
+the same: only "stable enough" versions will be uploaded to the file release
+system, while the SVN repository will also provide possibly unstable changes.
+
+
+
+REQUIREMENTS
+============
+
+PyCLIPS requires Python 2.4 or higher to work. Recently it has been tested
+on Python 2.5. Previous versions of Python are not supported.
+
+PyCLIPS also requires the CLIPS 6.23 or CLIPS 6.24 sources to compile.
+Compilation will fail against CLIPS version 6.22 or earlier: although the
+CLIPS API is quite stable, there are some improvements at this level in
+CLIPS 6.23 which are required for PyCLIPS. If you don't need to stick to
+the former CLIPS version, please use CLIPS 6.24: the previous version lacks
+some features and PyCLIPS is mostly developed against the more recent
+release.
+
+I use GCC 3.x to compile PyCLIPS both on UNIX (Linux and Solaris) and on
+Win32. If Python was compiled using Visual C 9.0 (the one released with
+Visual Studio 2008 Express) and the Platform SDK, this environment does also
+build the module successfully, although with warnings due to deprecation of
+insecure functions. Win32 users are encouraged to use the prebuilt package.
+PyCLIPS can also be successfully compiled using the free Microsoft Visual
+C++ Toolkit 2003. However also this compiler will issue some warnings (see
+below) which are mostly safe to ignore.
+
+I do not know other dependencies or requirements to build PyCLIPS, but feel
+free to contact me for any annoyance.
+
+
+
+INSTALLATION
+============
+
+
+1) from the source
+------------------
+
+Installing from the source should be simple, as the module uses distutils
+in the usual way. As said before, the setup script will try to download
+the CLIPS source code.
+
+The sequence of operations should be as follows:
+
+    $ gunzip -c pyclips-1.0.X.Y.tar.gz | tar xvf -
+    $ cd pyclips
+    $ python setup.py build
+    $ su -c "python setup.py install"
+
+This could not work, and you might still receive a message saying that the
+CLIPS source package has not been found: you will need to download it
+manually following the instructions on the above mentioned web site, and
+copy the package in the base directory of the source tree ('pyclips').
+
+The setup procedure should run out of the box. It has been tested on Linux,
+Solaris (with GCC and a self compiled version of Python) and Win32 (using
+MinGW 3.1 and MSYS 1.0, as well as some flavours of MS Visual C). Recent
+versions of PyCLIPS use setuptools instead of distutils, if found: the
+setup script falls back to distutils if setuptools are not installed. The
+standard setup procedure will also take care of performing additional steps
+such as applying patches to the CLIPS source if possible (see below).
+
+To use setuptools instead of distutils you will have to download the
+'ez_setup.py' file from http://peak.telecommunity.com, for instance using
+the following command:
+
+    $ wget http://peak.telecommunity.com/dist/ez_setup.py
+
+when you are in the base directory of the source tree ('pyclips'). The
+main advantage in using setuptools is that the resulting installation is
+less "sparse", and will consist in a single file in your $PYTHONPATH. I
+found myself this to be a big advantage. Moreover, recent PyCLIPS binary
+distributions will be packaged as "eggs", as I verified that this gives
+more compatibility across different Linux distributions: the binaries for
+Linux present on SourceForge (as .egg) have been built on a Debian-based
+distribution and installed and successfully tested on a Slackware-based
+one (respectively: Ubuntu and Zenwalk, even though on Ubuntu I completely
+recompiled Python for the build system and debugging).
+
+A small note for MS Visual C users: during compilation the compiler will
+warn about not recognizing the '-fno-strict-aliasing' option, but it will
+continue the build process anyway: this is not a problem, as Microsoft C
+does not try to aggressively optimize code in a way that would be unsafe
+for CLIPS. This parameter is necessary for CLIPS when using GCC, as stated
+in the CLIPS Advanced Programming Guide for CLIPS 6.24: in fact, omission
+of this flag produces a module that might lead to obscure crashes.
+
+
+2) using the prebuilt installer
+-------------------------------
+
+For Win32 I also provide prebuilt packages: to use them, just double-click
+the installer you downloaded. It will just find out where Python is located
+and copy the module in the right place. If your  distribution supports
+setuptools, you might also be able to use the "easy_install" program to
+install a prebuilt binary distribution (of the ones whose filenames have a
+".egg" extension) suitable to your needs. Linux ".egg" packages may also be
+available for some Python versions.
+
+
+
+LICENSE
+=======
+
+PyCLIPS is released under the Library General Public License (LGPL): a copy
+of the license text is included in the manual. Also, if you install the
+module, the license text can be viewed by typing:
+
+    >>> import clips
+    >>> print clips.license
+
+at the Python prompt. However the license can be found in the usual place,
+that is at the GNU's web site (http://www.gnu.org/copyleft/lesser.html).
+
+Please take your time to review the CLIPS license, especially in case the
+automatic CLIPS source download succeeds (because if it happens, it means
+that you have not read the notice on the CLIPS web site): CLIPS is free for
+everyone, but the Author suggests that if you derive any commercial or
+monetary benefit from CLIPS, a donation might be appreciated. This applies
+to CLIPS only, however: I give my "translation" work for free in the spirit
+of the LGPL.
+
+
+
+DOCUMENTATION
+=============
+
+The documentation can be found on SourceForge, at the PyCLIPS download page.
+It is distributed as a single PDF file, generated from the TeX sources that
+are included in the source distribution. The PyCLIPS documentation does not
+cover the CLIPS language: CLIPS is very well documented, the manuals for
+CLIPS are available as PDF on its web site.
+
+
+
+PATCHES
+=======
+
+Recent versions of PyCLIPS allow the possibility to easily apply optional
+patches to the official CLIPS source. Mandatory patches are however always
+applied by the setup script at the first build. Optional patches can be
+used to solve specific problems on some platforms or to test experimental
+bug fixes. At the time of writing there are in fact three patchsets:
+
+    - bgfx: fixes provided by the CLIPS maintainers
+    - test: "experimental" bug or annoyance fixes
+    - ia64: fixes needed for the x86_64 platforms
+
+Patches marked as "experimental" in fact derive from considerations found
+in developer forums and from contributions provided by other developers
+after addressing particular issues that were found after the release of
+the official CLIPS source. On the other hand, patches written for special
+platforms are normally mandatory on those: for example, the "ia64" patch
+set is needed to successfully pass the test suite on x86_64 platforms. 
+The other fixes (marked as "bgfx") should be considered mandatory, as they
+have officially been provided (sometimes as files to be replaced) by the
+people who invented CLIPS, and will hopefully be removed as soon as the
+next CLIPS release is out.
+
+If your system has a working GNU 'patch' command (it can be compiled for
+Win32 as well), the setup script will use it to apply all patch sets; in
+fact for 32-bit platforms the 'ia64' patchset is optional but not harmful.
+The setup script will skip files that have already been patched, that is,
+for which a copy of the original file exists: do not attempt to manually
+patch the files.
+
+
+
+TO DO
+=====
+
+Testing thoroughly has to be considered a primary goal. Also, in the same
+spirit, writing more tests for the test suite is needed: I will be grateful
+to everyone that would volunteer for helping me in this task.
+
+Probably both the C and the Python code in the module need some cleanup.
+Also the installation script is quite confused - probably it's not easy to
+understand what it does when it "creates the environment-aware submodule".
+
+The documentation is fairly complete, I think. However, if someone speaking
+english is reading this, probably she or he will notice that it's definitely
+not my mother tongue: even though I asked a friend to help me to find errors
+in current manual release, I think that especially for further additions and
+integrations I will introduce some clues of my "english illiteracy". So feel
+free to comment and criticize documentation as well.
+
+There are also other goals: they will pop up from time to time in the RFE
+list of the SourceForge.net PyCLIPS page. As the application I'm writing
+using the module goes on, I discover bugs and missing features, as well as
+concepts that can be implemented in different ways: every time it happens
+I post a request on SourceForge, as an external developer would do. Every
+developer with a SourceForge account can do the same, and this is also a
+contribution to the project.
+
+
+
+ACKNOWLEDGEMENTS
+================
+
+I'd like to thank the CLIPS crew for writing CLIPS, putting it in the Public
+Domain, and for writing the extensive documentation. And the people at CLIPS
+Developer Forum (http://groups.google.com/group/CLIPSESG/) for solving many
+of my doubts.
+
+I really have to thank Johan Lindberg (you can visit his blog at the address
+http://commentsarelies.blogspot.com/) who also develops the module with me.
+His help has been invaluable in testing, finding bugs and inconsistencies,
+as well as writing the example suite - it was heavily needed, and his idea
+to translate Gary's work for CLIPSJNI into PyCLIPS also gives an opportunity
+to compare the two different interfaces.
+
+Also thanks to people who have supported my work, especially Vladimir Ulogov
+who also worked on a module like this.
+
+A very big "Thank You" goes to all friends and people who have been near me,
+sometimes flooded by my words when I have been speaking about PyCLIPS (and
+more generally about computers) in front of some beverage...
+
+I would like as well to thank the people who found either bugs or unexpected
+behaviours for helping me in the hard task of finding a solution, as well as
+those who showed interest in using PyCLIPS for their projects and extending
+it to make it more useful.
+
+I am looking forward to having many people to thank here. :)
+
+
+
+CONTACT INFORMATION
+===================
+
+I can be reached for suggestions, criticisms and reports about any annoyance
+at the following e-mail address:
+
+    franzg -at- users -dot- sourceforge -dot- net
+
+I also have a web site, where I will occasionally write some news about this
+module as well:
+
+    http://www.jks.it
+
+Every kind of help is really welcome.
+
+Francesco Garosi
+
+
+---
+
+$Id: README 343 2008-02-22 01:35:38Z Franz $
diff --git a/clips/__init__.py b/clips/__init__.py
new file mode 100644
index 0000000..4f9d8df
--- /dev/null
+++ b/clips/__init__.py
@@ -0,0 +1,56 @@
+# __init__.py
+# clips wrapper module loader
+
+# (c) 2002-2008 Francesco Garosi/JKS
+#  The author's copyright is expressed through the following notice, thus
+#  giving effective rights to copy and use this software to anyone, as shown
+#  in the license text.
+#
+# NOTICE:
+#  This software is released under the terms of the GNU Lesser General Public
+#  license; a copy of the text has been released with this package (see file
+#  _license.py, where the license text also appears), and can be found on the
+#  GNU web site, at the following address:
+#
+#           http://www.gnu.org/copyleft/lesser.html
+#
+#  Please refer to the license text for any license information. This notice
+#  has to be considered part of the license, and should be kept on every copy
+#  integral or modified, of the source files. The removal of the reference to
+#  the license will be considered an infringement of the license itself.
+
+
+
+"""\
+clips - high-level interface to the CLIPS engine module
+        (c) 2002-2008 Francesco Garosi/JKS
+
+This work is based on the CLIPS library and interpreter, by Gary Riley and
+others. Please visit its homepage at http://clipsrules.sourceforge.net
+for further information and to obtain the full source code.
+
+Please issue 'print clips.license' at the prompt for licensing information.
+"""
+
+
+from _clips_wrap import *
+from _eclips_wrap import Environment, CurrentEnvironment
+from _license import license
+from _version import version, version_string
+
+
+# provide our __dict__ to the _clips_wrap in order to set up stock classes:
+# the name _setParentModuleDict will be removed later
+from _clips_wrap import _setParentModuleDict
+_setParentModuleDict(globals())
+del _setParentModuleDict
+
+
+
+# define the __all__ list so that the module can avoid useless names: in
+#  fact all useful names that this part of the module begin with a letter
+__all__ = filter(lambda x: x[0] != '_', dir())
+
+
+
+# end.
diff --git a/clips/_clips_wrap.py b/clips/_clips_wrap.py
new file mode 100644
index 0000000..dd7217b
--- /dev/null
+++ b/clips/_clips_wrap.py
@@ -0,0 +1,4347 @@
+# _clips_wrap.py
+# higher-level interface for the _clips module
+
+# (c) 2002-2008 Francesco Garosi/JKS
+#  The author's copyright is expressed through the following notice, thus
+#  giving effective rights to copy and use this software to anyone, as shown
+#  in the license text.
+#
+# NOTICE:
+#  This software is released under the terms of the GNU Lesser General Public
+#  license; a copy of the text has been released with this package (see file
+#  _license.py, where the license text also appears), and can be found on the
+#  GNU web site, at the following address:
+#
+#           http://www.gnu.org/copyleft/lesser.html
+#
+#  Please refer to the license text for any license information. This notice
+#  has to be considered part of the license, and should be kept on every copy
+#  integral or modified, of the source files. The removal of the reference to
+#  the license will be considered an infringement of the license itself.
+
+"""\
+clips - high-level interface to the CLIPS engine module
+        (c) 2002-2008 Francesco Garosi/JKS
+"""
+
+__revision__ = "$Id: _clips_wrap.py 342 2008-02-22 01:17:23Z Franz $"
+
+# ========================================================================== #
+# imports - these are hidden to module user
+
+# standard imports
+import sys as _sys
+import os as  _os
+
+# the low-level module
+import _clips as _c
+
+# check Python version, and issue an exception if not supported
+if _sys.version[:3] < "2.4":
+    raise _c.ClipsError("M99: Python 2.4 or higher required")
+
+
+# ========================================================================== #
+# globals
+
+# clips version is defined
+CLIPS_VERSION = "%s.%s" % (_c.CLIPS_MAJOR, _c.CLIPS_MINOR)
+PYCLIPS_VERSION = "%s.%s.%s.%s" % (
+    _c.PYCLIPS_MAJOR,
+    _c.PYCLIPS_MINOR,
+    _c.PYCLIPS_PATCHLEVEL,
+    _c.PYCLIPS_INCREMENTAL)
+
+# bring the CLIPS exception objects at top level
+ClipsError = _c.ClipsError
+ClipsMemoryError = _c.ClipsMemoryError
+
+
+# redeclare manifest constants here in order to avoid having to
+#  reference the ones defined in the low-level module _clips
+
+# These manifest constants are commented out, since the user has to rely
+#  on the class constructors defined below in order to build values to
+#  pass to the CLIPS engine. Also, these names are used to implement
+#  the stock class objects (see below)
+##INTEGER = _c.INTEGER
+##FLOAT = _c.FLOAT
+##STRING = _c.STRING
+##SYMBOL = _c.SYMBOL
+##INSTANCE_NAME = _c.INSTANCE_NAME
+##MULTIFIELD = _c.MULTIFIELD
+##INSTANCE_ADDRESS = _c.INSTANCE_ADDRESS
+##EXTERNAL_ADDRESS = _c.EXTERNAL_ADDRESS
+##FACT_ADDRESS = _c.FACT_ADDRESS
+
+LOCAL_SAVE = _c.LOCAL_SAVE
+VISIBLE_SAVE = _c.VISIBLE_SAVE
+
+WHEN_DEFINED = _c.WHEN_DEFINED
+WHEN_ACTIVATED = _c.WHEN_ACTIVATED
+EVERY_CYCLE = _c.EVERY_CYCLE
+
+NO_DEFAULT = _c.NO_DEFAULT
+STATIC_DEFAULT = _c.STATIC_DEFAULT
+DYNAMIC_DEFAULT = _c.DYNAMIC_DEFAULT
+
+DEPTH_STRATEGY = _c.DEPTH_STRATEGY
+BREADTH_STRATEGY = _c.BREADTH_STRATEGY
+LEX_STRATEGY = _c.LEX_STRATEGY
+MEA_STRATEGY = _c.MEA_STRATEGY
+COMPLEXITY_STRATEGY = _c.COMPLEXITY_STRATEGY
+SIMPLICITY_STRATEGY = _c.SIMPLICITY_STRATEGY
+RANDOM_STRATEGY = _c.RANDOM_STRATEGY
+
+CONVENIENCE_MODE = _c.CONVENIENCE_MODE
+CONSERVATION_MODE = _c.CONSERVATION_MODE
+
+AFTER = 'after'
+AROUND = 'around'
+BEFORE = 'before'
+PRIMARY = 'primary'
+
+
+# ========================================================================== #
+# these decorators allow to verify the types of data passed to the decorated
+#  functions and methods (_accepts* decorators) and to force the input types
+#  to some defined ones (_force* decorators)
+
+# verify that the types passed to the decorated functions are exactly the
+#  ones passed as arguments to the decorator: if not, raise an appropriate
+#  TypeError. If a type is specified as None, then the type in the same
+#  position will not be checked. If a tuple containing types is passed to
+#  the decorator, then the decorator will verify that the function name is
+#  of one of the types in the tuple. Examples:
+#
+# @_accepts(int, int)   # will raise TypeError if either x or y is not int
+# def add(x, y):
+#   return x + y
+#
+# @_accepts(int, (int, float))  # will accept if y is either int or float
+# def add(x, y):
+#   return x + y
+#
+# @_accepts(None, int)  # will raise if y is not int, but won't check x
+# def add(x, y):
+#   return x + y
+#
+def _accepts(*types):
+    def _DECO(f):
+        def _WRAPPER(*args):
+            i = 0   # start counting arguments at 0
+            for a in args:
+                t = types[i]
+                if t is not None:   # otherwise no type checking
+                    # please note that isinstance already accepts a tuple
+                    if not isinstance(a, t):
+                        if type(t) == tuple:
+                            errorstr = \
+                                "one of %s expected in %s, parameter %s" \
+                                % (", ".join(map(lambda x: str(x)[1:-1], t)),
+                                   f.__name__, i + 1)
+                        else:
+                            errorstr = \
+                                "%s expected in %s, parameter %s" \
+                                % (str(t)[1:-1], f.__name__, i + 1)
+                        raise TypeError(errorstr)
+                i += 1
+            return f(*args)
+        _WRAPPER.__name__ = f.__name__
+        _WRAPPER.__doc__ = f.__doc__
+        return _WRAPPER
+    return _DECO
+
+# same as above, but for class methods: takes the implicit self in account
+def _accepts_method(*types):
+    def _DECO(f):
+        def _WRAPPER(self, *args):
+            i = 0
+            for a in args:
+                t = types[i]
+                if t is not None:
+                    if not isinstance(a, t):
+                        if type(t) == tuple:
+                            errorstr = \
+                                "one of %s expected in %s, parameter %s" \
+                                % (", ".join(map(lambda x: str(x)[1:-1], t)),
+                                   f.__name__, i + 1)
+                        else:
+                            errorstr = \
+                                "%s expected in %s, parameter %s" \
+                                % (str(t)[1:-1], f.__name__, i + 1)
+                        raise TypeError(errorstr)
+                i += 1
+            return f(self, *args)
+        _WRAPPER.__name__ = f.__name__
+        _WRAPPER.__doc__ = f.__doc__
+        return _WRAPPER
+    return _DECO
+
+
+# given a list of types to the decorator, the arguments of the decorated
+#  function are converted (cast) to the corresponding type in the list. If
+#  None is given as an argument to the decorator, in the decorated function
+#  the corresponding parameter is left alone. Example:
+#
+# @_forces(None, int)   # x is left as it is, while y is converted to int
+# def add(x, y):
+#   return x + y
+#
+#  a dict can be specified as a conversion map: in this case the keys are
+#  the types that will be converted, the values are the types to convert to
+#  and None acts differently when used as key (in which case it converts
+#  every type as a last resort) or as a value (when used here there is no
+#  conversion). An example:
+#
+# @_forces(None, {float: long, long: None, None: int})
+# def add(x, y):
+#   return x + y
+#
+def _forces(*types):
+    def _DECO(f):
+        def _WRAPPER(*args):
+            newargs = []
+            i = 0
+            for a in args:
+                t = types[i]
+                # when None is used as a type to convert to, no conversion
+                #  performed at all (the argument is left as it is)
+                if t is None:
+                    newargs.append(a)
+                # pass a dict to perform selective conversions, where...
+                elif type(t) == dict:
+                    type_a = type(a)
+                    # ...if the type of the argument is taken into account...
+                    if t.has_key(type_a):
+                        conv = t[type_a]
+                        # ...when it is not None, the argument is converted
+                        if conv is not None:
+                            newargs.append(conv(a))
+                        # ...when it is None, the argument is left as it is
+                        else:
+                            newargs.append(a)
+                    # ...if no other specification was found, but there is
+                    #  None as a possible type to convert to another, then
+                    #  the argument is converted anyway (ie. None acts as a
+                    #  sink that converts any type as a last resort)
+                    elif t.has_key(None):
+                        newargs.append(t[None](a))
+                    # ...but when there is no suitable specific conversion
+                    #  and None is not given the argument is left as it is
+                    else:
+                        newargs.append(a)
+                # otherwise the argument is converted to the specified type
+                else:
+                    newargs.append(t(a))
+                i += 1
+            return f(*newargs)
+        _WRAPPER.__name__ = f.__name__
+        _WRAPPER.__doc__ = f.__doc__
+        return _WRAPPER
+    return _DECO
+
+# same as above, but for class methods: takes the implicit self in account
+def _forces_method(*types):
+    def _DECO(f):
+        def _WRAPPER(self, *args):
+            newargs = []
+            i = 0
+            for a in args:
+                t = types[i]
+                if t is None:
+                    newargs.append(a)
+                elif type(t) == dict:
+                    type_a = type(a)
+                    if t.has_key(type_a):
+                        conv = t[type_a]
+                        if conv is not None:
+                            newargs.append(conv(a))
+                        else:
+                            newargs.append(a)
+                    elif t.has_key(None):
+                        newargs.append(t[None](a))
+                    else:
+                        newargs.append(a)
+                else:
+                    newargs.append(t(a))
+                i += 1
+            return f(self, *newargs)
+        _WRAPPER.__name__ = f.__name__
+        _WRAPPER.__doc__ = f.__doc__
+        return _WRAPPER
+    return _DECO
+
+# the decorators have underscored names, because they are too raw and too
+#  unspecific to the module to be used outside this scope; please note that
+#  the environment aware module will only have to use the method specific
+#  versions
+
+
+# ========================================================================== #
+# High-level classes to embed clips internal types
+
+# 1) numeric types
+class Integer(int):
+    """extend an int for use with CLIPS"""
+    def __repr__(self):
+        return "<Integer %s>" % int.__repr__(self)
+    def __add__(self, o):
+        return Integer(int(self) + int(o))
+    def __sub__(self, o):
+        return Integer(int(self) - int(o))
+    def __mul__(self, o):
+        return Integer(int(self) * int(o))
+    def __floordiv__(self, o):
+        return Integer(int(self) // int(o))
+    def __truediv__(self, o):
+        return Integer(int(self) / int(o))
+    def __div__(self, o):
+        return Integer(int(self) / int(o))
+    def __mod__(self, o):
+        return Integer(int(self) % int(o))
+    def __lshift__(self, o):
+        return Integer(int(self) << int(o))
+    def __rshift__(self, o):
+        return Integer(int(self) >> int(o))
+    def __and__(self, o):
+        return Integer(int(self) & int(o))
+    def __xor__(self, o):
+        return Integer(int(self) ^ int(o))
+    def __or__(self, o):
+        return Integer(int(self) | int(o))
+    def __pow__(self, o, m=None):
+        if m is not None:
+            return Integer((int(self) ** int(o)) % int(m))
+        return Integer(int(self) ** int(o))
+    def clrepr(self):
+        """represent this Integer for CLIPS"""
+        return (_c.INTEGER, int(self))
+    def clsyntax(self):
+        """represent this Integer as it would be in CLIPS syntax"""
+        return str(self)
+    def cltypename(self):
+        """name of this type in CLIPS"""
+        return "INTEGER"
+ClipsIntegerType = type(Integer(0))
+
+class Float(float):
+    """extend a float for use with CLIPS"""
+    def __repr__(self):
+        return "<Float %s>" % float.__repr__(self)
+    def __add__(self, o):
+        return Float(float(self) + float(o))
+    def __sub__(self, o):
+        return Float(float(self) - float(o))
+    def __mul__(self, o):
+        return Float(float(self) * float(o))
+    def __floordiv__(self, o):
+        return Float(float(self) // float(o))
+    def __truediv__(self, o):
+        return Float(float(self) / float(o))
+    def __div__(self, o):
+        return Float(float(self) / float(o))
+    def __pow__(self, o, m=None):
+        if m is not None:
+            return Float((float(self) ** float(o)) % float(m))
+        return Float(float(self) ** float(o))
+    def clrepr(self):
+        """represent this Float for CLIPS"""
+        return (_c.FLOAT, float(self))
+    def clsyntax(self):
+        """represent this Float as it would be in CLIPS syntax"""
+        return str(self)
+    def cltypename(self):
+        """name of this type in CLIPS"""
+        return "FLOAT"
+ClipsFloatType = type(Float(0.0))
+
+# 2) string types
+class String(str):
+    """extend a str for use with CLIPS"""
+    def __repr__(self):
+        return "<String %s>" % str.__repr__(self)
+    def __add__(self, o):
+        return String(str(self) + str(o))
+    def clrepr(self):
+        """represent this String for CLIPS"""
+        return (_c.STRING, str(self))
+    def clsyntax(self):
+        """represent this String as it would be in CLIPS syntax"""
+        return '"%s"' % str(self).replace("\\", "\\\\").replace('"', '\\"')
+    def cltypename(self):
+        """name of this type in CLIPS"""
+        return "STRING"
+ClipsStringType = type(String(""))
+
+class Symbol(str):
+    """extend a str for use with CLIPS as symbol"""
+    def __repr__(self):
+        return "<Symbol %s>" % str.__repr__(self)
+    def __nonzero__(self):
+        return bool(self not in ('FALSE', 'nil', ''))
+    def __add__(self, o):
+        return Symbol(str(self) + str(o))
+    def clrepr(self):
+        """represent this Symbol for CLIPS"""
+        return (_c.SYMBOL, str(self))
+    def clsyntax(self):
+        """represent this Symbol as it would be in CLIPS syntax"""
+        return str(self)
+    def cltypename(self):
+        """name of this type in CLIPS"""
+        return "SYMBOL"
+ClipsSymbolType = type(Symbol(""))
+
+class InstanceName(str):
+    """extend a str for use with CLIPS as instance name"""
+    def __repr__(self):
+        return "<InstanceName %s>" % str.__repr__(self)
+    def __add__(self, o):
+        return InstanceName(str(self) + str(o))
+    def clrepr(self):
+        """represent this InstanceName for CLIPS"""
+        return (_c.INSTANCE_NAME, str(self))
+    def clsyntax(self):
+        """represent this InstanceName as it would be in CLIPS syntax"""
+        return "[%s]" % str(self)
+    def cltypename(self):
+        """name of this type in CLIPS"""
+        return "INSTANCE-NAME"
+ClipsInstanceNameType = type(InstanceName(""))
+
+# a Nil object that might be useful in comparisons and assignments: after
+#  its creation the constructor is no longer necessary and is later deleted
+class NilObject(Symbol):
+    """represent the CLIPS nil symbol"""
+    __created = False
+    def __init__(self):
+        if self.__created:
+            raise TypeError("Nil object cannot be created")
+        _NilObject__created = True
+    def __repr__(self):
+        return "<Nil>"
+    def __str__(self):
+        return "nil"
+    def __eq__(self, o):
+        return o is self or o == Symbol("nil")
+    def __ne__(self, o):
+        return o is not self and o != Symbol("nil")
+    def __nonzero__(self):
+        return False
+    def clrepr(self):
+        """represent the nil symbol for CLIPS"""
+        return (_c.SYMBOL, "nil")
+    def clsyntax(self):
+        """represent Nil as it would be in CLIPS syntax"""
+        return "nil"
+    def cltypename(self):
+        """name of this type in CLIPS"""
+        return "SYMBOL"
+Nil = NilObject()
+ClipsNilType = type(Nil)
+del NilObject
+
+# the multifield type is a little bit more complex, since a list
+#  can contain elements of various types: at conversion time we must
+#  check that all elements are suitable for building a multivalue
+class Multifield(list):
+    """extend a list for use with CLIPS as Multifield value"""
+    def __repr__(self):
+        return "<Multifield %s>" % list.__repr__(self)
+    def __add__(self, o):
+        return Multifield(list(self) + list(o))
+    def clrepr(self):
+        """represent this Multifield for CLIPS"""
+        li = []
+        for x in self:
+            t = type(x)
+            if t in (ClipsIntegerType, ClipsFloatType, ClipsStringType,
+                     ClipsSymbolType, ClipsNilType, ClipsInstanceNameType):
+                li.append(x.clrepr())
+            elif t in (int, long):
+                li.append(Integer(x).clrepr())
+            elif t == float:
+                li.append(Float(x).clrepr())
+            elif t in (str, unicode):
+                li.append(String(x).clrepr())
+            elif isinstance(x, int):
+                li.append(Integer(x).clrepr())
+            elif isinstance(x, long):
+                li.append(Integer(x).clrepr())
+            elif isinstance(x, float):
+                li.append(Float(x).clrepr())
+            elif isinstance(x, str):
+                li.append(String(x).clrepr())
+            elif isinstance(x, unicode):
+                li.append(String(x).clrepr())
+            else:
+                raise TypeError(
+                    "list element of type %s cannot be converted" % t)
+        return (_c.MULTIFIELD, li)
+    def clsyntax(self):
+        """represent this Multifield as it would be in CLIPS syntax"""
+        li = []
+        for x in self:
+            t = type(x)
+            if t in (ClipsIntegerType, ClipsFloatType, ClipsStringType,
+                     ClipsSymbolType, ClipsNilType, ClipsInstanceNameType):
+                li.append(x.clsyntax())
+            elif t in (int, long):
+                li.append(Integer(x).clsyntax())
+            elif t == float:
+                li.append(Float(x).clsyntax())
+            elif t in (str, unicode):
+                li.append(String(x).clsyntax())
+            elif isinstance(x, int):
+                li.append(Integer(x).clsyntax())
+            elif isinstance(x, long):
+                li.append(Integer(x).clsyntax())
+            elif isinstance(x, float):
+                li.append(Float(x).clsyntax())
+            elif isinstance(x, str):
+                li.append(String(x).clsyntax())
+            elif isinstance(x, unicode):
+                li.append(String(x).clsyntax())
+            else:
+                raise TypeError(
+                    "list element of type %s cannot be converted" % t)
+        return "(create$ %s)" % " ".join(li)    # only createable via this
+    def cltypename(self):
+        """name of this type in CLIPS"""
+        return "MULTIFIELD"
+ClipsMultifieldType = type(Multifield([]))
+
+
+# ========================================================================== #
+# NOTICE:
+#  as of version 1.0.6 (incremental 331) we use the special markers around
+#  _cl2py and _py2cl, namely #{{FUNCTION and #}} in order to publish the
+#  above functions to the Environment class and allow passing and returning
+#  Fact and Instance objects from the respective pointers
+# ========================================================================== #
+
+# Converter from internal form (type, value) of CLIPS data to the
+#  wrappers provided above, in order to simplify transparent conversions
+#{{FUNCTION
+def _cl2py(o):
+    """convert a well-formed tuple to one of the CLIPS wrappers"""
+    if o is None: return None
+    elif type(o) == tuple and len(o) == 2:
+        if o[0] == _c.INTEGER:
+            return Integer(o[1])
+        elif o[0] == _c.FLOAT:
+            return Float(o[1])
+        elif o[0] == _c.STRING:
+            return String(o[1])
+        elif o[0] == _c.INSTANCE_NAME:
+            return InstanceName(o[1])
+        elif o[0] == _c.SYMBOL:
+            if o[1] == "nil":
+                return Nil
+            else:
+                return Symbol(o[1])
+        elif o[0] == _c.INSTANCE_ADDRESS:
+            return Instance(o[1])
+        elif o[0] == _c.FACT_ADDRESS:
+            return Fact(o[1])
+        elif o[0] == _c.MULTIFIELD:
+            li = []
+            for (x, v) in o[1]:
+                if x == _c.INTEGER:
+                    li.append(Integer(v))
+                elif x == _c.FLOAT:
+                    li.append(Float(v))
+                elif x == _c.STRING:
+                    li.append(String(v))
+                elif x == _c.SYMBOL:
+                    li.append(Symbol(v))
+                elif x == _c.INSTANCE_NAME:
+                    li.append(InstanceName(v))
+                elif x == _c.INSTANCE_ADDRESS:
+                    li.append(Instance(v))
+                elif x == _c.FACT_ADDRESS:
+                    li.append(Fact(v))
+                else:
+                    raise TypeError("list cannot be converted")
+            return Multifield(li)
+        else:
+            raise TypeError("malformed tuple value")
+    else:
+        raise TypeError("wrong argument type")
+#}}
+
+# same as above, but from Python to CLIPS
+#{{FUNCTION
+def _py2cl(o):
+    """convert Python data to a well-formed tuple"""
+    t1 = type(o)
+    if t1 in (int, long):
+        return (_c.INTEGER, int(o))
+    elif t1 == float:
+        return (_c.FLOAT, float(o))
+    elif t1 in (str, unicode):
+        return (_c.STRING, str(o))
+    elif t1 in (ClipsIntegerType, ClipsFloatType, ClipsStringType,
+                ClipsSymbolType, ClipsInstanceNameType, ClipsNilType,
+                ClipsMultifieldType):
+        return o.clrepr()
+    elif t1 == Fact:
+        return (_c.FACT_ADDRESS, o._Fact__fact)
+    elif t1 == Instance:
+        return (_c.INSTANCE_ADDRESS, o._Instance__instance)
+    elif isinstance(o, int):
+        return (_c.INTEGER, int(o))
+    elif isinstance(o, long):
+        return (_c.INTEGER, int(o))
+    elif isinstance(o, float):
+        return (_c.FLOAT, float(o))
+    elif isinstance(o, str):
+        return (_c.STRING, str(o))
+    elif isinstance(o, unicode):
+        return (_c.STRING, str(o))
+    elif t1 in (list, tuple):
+        li = []
+        for x in o:
+            t0 = type(x)
+            if t0 in (int, long):
+                li.append((_c.INTEGER, int(x)))
+            elif t0 == float:
+                li.append((_c.FLOAT, float(x)))
+            elif t0 in (str, unicode):
+                li.append((_c.STRING, str(x)))
+            elif t0 in (ClipsIntegerType, ClipsFloatType, ClipsStringType,
+                        ClipsSymbolType, ClipsInstanceNameType, ClipsNilType):
+                li.append(x.clrepr())
+            elif t0 == Fact:
+                li.append((_c.FACT_ADDRESS, o._Fact__fact))
+            elif t0 == Instance:
+                li.append((_c.INSTANCE_ADDRESS, o._Instance__instance))
+            elif isinstance(x, int):
+                li.append((_c.INTEGER, int(o)))
+            elif isinstance(x, long):
+                li.append((_c.INTEGER, int(o)))
+            elif isinstance(x, float):
+                li.append((_c.FLOAT, float(o)))
+            elif isinstance(x, str):
+                li.append((_c.STRING, str(o)))
+            elif isinstance(x, unicode):
+                li.append((_c.STRING, str(o)))
+            else:
+                raise TypeError(
+                    "list element of type %s cannot be converted" % t0)
+        return (_c.MULTIFIELD, li)
+    else:
+        raise TypeError("value of type %s cannot be converted" % t1)
+#}}
+
+# convert a Python value to what the python value would be in CLIPS syntax
+def _py2clsyntax(o):
+    """convert Python data to CLIPS syntax"""
+    t1 = type(o)
+    if t1 in (int, long):
+        return Integer(int(o)).clsyntax()
+    elif t1 == float:
+        return Float(o).clsyntax()
+    elif t1 in (str, unicode):
+        return String(o).clsyntax()
+    elif t1 in (ClipsIntegerType, ClipsFloatType, ClipsStringType,
+                ClipsSymbolType, ClipsInstanceNameType, ClipsNilType,
+                ClipsMultifieldType):
+        return o.clsyntax()
+    elif isinstance(o, int):
+        return Integer(int(o)).clsyntax()
+    elif isinstance(o, long):
+        return Integer(int(o)).clsyntax()
+    elif isinstance(o, float):
+        return Float(o).clsyntax()
+    elif isinstance(o, str):
+        return String(o).clsyntax()
+    elif t1 in (list, tuple):
+        li = []
+        for x in o:
+            t0 = type(x)
+            if t0 in (int, long):
+                li.append(Integer(int(x)).clsyntax())
+            elif t0 == float:
+                li.append(Float(x).clsyntax())
+            elif t0 == str:
+                li.append(String(x).clsyntax())
+            elif t0 in (ClipsIntegerType, ClipsFloatType, ClipsStringType,
+                        ClipsSymbolType, ClipsInstanceNameType, ClipsNilType):
+                li.append(x.clsyntax())
+            elif isinstance(x, int):
+                li.append(Integer(int(x)).clsyntax())
+            elif isinstance(x, long):
+                li.append(Integer(int(x)).clsyntax())
+            elif isinstance(x, float):
+                li.append(Float(x).clsyntax())
+            elif isinstance(x, str):
+                li.append(String(x).clsyntax())
+            elif isinstance(x, unicode):
+                li.append(String(x).clsyntax())
+            else:
+                raise TypeError(
+                    "list element of type %s cannot be converted" % t0)
+        return Multifield(li).clsyntax()
+    else:
+        raise TypeError("value of type %s cannot be converted" % t1)
+
+
+
+# ========================================================================== #
+# NOTICE:
+#  as of version 1.0.5 (incremental 324) every class that should also appear
+#  in the environment-aware submodule must be surrounded by special comments,
+#  namely '#{{CLASS' and '#}}'; the same has to be done for functions: the
+#  surrounding comments in this case are '#{{FUNCTION' and '#}}'; this allows
+#  the setup process to be more readable and avoid certain 'tricks'
+# ========================================================================== #
+
+
+# ========================================================================== #
+# 0.1) Status functions and classes - as of APG section 4.1
+
+# as we did above, we group all the status functions under a class and then
+#  create a single instance of the class itself prohibiting further instances
+#{{CLASS
+class _clips_Status(object):
+    """object to access global status functions"""
+
+    __created = False
+
+    def __init__(self):
+        """raise an exception if an object of this type has been created"""
+        if(self.__created):
+            raise TypeError("cannot create this object twice")
+        self.__created = True
+
+    def __repr__(self):
+        return "<Configuration Management Object>"
+
+    def __getstate__(self):
+        raise _c.ClipsError("M03: cannot pickle engine status")
+
+    def __property_setFactDuplication(self, v):
+        _c.setFactDuplication(v)
+    def __property_getFactDuplication(self, v):
+        return bool(_c.getFactDuplication())
+    FactDuplication = property(
+        __property_getFactDuplication,
+        __property_setFactDuplication,
+        None, "Fact duplication behaviour")
+
+    def __property_setAutoFloatDividend(self, v):
+        _c.setAutoFloatDividend(v)
+    def __property_getAutoFloatDividend(self):
+        return bool(_c.getAutoFloatDividend())
+    AutoFloatDividend = property(
+        __property_getAutoFloatDividend,
+        __property_setAutoFloatDividend,
+        None, "AutoFloatDividend behaviour")
+
+    def __property_setDynamicConstraintChecking(self, v):
+        _c.setDynamicConstraintChecking(v)
+    def __property_getDynamicConstraintChecking(self):
+        return bool(_c.getDynamicConstraintChecking())
+    DynamicConstraintChecking = property(
+        __property_getDynamicConstraintChecking,
+        __property_setDynamicConstraintChecking,
+        None, "Dynamic constraint checking behaviour")
+
+    def __property_setSequenceOperatorRecognition(self, v):
+        _c.setSequenceOperatorRecognition(v)
+    def __property_getSequenceOperatorRecognition(self):
+        return bool(_c.getSequenceOperatorRecognition())
+    SequenceOperatorRecognition = property(
+        __property_getSequenceOperatorRecognition,
+        __property_setSequenceOperatorRecognition,
+        None, "Sequence operator recognition behaviour")
+
+    def __property_setStaticConstraintChecking(self, v):
+        _c.setStaticConstraintChecking(v)
+    def __property_getStaticConstraintChecking(self):
+        return bool(_c.getStaticConstraintChecking())
+    StaticConstraintChecking = property(
+        __property_getStaticConstraintChecking,
+        __property_setStaticConstraintChecking,
+        None, "Static constraint checking behaviour")
+
+    def __property_setIncrementalReset(self, v):
+        _c.setIncrementalReset(v)
+    def __property_getIncrementalReset(self):
+        return bool(_c.getIncrementalReset())
+    IncrementalReset = property(
+        __property_getIncrementalReset,
+        __property_setIncrementalReset,
+        None, "Incremental reset behaviour")
+
+    def __property_setResetGlobals(self, v):
+        _c.setResetGlobals(v)
+    def __property_getResetGlobals(self):
+        return bool(_c.getResetGlobals())
+    ResetGlobals = property(
+        __property_getResetGlobals,
+        __property_setResetGlobals,
+        None, "ResetGlobals behaviour")
+
+    def __property_setStrategy(self, v):
+        _c.setStrategy(v)
+    def __property_getStrategy(self):
+        return _c.getStrategy()
+    Strategy = property(
+        __property_getStrategy,
+        __property_setStrategy,
+        None, "strategy behaviour")
+
+    def __property_setSalienceEvaluation(self, v):
+        _c.setSalienceEvaluation(v)
+    def __property_getSalienceEvaluation(self):
+        return _c.getSalienceEvaluation()
+    SalienceEvaluation = property(
+        __property_getSalienceEvaluation,
+        __property_setSalienceEvaluation,
+        None, "salience evaluation behaviour")
+
+    def __property_setClassDefaultsMode(self, v):
+        _c.setClassDefaultsMode(v)
+    def __property_getClassDefaultsMode(self):
+        return _c.getClassDefaultsMode()
+    ClassDefaultsMode = property(
+        __property_getClassDefaultsMode,
+        __property_setClassDefaultsMode,
+        None, "class defaults mode")
+#}}
+
+
+
+# ========================================================================== #
+# 0.2) Debugging functions and classes - as of APG section 4.2
+
+# we group all debugging function under a class, then we prohibit
+#  creation of items of that class but provide an object able to
+#  access debugging status and to toggle debugging features
+#{{CLASS
+class _clips_Debug(object):
+    """object to enable/disable debugging features"""
+
+    __created = False
+
+    def __init__(self):
+        """one-time initializer"""
+        if(self.__created):
+            raise TypeError("cannot create this object twice")
+        self.__created = True
+        self.__watchitems = ['facts', 'rules', 'activations', 'compilations',
+                             'statistics', 'globals', 'slots', 'instances',
+                             'messages', 'message-handlers',
+                             'generic-functions', 'methods', 'deffunctions',]
+        # the following would modify the engine status on instantiation,
+        #  which would disallow storing current environment for swapping
+        ##for x in self.__watchitems: _c.unwatch(x)
+        ##_c.dribbleOff()
+
+    def __repr__(self):
+        return "<Debug Management Object>"
+
+    def __getstate__(self):
+        raise _c.ClipsError("M03: cannot pickle debug status")
+
+    def DribbleOn(self, fn):
+        """enable dribble on given file"""
+        _c.dribbleOn(fn)
+    def DribbleOff(self):
+        """turn off dribble"""
+        _c.dribbleOff()
+    def DribbleActive(self):
+        """tell whether or not dribble is active"""
+        return bool(_c.dribbleActive())
+
+    def __property_setFactsWatched(self, v):
+        if(v):
+            _c.watch("facts")
+        else:
+            _c.unwatch("facts")
+    def __property_getFactsWatched(self):
+        return bool(_c.getWatchItem("facts"))
+    FactsWatched = property(__property_getFactsWatched,
+                            __property_setFactsWatched,
+                            None, "Facts watch status")
+
+    def __property_setRulesWatched(self, v):
+        if(v):
+            _c.watch("rules")
+        else:
+            _c.unwatch("rules")
+    def __property_getRulesWatched(self):
+        return bool(_c.getWatchItem("rules"))
+    RulesWatched = property(__property_getRulesWatched,
+                            __property_setRulesWatched,
+                            None, "Rules watch status")
+
+    def __property_setActivationsWatched(self, v):
+        if(v):
+            _c.watch("activations")
+        else:
+            _c.unwatch("activations")
+    def __property_getActivationsWatched(self):
+        return bool(_c.getWatchItem("activations"))
+    ActivationsWatched = property(__property_getActivationsWatched,
+                                  __property_setActivationsWatched,
+                                  None, "Activations watch status")
+
+    def __property_setCompilationsWatched(self, v):
+        if(v):
+            _c.watch("compilations")
+        else:
+            _c.unwatch("compilations")
+    def __property_getCompilationsWatched(self):
+        return bool(_c.getWatchItem("compilations"))
+    CompilationsWatched = property(__property_getCompilationsWatched,
+                                   __property_setCompilationsWatched,
+                                   None, "compilations watch status")
+
+    def __property_setStatisticsWatched(self, v):
+        if(v):
+            _c.watch("statistics")
+        else:
+            _c.unwatch("statistics")
+    def __property_getStatisticsWatched(self):
+        return bool(_c.getWatchItem("statistics"))
+    StatisticsWatched = property(__property_getStatisticsWatched,
+                                 __property_setStatisticsWatched,
+                                 None, "statistics watch status")
+
+    def __property_setGlobalsWatched(self, v):
+        if(v):
+            _c.watch("globals")
+        else:
+            _c.unwatch("globals")
+    def __property_getGlobalsWatched(self):
+        return bool(_c.getWatchItem("globals"))
+    GlobalsWatched = property(__property_getGlobalsWatched,
+                              __property_setGlobalsWatched,
+                              None, "Globals watch status")
+
+    def __property_setSlotsWatched(self, v):
+        if(v):
+            _c.watch("slots")
+        else:
+            _c.unwatch("slots")
+    def __property_getSlotsWatched(self):
+        return bool(_c.getWatchItem("slots"))
+    SlotsWatched = property(__property_getSlotsWatched,
+                            __property_setSlotsWatched,
+                            None, "Slots watch status")
+
+    def __property_setMessagesWatched(self, v):
+        if(v):
+            _c.watch("messages")
+        else:
+            _c.unwatch("messages")
+    def __property_getMessagesWatched(self):
+        return bool(_c.getWatchItem("messages"))
+    MessagesWatched = property(__property_getMessagesWatched,
+                               __property_setMessagesWatched,
+                               None, "messages watch status")
+
+    def __property_setMessageHandlersWatched(self, v):
+        if(v):
+            _c.watch("message-handlers")
+        else:
+            _c.unwatch("message-handlers")
+    def __property_getMessageHandlersWatched(self):
+        return bool(_c.getWatchItem("message-handlers"))
+    MessageHandlersWatched = property(__property_getMessageHandlersWatched,
+                                      __property_setMessageHandlersWatched,
+                                      None, "MessageHandlers watch status")
+
+    def __property_setGenericFunctionsWatched(self, v):
+        if(v):
+            _c.watch("generic-functions")
+        else:
+            _c.unwatch("generic-functions")
+    def __property_getGenericFunctionsWatched(self):
+        return bool(_c.getWatchItem("generic-functions"))
+    GenericFunctionsWatched = property(__property_getGenericFunctionsWatched,
+                                       __property_setGenericFunctionsWatched,
+                                       None, "Generic functions watch status")
+
+    def __property_setMethodsWatched(self, v):
+        if(v):
+            _c.watch("methods")
+        else:
+            _c.unwatch("methods")
+    def __property_getMethodsWatched(self):
+        return bool(_c.getWatchItem("methods"))
+    MethodsWatched = property(__property_getMethodsWatched,
+                              __property_setMethodsWatched,
+                              None, "Methods watch status")
+
+    def __property_setFunctionsWatched(self, v):
+        if(v):
+            _c.watch("deffunctions")
+        else:
+            _c.unwatch("deffunctions")
+    def __property_getFunctionsWatched(self):
+        return bool(_c.getWatchItem("deffunctions"))
+    FunctionsWatched = property(__property_getFunctionsWatched,
+                                __property_setFunctionsWatched,
+                                None, "Deffunctions watch status")
+
+    def __property_setExternalTraceback(self, v):
+        _c.setPrintExternalTraceback(bool(v))
+    def __property_getExternalTraceback(self):
+        return bool(_c.getPrintExternalTraceback())
+    ExternalTraceback = property(__property_getExternalTraceback,
+                                 __property_setExternalTraceback,
+                                 None,
+                                 "traceback of Python functions in CLIPS")
+
+    def WatchAll(self):
+        """watch all items"""
+        for x in self.__watchitems:
+            _c.watch(x)
+    def UnwatchAll(self):
+        """unwatch all items"""
+        for x in self.__watchitems:
+            _c.unwatch(x)
+#}}
+
+
+
+# ========================================================================== #
+# High-level class for deftemplate objects
+# Treat a deftemplate as an object having an Object-Oriented interface.
+#  Implements all the functions needed to access deftemplate objects.
+#{{CLASS
+class Template(object):
+    """high-level Template class (represents: deftemplate)"""
+
+    def __init__(self, o=None):
+        """create a Template object (internal)"""
+        if _c.isDeftemplate(o):
+            self.__deftemplate = o
+        else:
+            raise _c.ClipsError("M01: cannot directly create Template")
+
+        class __template_Slots:
+            """define a structure for Class Slots"""
+            def __init__(self, o):
+                self.__deftemplate = o
+            def __getstate__(self):
+                raise _c.ClipsError("M03: cannot pickle template slots")
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def AllowedValues(self, name):
+                """return allowed values for specified Slot"""
+                rv = _cl2py(
+                    _c.deftemplateSlotAllowedValues(self.__deftemplate, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def Cardinality(self, name):
+                """return cardinality for specified Slot"""
+                rv = _cl2py(
+                    _c.deftemplateSlotCardinality(self.__deftemplate, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def HasDefault(self, name):
+                """one of NO_DEFAULT, STATIC_DEFAULT or DYNAMIC_DEFAULT"""
+                return _c.deftemplateSlotDefaultP(self.__deftemplate, name)
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def DefaultValue(self, name):
+                """return default value for specified Slot"""
+                rv = _cl2py(
+                    _c.deftemplateSlotDefaultValue(self.__deftemplate, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def Exists(self, name):
+                """return True if specified Slot exists"""
+                return bool(
+                    _c.deftemplateSlotExistP(self.__deftemplate, name))
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def IsMultifield(self, name):
+                """return True if specified Slot is a multifield one"""
+                return bool(
+                    _c.deftemplateSlotMultiP(self.__deftemplate, name))
+
+            def Names(self):
+                """return the list of Slot names"""
+                rv = _cl2py(_c.deftemplateSlotNames(self.__deftemplate))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def Range(self, name):
+                """return numeric range information of specified Slot"""
+                rv = _cl2py(_c.deftemplateSlotRange(self.__deftemplate, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def IsSinglefield(self, name):
+                """return True if specified Slot is a single field one"""
+                return bool(
+                    _c.deftemplateSlotSingleP(self.__deftemplate, name))
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def Types(self, name):
+                """return names of primitive types for specified Slot"""
+                rv = _cl2py(_c.deftemplateSlotTypes(self.__deftemplate, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+        self.__Slots = __template_Slots(self.__deftemplate)
+        try:
+            self.__Slots._template_Slots__env = self.__env
+        except AttributeError: pass
+        try:
+            self.__Slots._template_Slots__envobject = self.__envobject
+        except AttributeError: pass
+
+    def __str__(self):
+        """string form of Template"""
+        return _c.getDeftemplateName(self.__deftemplate)
+
+    def __repr__(self):
+        """representation of Template"""
+        s = repr(self.__deftemplate)[1:-1]
+        return "<Template '%s': %s>" % (
+            _c.getDeftemplateName(self.__deftemplate), s)
+
+    def __getstate__(self):
+        raise _c.ClipsError(
+            "M03: cannot pickle objects of type '%s'"
+            % self.__class__.__name__)
+
+    # Interface
+    def Next(self):
+        """return next Template"""
+        o = _c.getNextDeftemplate(self.__deftemplate)
+        if(o):
+            return Template(o)
+        else:
+            return None
+
+    def PPForm(self):
+        """return the pretty-print form of Template"""
+        return _c.getDeftemplatePPForm(self.__deftemplate)
+
+    def Remove(self):
+        """remove Template"""
+        _c.undeftemplate(self.__deftemplate)
+
+    def BuildFact(self):
+        """create a fact from this Template without asserting it"""
+        return Fact(self.__deftemplate)
+
+    def InitialFact(self):
+        """find initial Fact for this Template"""
+        return Fact(_c.getNextFactInTemplate(self.__deftemplate))
+
+    def NextFact(self, fact):
+        """find initial Fact for this Template"""
+        return Fact(
+            _c.getNextFactInTemplate(self.__deftemplate, fact._Fact__fact))
+
+    def __property_getDeletable(self):
+        return bool(_c.isDeftemplateDeletable(self.__deftemplate))
+    Deletable = property(__property_getDeletable, None, None,
+                         "verify if this Template can be deleted")
+
+    def __property_getName(self):
+        return Symbol(_c.getDeftemplateName(self.__deftemplate))
+    Name = property(__property_getName, None, None, "retrieve Template name")
+
+    def __property_getModule(self):
+        return Symbol(_c.deftemplateModule(self.__deftemplate))
+    Module = property(__property_getModule, None, None,
+                      "retrieve Template Module name")
+
+    # access class slots through the internal object
+    def __property_getSlots(self): return self.__Slots
+    Slots = property(__property_getSlots, None, None,
+                     "Template Slots information")
+
+    # debugging functions and properties
+    def __property_setWatch(self, v):
+        _c.setDeftemplateWatch(v, self.__deftemplate)
+    def __property_getWatch(self):
+        return _c.getDeftemplateWatch(self.__deftemplate)
+    Watch = property(__property_getWatch, __property_setWatch,
+                     None, "watch status of this Template")
+#}}
+
+
+
+# ========================================================================== #
+# High-level class for fact objects
+# Treat a fact as an object having an Object-Oriented interface. All functions
+#  that normally refer to a fact use the underlying low-level fact object to
+#  interact with the system.
+#{{CLASS
+class Fact(object):
+    """high-level Fact class (represents: fact)"""
+
+    # class constructor - we want to initialize the fact in several ways, ie.
+    #  by creation (using a Template or its underlying __deftemplate), by
+    #  copy (using a Fact or its underlying __fact), or by assertion using a
+    #  string; besides this, we also want to initialize some internal structs
+    #  that help use the fact "the Python way" (eg. the fact slots should be
+    #  grouped in a string-addressed dictionary, as it would naturally be)
+    def __init__(self, o):
+        """create a Fact object"""
+        # this on-the-fly class takes the underlying fact object, which
+        #  should already exist, and accesses its slots through the functions
+        #  provided by the low-level module, thus exposing a dictionary-like
+        #  interface that can be used to access slots at high level
+        #  NOTE: there is a hack that allows the environment version to work
+        #        by trying to access the underlying environment object
+        class __fact_Slots:
+            """access fact Slots"""
+            def __init__(self, fo):
+                self.__fact = fo
+
+            @_accepts_method((str, unicode), None)
+            @_forces_method(str, None)
+            def __setitem__(self, name, v):
+                _c.putFactSlot(self.__fact, name, _py2cl(v))
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def __getitem__(self, name):
+                if not name:
+                    return _cl2py(_c.getFactSlot(self.__fact))
+                else:
+                    return _cl2py(_c.getFactSlot(self.__fact, name))
+
+            def keys(self):
+                return _cl2py(_c.factSlotNames(self.__fact))
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def has_key(self, k):
+                return k in map(str, _cl2py(_c.factSlotNames(self.__fact)))
+
+            def __repr__(self):
+                return "<Fact '%s' Slots>" \
+                       % _c.getFactPPForm(self.__fact).split()[0]
+
+            def __getstate__(self):
+                raise _c.ClipsError("M03: cannot pickle fact slots")
+
+        # now we can instance an object of this kind, and throw the class
+        #  away; however the instance must be created at the end of function
+        #  body since the fact has to be created at lower level
+        if _c.isFact(o):
+            self.__fact = o
+        elif '_Fact__fact' in dir(o) and _c.isFact(o.__fact):
+            self.__fact = o.__fact
+        elif _c.isDeftemplate(o):
+            self.__fact = _c.createFact(o)
+        elif '_Template__deftemplate' in dir(o) and \
+           _c.isDeftemplate(o._Template__deftemplate):
+            self.__fact = _c.createFact(o._Template__deftemplate)
+        elif type(o) == str:
+            try:
+                self.__fact = _c.assertString(o)
+            except:
+                raise ValueError("invalid assertion string")
+        else:
+            raise TypeError("argument should be Fact, Template or str")
+        # here the fact is created: we create an instance of it and do not
+        #  care about internal class definition destiny, since it's useful
+        #  that this class definition disappears from Fact dictionary
+        self.__Slots = __fact_Slots(self.__fact)
+        try:
+            self.__Slots._fact_Slots__env = self.__env
+        except AttributeError: pass
+        try:
+            self.__Slots._fact_Slots__envobject = self.__envobject
+        except AttributeError: pass
+
+    def __str__(self):
+        """string form of Fact"""
+        return _c.getFactPPForm(self.__fact).split()[0]
+
+    def __repr__(self):
+        """representation of Fact"""
+        s = repr(self.__fact)[1:-1]
+        return "<Fact '%s': %s>" % (
+            _c.getFactPPForm(self.__fact).split()[0], s)
+
+    def __getstate__(self):
+        raise _c.ClipsError(
+            "M03: cannot pickle objects of type '%s'"
+            % self.__class__.__name__)
+
+    # interface
+    def Assert(self):
+        """assert this Fact"""
+        self.__fact = _c.assertFact(self.__fact)
+
+    def Retract(self):
+        """retract this Fact"""
+        _c.retract(self.__fact)
+
+    def AssignSlotDefaults(self):
+        """assign Fact Slot defaults"""
+        _c.assignFactSlotDefaults(self.__fact)
+
+    def Next(self):
+        """return next Fact"""
+        o = _c.getNextFact(self.__fact)
+        if(o):
+            return Fact(o)
+        else:
+            return None
+
+    def PPForm(self):
+        """return the pretty-print form of Fact"""
+        return _c.getFactPPForm(self.__fact)
+
+    def PPrint(self, ignoredefaults=True):
+        """pretty-print fact, possibly including slot default values"""
+        _c.routerClear("temporary")
+        _c.ppFact(self.__fact, "temporary", ignoredefaults)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    def CleanPPForm(self):
+        """return the pretty-print form of Fact"""
+        return _c.getFactPPForm(self.__fact).split(None, 1)[1].strip()
+
+    # return the relation field
+    def __property_getRelation(self):
+        return Symbol(
+            _c.getFactPPForm(self.__fact).split(
+                None, 1)[1].strip()[1:-1].split(None, 1)[0])
+    Relation = property(__property_getRelation, None, None,
+                        "fact relation symbol")
+
+    # the list of implied slots
+    def __property_getImpliedSlots(self):
+        try:
+            mli = _cl2py(_c.getFactSlot(self.__fact))
+        except:
+            mli = Multifield([])
+        return mli
+    ImpliedSlots = property(__property_getImpliedSlots, None, None,
+                            "list of implied Slots")
+
+    # access fact index, read only property
+    def __property_getIndex(self):
+        return _c.factIndex(self.__fact)
+    Index = property(__property_getIndex, None, None, "index of this Fact")
+
+    # access fact slots through the internal object
+    def __property_getSlots(self):
+        return self.__Slots
+    Slots = property(__property_getSlots, None, None,
+                     """Fact Slots dictionary""")
+
+    # access Template of this Fact, read only property
+    def __property_getTemplate(self):
+        return Template(_c.factDeftemplate(self.__fact))
+    Template = property(__property_getTemplate, None, None,
+                        """Template for this Fact""")
+
+    # tell whether or not this Fact has been retracted (if asserted)
+    def __property_getExists(self):
+        return bool(_c.factExistp(self.__fact))
+    Exists = property(__property_getExists, None, None,
+                      "determine if Fact has been asserted and not retracted")
+#}}
+
+
+
+# ========================================================================== #
+# High-level class for deffacts objects
+# Treat a deffacts as an object having an Object-Oriented interface.
+#  Implements all the functions needed to access deffacts objects.
+#{{CLASS
+class Deffacts(object):
+    """high-level Deffacts class (represents: deffacts)"""
+
+    def __init__(self, o):
+        """create a Deffacts object (internal)"""
+        if _c.isDeffacts(o):
+            self.__deffacts = o
+        else:
+            raise _c.ClipsError("M01: cannot directly create Deffacts")
+
+    def __str__(self):
+        """string form of Deffacts"""
+        return _c.getDeffactsName(self.__deffacts)
+
+    def __repr__(self):
+        """representation of Deffacts"""
+        s = repr(self.__deffacts)[1:-1]
+        return "<Deffacts '%s': %s>" % (
+            _c.getDeffactsName(self.__deffacts), s)
+
+    def __getstate__(self):
+        raise _c.ClipsError("M03: cannot pickle objects of type '%s'"
+              % self.__class__.__name__)
+
+    # Interface
+    def Next(self):
+        """return next Deffacts"""
+        o = _c.getNextDeffacts(self.__deffacts)
+        if(o):
+            return Deffacts(o)
+        else:
+            return None
+
+    def PPForm(self):
+        """return the pretty-print form of Deffacts"""
+        return _c.getDeffactsPPForm(self.__deffacts)
+
+    def Remove(self):
+        """remove Deffacts"""
+        _c.undeffacts(self.__deffacts)
+
+    def __property_getName(self):
+        return Symbol(_c.getDeffactsName(self.__deffacts))
+    Name = property(__property_getName, None, None, "retrieve Deffacts name")
+
+    def __property_getModule(self):
+        return Symbol(_c.deffactsModule(self.__deffacts))
+    Module = property(__property_getModule, None, None,
+                      "retrieve Deffacts Module name")
+
+    def __property_getDeletable(self):
+        return bool(_c.isDeffactsDeletable(self.__deffacts))
+    Deletable = property(__property_getDeletable, None, None,
+                         "verify if this Deffacts can be deleted")
+#}}
+
+
+
+# ========================================================================== #
+# High-level class for defrule objects
+# Treat a defrule as an object having an Object-Oriented interface.
+#  Implements all the functions needed to access defrule objects.
+#{{CLASS
+class Rule(object):
+    """high-level Rule class (represents: defrule)"""
+
+    def __init__(self, o):
+        """create a Rule object (internal)"""
+        if _c.isDefrule(o):
+            self.__defrule = o
+        else:
+            raise _c.ClipsError("M01: cannot directly create Rule")
+
+    def __str__(self):
+        """string form of Rule"""
+        return _c.getDefruleName(self.__defrule)
+
+    def __repr__(self):
+        """representation of Rule"""
+        s = repr(self.__defrule)[1:-1]
+        return "<Rule '%s': %s>" % (
+            _c.getDefruleName(self.__defrule), s)
+
+    def __getstate__(self):
+        raise _c.ClipsError("M03: cannot pickle objects of type '%s'"
+            % self.__class__.__name__)
+
+    # Interface
+    def Next(self):
+        """return next Rule"""
+        o = _c.getNextDefrule(self.__defrule)
+        if o:
+            return Rule(o)
+        else:
+            return None
+
+    def PPForm(self):
+        """return the pretty-print form of Rule"""
+        return _c.getDefrulePPForm(self.__defrule)
+
+    def Refresh(self):
+        """refresh Rule"""
+        _c.refresh(self.__defrule)
+
+    def PrintMatches(self):
+        """print partial matches to standard output"""
+        _c.routerClear("temporary")
+        _c.matches("temporary", self.__defrule)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    def Remove(self):
+        """remove Rule"""
+        _c.undefrule(self.__defrule)
+
+    def __property_getName(self):
+        return Symbol(_c.getDefruleName(self.__defrule))
+    Name = property(__property_getName, None, None, "retrieve Rule name")
+
+    def __property_getModule(self):
+        return Symbol(_c.defruleModule(self.__defrule))
+    Module = property(__property_getModule, None, None,
+                      "retrieve Rule Module name")
+
+    def __property_setBreak(self, v):
+        if v:
+            _c.setBreak(self.__defrule)
+        else:
+            if _c.defruleHasBreakpoint(self.__defrule):
+                _c.removeBreak(self.__defrule)
+    def __property_getBreak(self):
+        return bool(_c.defruleHasBreakpoint(self.__defrule))
+    Breakpoint = property(__property_getBreak, __property_setBreak,
+                          None, "set or remove breakpoint from Rule")
+
+    def __property_getDeletable(self):
+        return bool(_c.isDefruleDeletable(self.__defrule))
+    Deletable = property(__property_getDeletable, None, None,
+                         "verify if this Rule can be deleted")
+
+    def __property_setWatchActivations(self, v):
+        _c.setDefruleWatchActivations(self.__defrule, v)
+    def __property_getWatchActivations(self):
+        return bool(_c.getDefruleWatchActivations(self.__defrule))
+    WatchActivations = property(__property_getWatchActivations,
+                                __property_setWatchActivations,
+                                None, "Rule Activations debug status")
+
+    def __property_setWatchFirings(self, v):
+        _c.setDefruleWatchFirings(self.__defrule, v)
+    def __property_getWatchFirings(self):
+        return bool(_c.getDefruleWatchFirings(self.__defrule))
+    WatchFirings = property(__property_getWatchFirings,
+                            __property_setWatchFirings,
+                            None, "Rule firings debug status")
+#}}
+
+
+
+# ========================================================================== #
+# High-level class for activation objects
+# Treat an activation as an object having an Object-Oriented interface.
+#  Implements all the functions needed to access activation objects.
+#{{CLASS
+class Activation(object):
+    """high-level Activation class (represents: activation)"""
+
+    def __init__(self, o):
+        """create an Activation object (internal)"""
+        if _c.isActivation(o):
+            self.__activation = o
+        else:
+            raise _c.ClipsError("M01: cannot directly create Activation")
+
+    def __str__(self):
+        """string form of Activation"""
+        return _c.getActivationName(self.__activation)
+
+    def __repr__(self):
+        """representation of Activation"""
+        return "<Activation '%s'>" % _c.getActivationName(self.__activation)
+
+    def __getstate__(self):
+        raise _c.ClipsError("M03: cannot pickle objects of type '%s'"
+            % self.__class__.__name__)
+
+    # Interface
+    def Next(self):
+        """return next Activation"""
+        o = _c.getNextActivation(self.__activation)
+        if o:
+            return Activation(o)
+        else:
+            return None
+
+    def PPForm(self):
+        """return the pretty-print form of Activation"""
+        return _c.getActivationPPForm(self.__activation)
+
+    def Remove(self):
+        """remove this Activation"""
+        _c.deleteActivation(self.__activation)
+
+    def __property_getName(self):
+        return Symbol(_c.getActivationName(self.__activation))
+    Name = property(__property_getName, None, None,
+                    "retrieve Activation name")
+
+    def __property_setSalience(self, v):
+        _c.setActivationSalience(self.__activation, v)
+    def __property_getSalience(self):
+        return _c.getActivationSalience(self.__activation)
+    Salience = property(__property_getSalience, __property_setSalience,
+                        None, "retrieve Activation salience")
+#}}
+
+
+
+# ========================================================================== #
+# High-level class for defglobal objects
+# Treat a defglobal as an object having an Object-Oriented interface.
+#  Implements all the functions needed to access defglobal objects.
+#{{CLASS
+class Global(object):
+    """high-level Global class (represents: defglobal)"""
+
+    def __init__(self, o):
+        """create a Global object (internal)"""
+        if _c.isDefglobal(o):
+            self.__defglobal = o
+        else:
+            raise _c.ClipsError("M01: cannot directly create Global")
+
+    def __str__(self):
+        """string form of Global"""
+        return _c.getDefglobalName(self.__defglobal)
+
+    def __repr__(self):
+        """representation of Global"""
+        s = repr(self.__defglobal)[1:-1]
+        return "<Global '%s': %s>" % (
+            _c.getDefglobalName(self.__defglobal), s)
+
+    def __getstate__(self):
+        raise _c.ClipsError("M03: cannot pickle objects of type '%s'"
+            % self.__class__.__name__)
+
+    # Interface
+    def Next(self):
+        """return next Global"""
+        o = _c.getNextDefglobal(self.__defglobal)
+        if o:
+            return Global(o)
+        else:
+            return None
+
+    def PPForm(self):
+        """return the pretty-print form of Global"""
+        return _c.getDefglobalPPForm(self.__defglobal)
+
+    def ValueForm(self):
+        """return a 'printed' form of Global value"""
+        return _c.getDefglobalValueForm(self.__defglobal)
+
+    def Remove(self):
+        """remove this Global"""
+        _c.undefglobal(self.__defglobal)
+
+    def __property_getName(self):
+        return Symbol(_c.getDefglobalName(self.__defglobal))
+    Name = property(__property_getName, None, None, "retrieve Global name")
+
+    def __property_getModule(self):
+        return Symbol(_c.defglobalModule(self.__defglobal))
+    Module = property(__property_getModule, None, None,
+                      "retrieve Global Module name")
+
+    def __property_setValue(self, v):
+        _c.setDefglobalValue(self.Name, _py2cl(v))
+    def __property_getValue(self):
+        return _cl2py(_c.getDefglobalValue(self.Name))
+    Value = property(__property_getValue, __property_setValue,
+                     None, "set/retrieve Global value")
+
+    def __property_getDeletable(self):
+        return bool(_c.isDefglobalDeletable(self.__defglobal))
+    Deletable = property(__property_getDeletable, None, None,
+                         "verify if this Global can be deleted")
+
+    def __property_setWatch(self, v):
+        _c.setDefglobalWatch(v, self.__defglobal)
+    def __property_getWatch(self):
+        return _c.getDefglobalWatch(self.__defglobal)
+    Watch = property(__property_getWatch, __property_setWatch,
+                     None, "set/retrieve Global debug status")
+#}}
+
+
+
+# ========================================================================== #
+# High-level class for deffunction objects
+# Treat a deffunction as an object having an Object-Oriented interface.
+#  Implements all the functions needed to access deffunction objects.
+#{{CLASS
+class Function(object):
+    """high-level Function class (represents: deffunction)"""
+
+    def __init__(self, o):
+        """create a Function object (internal)"""
+        if _c.isDeffunction(o):
+            self.__deffunction = o
+        else:
+            raise _c.ClipsError("M01: cannot directly create Function")
+
+    def __str__(self):
+        """string form of Function"""
+        return _c.getDeffunctionName(self.__deffunction)
+
+    def __repr__(self):
+        """representation of Function"""
+        s = repr(self.__deffunction)[1:-1]
+        return "<Function '%s': %s>" % (
+            _c.getDeffunctionName(self.__deffunction), s)
+
+    def __getstate__(self):
+        raise _c.ClipsError("M03: cannot pickle objects of type '%s'"
+            % self.__class__.__name__)
+
+    # Interface
+    def Next(self):
+        """return next Function"""
+        o = _c.getNextDeffunction(self.__deffunction)
+        if o:
+            return Function(o)
+        else:
+            return None
+
+    def PPForm(self):
+        """return the pretty-print form of Function"""
+        return _c.getDeffunctionPPForm(self.__deffunction)
+
+    def Remove(self):
+        """remove this Function"""
+        _c.undeffunction(self.__deffunction)
+
+    def Call(self, *args):
+        """call this Function with given arguments"""
+        func = _c.getDeffunctionName(self.__deffunction)
+        if args:
+            if(len(args) == 1 and type(args[0]) == str):
+                sargs = args[0]
+            else:
+                li = []
+                for x in args:
+                    t1 = type(x)
+                    if t1 in (ClipsIntegerType, ClipsFloatType,
+                              ClipsStringType, ClipsSymbolType, ClipsNilType,
+                              ClipsInstanceNameType, ClipsMultifieldType):
+                        li.append(_py2clsyntax(x))
+                    elif t1 in (int, long):
+                        li.append(Integer(x).clsyntax())
+                    elif t1 == float:
+                        li.append(Float(x).clsyntax())
+                    elif t1 in (str, unicode):
+                        li.append(String(x).clsyntax())
+                    elif isinstance(x, int):
+                        li.append(Integer(x).clsyntax())
+                    elif isinstance(x, long):
+                        li.append(Integer(x).clsyntax())
+                    elif isinstance(x, float):
+                        li.append(Float(x).clsyntax())
+                    elif isinstance(x, str):
+                        li.append(String(x).clsyntax())
+                    elif isinstance(x, unicode):
+                        li.append(String(x).clsyntax())
+                    else:
+                        li.append(str(x))
+                sargs = " ".join(li)
+            return _cl2py(_c.functionCall(func, sargs))
+        else:
+            return _cl2py(_c.functionCall(func))
+    __call__ = Call
+
+    def __property_getName(self):
+        return Symbol(_c.getDeffunctionName(self.__deffunction))
+    Name = property(__property_getName, None, None, "retrieve Function name")
+
+    def __property_getModule(self):
+        return Symbol(_c.deffunctionModule(self.__deffunction))
+    Module = property(__property_getModule, None, None,
+                      "retrieve Function Module name")
+
+    def __property_getDeletable(self):
+        return bool(_c.isDeffunctionDeletable(self.__deffunction))
+    Deletable = property(__property_getDeletable, None, None,
+                         "verify if this Function can be deleted")
+
+    def __property_setWatch(self, v):
+        _c.setDeffunctionWatch(v, self.__deffunction)
+    def __property_getWatch(self):
+        return bool(_c.getDeffunctionWatch(self.__deffunction))
+    Watch = property(__property_getWatch, __property_setWatch,
+                     None, "set/retrieve Function debug status")
+#}}
+
+
+
+# ========================================================================== #
+# High-level class for defgeneric objects
+# Treat a defgeneric as an object having an Object-Oriented interface.
+#  Implements all the functions needed to access defgeneric objects.
+#{{CLASS
+class Generic(object):
+    """high-level Generic class (represents: defgeneric)"""
+
+    def __init__(self, o):
+        """create a Generic function object (internal)"""
+        if _c.isDefgeneric(o):
+            self.__defgeneric = o
+        else:
+            raise _c.ClipsError("M01: cannot directly create Generic")
+
+    def __str__(self):
+        """string form of Generic"""
+        return _c.getDefgenericName(self.__defgeneric)
+
+    def __repr__(self):
+        """representation of Generic"""
+        s = repr(self.__defgeneric)[1:-1]
+        return "<Generic '%s': %s>" % (
+            _c.getDefgenericName(self.__defgeneric), s)
+
+    def __getstate__(self):
+        raise _c.ClipsError("M03: cannot pickle objects of type '%s'"
+            % self.__class__.__name__)
+
+    # Interface
+    def Next(self):
+        """return next Generic"""
+        o = _c.getNextDefgeneric(self.__defgeneric)
+        if o:
+            return Generic(o)
+        else:
+            return None
+
+    def PPForm(self):
+        """return the pretty-print form of Generic"""
+        return _c.getDefgenericPPForm(self.__defgeneric)
+
+    def Remove(self):
+        """remove this Generic"""
+        _c.undefgeneric(self.__defgeneric)
+
+    def Call(self, *args):
+        """call this Generic with given arguments"""
+        func = _c.getDefgenericName(self.__defgeneric)
+        if args:
+            if(len(args) == 1 and type(args[0]) in (str, unicode)):
+                sargs = str(args[0])
+            else:
+                li = []
+                for x in args:
+                    t1 = type(x)
+                    if t1 in (ClipsIntegerType, ClipsFloatType,
+                              ClipsStringType, ClipsSymbolType, ClipsNilType,
+                              ClipsInstanceNameType, ClipsMultifieldType):
+                        li.append(_py2clsyntax(x))
+                    elif t1 in (int, long):
+                        li.append(Integer(int(x)).clsyntax())
+                    elif t1 == float:
+                        li.append(Float(x).clsyntax())
+                    elif t1 in (str, unicode):
+                        li.append(String(x).clsyntax())
+                    elif isinstance(x, int):
+                        li.append(Integer(x).clsyntax())
+                    elif isinstance(x, long):
+                        li.append(Integer(x).clsyntax())
+                    elif isinstance(x, float):
+                        li.append(Float(x).clsyntax())
+                    elif isinstance(x, str):
+                        li.append(String(x).clsyntax())
+                    elif isinstance(x, unicode):
+                        li.append(String(x).clsyntax())
+                    else:
+                        li.append(str(x))
+                sargs = " ".join(li)
+            return _cl2py(_c.functionCall(func, sargs))
+        else:
+            return _cl2py(_c.functionCall(func))
+    __call__ = Call
+
+    def __property_getName(self):
+        return Symbol(_c.getDefgenericName(self.__defgeneric))
+    Name = property(__property_getName, None, None, "retrieve Generic name")
+
+    def __property_getModule(self):
+        return Symbol(_c.defgenericModule(self.__defgeneric))
+    Module = property(__property_getModule, None, None,
+                      "retrieve Generic Module name")
+
+    def __property_getDeletable(self):
+        return bool(_c.isDefgenericDeletable(self.__defgeneric))
+    Deletable = property(__property_getDeletable, None, None,
+                         "verify if this Generic can be deleted")
+
+    def __property_setWatch(self, v):
+        _c.setDefgenericWatch(v, self.__defgeneric)
+    def __property_getWatch(self):
+        return bool(_c.getDefgenericWatch(self.__defgeneric))
+    Watch = property(__property_getWatch, __property_setWatch,
+                     None, "set/retrieve Generic debug status")
+
+    # Method functions
+    def MethodList(self):
+        """return the list of Method indices for this Generic"""
+        o = _c.getDefmethodList(self.__defgeneric)
+        li, mli = Multifield(_cl2py(o)), Multifield([])
+        l = len(li) / 2
+        for x in range(0, l):
+            mli.append(li[2 * x + 1])
+        return mli
+
+    def MethodDescription(self, midx):
+        """return the synopsis of specified Method restrictions"""
+        return _c.getDefmethodDescription(midx, self.__defgeneric)
+
+    def MethodPPForm(self, midx):
+        """return the pretty-print form of specified Method"""
+        return _c.getDefmethodPPForm(midx, self.__defgeneric)
+
+    def MethodRestrictions(self, midx):
+        """return the restrictions of specified Method"""
+        return Multifield(
+            _cl2py(_c.getMethodRestrictions(midx, self.__defgeneric)))
+
+    def InitialMethod(self):
+        """return the index of first Method in this Generic"""
+        try:
+            return _c.getNextDefmethod(0, self.__defgeneric)
+        except:
+            raise _c.ClipsError("M02: could not find any Method")
+
+    def NextMethod(self, midx):
+        """return the index of next Method in this Generic"""
+        return _c.getNextDefmethod(midx, self.__defgeneric)
+
+    def PrintMethods(self):
+        """print out Method list for this Generic"""
+        _c.routerClear("temporary")
+        _c.listDefmethods("temporary", self.__defgeneric)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    @_accepts_method(None, None, (int, long), None)
+    def AddMethod(self, restrictions, actions, midx=None, comment=None):
+        """Add a method to this Generic, given restrictions and actions"""
+        if comment:
+            cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+        else:
+            cmtstr = ""
+        if midx:
+            indstr = str(midx)
+        else:
+            indstr = ""
+        if type(restrictions) in (tuple, list):
+            rstr = ""
+            for x in restrictions:
+                if type(x) not in (tuple, str, unicode):
+                    raise TypeError("tuple or string expected as restriction")
+                if type(x) == str:
+                    rstr += "(%s)" % x
+                elif type(x) == unicode:
+                    rstr += "(%s)" % str(x)
+                else:
+                    if len(x) < 2:
+                        raise ValueError("tuple must be at least a pair")
+                    v1, v2 = str(x[0]), []
+                    for y in range(1, len(x)):
+                        z = x[y]
+                        if z == str:
+                            v2.append("STRING")
+                        elif z == ClipsStringType:
+                            v2.append("STRING")
+                        elif z == ClipsSymbolType:
+                            v2.append("SYMBOL")
+                        elif z == ClipsInstanceNameType:
+                            v2.append("INSTANCE-NAME")
+                        elif z == int:
+                            v2.append("INTEGER")
+                        elif z == ClipsIntegerType:
+                            v2.append("INTEGER")
+                        elif z == float:
+                            v2.append("FLOAT")
+                        elif z == ClipsFloatType:
+                            v2.append("FLOAT")
+                        elif z == list:
+                            v2.append("MULTIFIELD")
+                        elif z == ClipsMultifieldType:
+                            v2.append("MULTIFIELD")
+                        elif type(z) == str:
+                            v2.append(z)
+                        elif type(z) == unicode:
+                            v2.append(str(z))
+                        else:
+                            raise TypeError("unexpected value '%s'" % z)
+                        rstr += "(%s %s)" % (v1, " ".join(v2))
+        elif type(restrictions) == str:
+            rstr = restrictions
+        else:
+            raise TypeError("tuple or string expected as restriction")
+        _c.build("(defmethod %s %s %s (%s) %s)" % (
+            self.Name, indstr, cmtstr, rstr, actions))
+
+    def RemoveMethod(self, midx):
+        """remove specified Method"""
+        _c.undefmethod(midx, self.__defgeneric)
+
+    # these are peculiar, since defmethods cannot be rendered as classes
+    def WatchMethod(self, midx):
+        """activate watch on specified Method"""
+        _c.setDefmethodWatch(True, midx, self.__defgeneric)
+
+    def UnwatchMethod(self, midx):
+        """deactivate watch on specified Method"""
+        _c.setDefmethodWatch(False, midx, self.__defgeneric)
+
+    def MethodWatched(self, midx):
+        """test whether or not specified Method is being watched"""
+        return bool(_c.getDefmethodWatch(midx, self.__defgeneric))
+
+    def MethodDeletable(self, midx):
+        """test whether or not specified Method can be deleted"""
+        return bool(_c.isDefmethodDeletable(midx, self.__defgeneric))
+#}}
+
+
+
+# ========================================================================== #
+# High-level class for defclass objects
+# Treat a defclass as an object having an Object-Oriented interface.
+#  Implements all the functions needed to access defclass objects.
+#{{CLASS
+class Class(object):
+    """high-level Class class (represents: defclass)"""
+
+    def __init__(self, o):
+        """create a Class object (internal)"""
+        if _c.isDefclass(o):
+            self.__defclass = o
+        else:
+            raise _c.ClipsError("M01: cannot directly create Class")
+        # define a class to group slots information
+        #  NOTE: there is a hack that allows the environment version to work
+        #        by trying to access the underlying environment object
+        class __class_Slots:
+            """define a structure for Class Slots"""
+            def __init__(self, o):
+                self.__defclass = o
+
+            def __getstate__(self):
+                raise _c.ClipsError("M03: cannot pickle class slots")
+
+            def Names(self):
+                """return the list of Slot names"""
+                rv = _cl2py(_c.classSlots(self.__defclass, 1))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            def NamesDefined(self):
+                """return the list of Slot names"""
+                rv = _cl2py(_c.classSlots(self.__defclass, 0))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def AllowedValues(self, name):
+                """return allowed values for specified Slot"""
+                rv = _cl2py(_c.slotAllowedValues(self.__defclass, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def AllowedClasses(self, name):
+                """return allowed classes for specified Slot"""
+                rv = _cl2py(_c.slotAllowedClasses(self.__defclass, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def Cardinality(self, name):
+                """return cardinality for specified Slot"""
+                rv = _cl2py(_c.slotCardinality(self.__defclass, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def DefaultValue(self, name):
+                """return default value for specified Slot"""
+                rv = _cl2py(_c.slotDefaultValue(self.__defclass, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def Facets(self, name):
+                """return facet values for specified Slot"""
+                rv = _cl2py(_c.slotFacets(self.__defclass, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def Range(self, name):
+                """return numeric range information of specified Slot"""
+                rv = _cl2py(_c.slotRange(self.__defclass, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def Sources(self, name):
+                """return source class names for specified Slot"""
+                rv = _cl2py(_c.slotSources(self.__defclass, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def Types(self, name):
+                """return names of primitive types for specified Slot"""
+                rv = _cl2py(_c.slotTypes(self.__defclass, name))
+                if type(rv) in (tuple, list):
+                    return Multifield(rv)
+                else:
+                    return rv
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def HasDirectAccess(self, name):
+                """return True if specified Slot is directly accessible"""
+                return bool(_c.slotDirectAccessP(self.__defclass, name))
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def Exists(self, name):
+                """return True if specified Slot exists or is inherited"""
+                return bool(_c.slotExistP(self.__defclass, name, 1))
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def ExistsDefined(self, name):
+                """return True if specified Slot is defined in this Class"""
+                return bool(_c.slotExistP(self.__defclass, name, 0))
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def IsInitable(self, name):
+                """return True if specified Slot is initable"""
+                return bool(_c.slotInitableP(self.__defclass, name))
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def IsPublic(self, name):
+                """return True if specified Slot is public"""
+                return bool(_c.slotPublicP(self.__defclass, name))
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def IsWritable(self, name):
+                """return True if specified Slot is writable"""
+                return bool(_c.slotWritableP(self.__defclass, name))
+
+        self.__Slots = __class_Slots(self.__defclass)
+        # the following try/except blocks are to enable companion versions
+        try:
+            self.__Slots._class_Slots__env = self.__env
+        except AttributeError: pass
+        try:
+            self.__Slots._class_Slots__envobject = self.__envobject
+        except AttributeError: pass
+
+    def __str__(self):
+        """string form of Class"""
+        return _c.getDefclassName(self.__defclass)
+
+    def __repr__(self):
+        """representation of Class"""
+        s = repr(self.__defclass)[1:-1]
+        return "<Class '%s': %s>" % (
+            _c.getDefclassName(self.__defclass), s)
+
+    def __getstate__(self):
+        raise _c.ClipsError("M03: cannot pickle objects of type '%s'"
+            % self.__class__.__name__)
+
+    # Interface
+    def Next(self):
+        """return next Class"""
+        o = _c.getNextDefclass(self.__defclass)
+        if o:
+            return Class(o)
+        else:
+            return None
+
+    def PPForm(self):
+        """return the pretty-print form of Class"""
+        return _c.getDefclassPPForm(self.__defclass)
+
+    def Description(self):
+        """return a summary of Class description"""
+        _c.routerClear("temporary")
+        _c.describeClass("temporary", self.__defclass)
+        return _c.routerRead("temporary").strip()
+
+    def IsSubclassOf(self, o):
+        """test whether this Class is a subclass of specified Class"""
+        return bool(_c.subclassP(self.__defclass, o.__defclass))
+
+    def IsSuperclassOf(self, o):
+        """test whether this Class is a superclass of specified Class"""
+        return bool(_c.superclassP(self.__defclass, o.__defclass))
+
+    def Subclasses(self, inherit=True):
+        """return the names of subclasses"""
+        return Multifield(
+            _cl2py(_c.classSubclasses(self.__defclass, inherit)))
+
+    def Superclasses(self, inherit=True):
+        """return the names of superclasses"""
+        return Multifield(
+            _cl2py(_c.classSuperclasses(self.__defclass, inherit)))
+
+    @_accepts_method((str, unicode))
+    @_forces_method(str)
+    def RawInstance(self, name):
+        """create an empty Instance of this Class with specified name"""
+        return Instance(_c.createRawInstance(self.__defclass, name))
+
+    def InitialInstance(self):
+        """return initial Instance of this Class"""
+        try:
+            return Instance(_c.getNextInstanceInClass(self.__defclass))
+        except:
+            raise _c.ClipsError("M02: could not find any Instance")
+
+    def NextInstance(self, instance):
+        """return next Instance of this Class"""
+        i = _c.getNextInstanceInClass(
+            self.__defclass, instance._Instance__instance)
+        if _c.isInstance(i):
+            return Instance(i)
+        else:
+            return None
+
+    def InitialSubclassInstance(self):
+        """return initial instance of this Class and subclasses"""
+        try:
+            return Instance(_c.getNextInstanceInClassAndSubclasses(
+                self.__defclass))
+        except:
+            raise _c.ClipsError("M02: could not find any Instance")
+
+    def NextSubclassInstance(self, instance):
+        """return next instance of this Class and subclasses"""
+        i = _c.getNextInstanceInClassAndSubclasses(
+            self.__defclass, instance._Instance__instance)
+        if _c.isInstance(i):
+            return Instance(i)
+        else:
+            return None
+
+    def Remove(self):
+        """remove this Class"""
+        _c.undefclass(self.__defclass)
+
+    @_accepts_method((str, unicode), (str, unicode), None)
+    @_forces_method(str, str, None)
+    def BuildSubclass(self, name, text="", comment=None):
+        """build a subclass of this Class with specified name and body"""
+        if comment:
+            cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+        else:
+            cmtstr = ""
+        clname = _c.getDefclassName(self.__defclass)
+        cltext = "(is-a %s)" % clname + text
+        construct = "(defclass %s %s %s)" % (name, cmtstr, cltext)
+        _c.build(construct)
+        return Class(_c.findDefclass(name))
+
+    @_accepts_method((str, unicode), (str, unicode))
+    @_forces_method(str, str)
+    def BuildInstance(self, name, overrides=""):
+        """build an instance of this class overriding specified slots"""
+        clname = _c.getDefclassName(self.__defclass)
+        cmdstr = "(%s of %s %s)" % (name, clname, overrides)
+        return Instance(_c.makeInstance(cmdstr))
+
+    def __property_getName(self):
+        return Symbol(_c.getDefclassName(self.__defclass))
+    Name = property(__property_getName, None, None, "retrieve Class name")
+
+    def __property_getModule(self):
+        return Symbol(_c.defclassModule(self.__defclass))
+    Module = property(__property_getModule, None, None,
+                      "retrieve Class Module name")
+
+    def __property_getDeletable(self):
+        return bool(_c.isDefclassDeletable(self.__defclass))
+    Deletable = property(__property_getDeletable, None, None,
+                         "verify if this Class can be deleted")
+
+    def __property_getAbstract(self):
+        return bool(_c.classAbstractP(self.__defclass))
+    Abstract = property(__property_getAbstract, None, None,
+                        "verify if this Class is abstract or not")
+
+    def __property_getReactive(self):
+        return bool(_c.classReactiveP(self.__defclass))
+    Reactive = property(__property_getReactive, None, None,
+                        "verify if this Class is reactive or not")
+
+    def __property_setWatchSlots(self, v):
+        _c.setDefclassWatchSlots(v, self.__defclass)
+    def __property_getWatchSlots(self):
+        return bool(_c.getDefclassWatchSlots(self.__defclass))
+    WatchSlots = property(__property_getWatchSlots, __property_setWatchSlots,
+                          None, "set/retrieve Slot debug status")
+
+    def __property_setWatchInstances(self, v):
+        _c.setDefclassWatchInstances(v, self.__defclass)
+    def __property_getWatchInstances(self):
+        return bool(_c.getDefclassWatchInstances(self.__defclass))
+    WatchInstances = property(__property_getWatchInstances,
+                              __property_setWatchInstances,
+                              None, "set/retrieve Instance debug status")
+
+    # access class slots through the internal object
+    def __property_getSlots(self): return self.__Slots
+    Slots = property(__property_getSlots, None, None,
+                     "Class Slots information")
+
+    # message-handler functions
+    @_accepts_method((str, unicode), (str, unicode), (str, unicode), None, None)
+    @_forces_method(str, str, str, None, None)
+    def AddMessageHandler(self, name, args, text, htype=PRIMARY, comment=None):
+        """build a MessageHandler for this class with arguments and body"""
+        if comment:
+            cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+        else:
+            cmtstr = ""
+        htype = htype.lower()
+        if not htype in (AROUND, BEFORE, PRIMARY, AFTER):
+            raise ValueError("htype must be AROUND, BEFORE, PRIMARY or AFTER")
+        if type(args) in (tuple, list):
+            sargs = " ".join(args)
+        elif args is None:
+            sargs = ""
+        else:
+            sargs = str(args)
+        hclass = _c.getDefclassName(self.__defclass)
+        construct = "(defmessage-handler %s %s %s %s (%s) %s)" % (
+            hclass, name, htype, cmtstr, sargs, text)
+        _c.build(construct)
+        return _c.findDefmessageHandler(self.__defclass, name, htype)
+
+    @_accepts_method((str, unicode), None)
+    @_forces_method(str, None)
+    def MessageHandlerIndex(self, name, htype=PRIMARY):
+        """find the specified MessageHandler"""
+        htype = htype.lower()
+        if htype in (AROUND, BEFORE, PRIMARY, AFTER):
+            return _c.findDefmessageHandler(self.__defclass, name, htype)
+        else:
+            raise ValueError(
+                "htype must be in AROUND, BEFORE, PRIMARY, AFTER")
+
+    def MessageHandlerName(self, index):
+        """return name of specified MessageHandler"""
+        return Symbol(_c.getDefmessageHandlerName(self.__defclass, index))
+
+    def MessageHandlerPPForm(self, index):
+        """return the pretty-print form of specified MessageHandler"""
+        return _c.getDefmessageHandlerPPForm(self.__defclass, index)
+
+    def MessageHandlerType(self, index):
+        """return type of specified MessageHandler"""
+        return _c.getDefmessageHandlerType(self.__defclass, index)
+
+    def MessageHandlerWatched(self, index):
+        """return watch status of specified MessageHandler"""
+        return bool(_c.getDefmessageHandlerWatch(self.__defclass, index))
+
+    def MessageHandlerDeletable(self, index):
+        """return True if specified MessageHandler can be deleted"""
+        return bool(_c.isDefmessageHandlerDeletable(self.__defclass, index))
+
+    def NextMessageHandlerIndex(self, index):
+        """return index of next MessageHandler wrt. specified"""
+        return _c.getNextDefmessageHandler(self.__defclass, index)
+
+    def RemoveMessageHandler(self, index):
+        """remove the specified MessageHandler"""
+        return _c.undefmessageHandler(self.__defclass, index)
+
+    def WatchMessageHandler(self, index):
+        """watch specified MessageHandler"""
+        return _c.setDefmessageHandlerWatch(True, self.__defclass, index)
+
+    def UnwatchMessageHandler(self, index):
+        """unwatch specified MessageHandler"""
+        return _c.setDefmessageHandlerWatch(False, self.__defclass, index)
+
+    def MessageHandlerList(self):
+        """return list of MessageHandler constructs of this Class"""
+        o = _c.getDefmessageHandlerList(self.__defclass, False)
+        li, rv = Multifield(_cl2py(o)), []
+        l = len(li) / 3
+        for x in range(0, l):
+            rv.append(Multifield([li[x * 3], li[x * 3 + 1], li[x * 3 + 2]]))
+        return Multifield(rv)
+
+    def AllMessageHandlerList(self):
+        """return list of MessageHandlers of this Class and superclasses"""
+        o = _c.getDefmessageHandlerList(self.__defclass, True)
+        li, rv = Multifield(_cl2py(o)), []
+        l = len(li) / 3
+        for x in range(0, l):
+            rv.append(Multifield([li[x * 3], li[x * 3 + 1], li[x * 3 + 2]]))
+        return Multifield(rv)
+
+    def PrintMessageHandlers(self):
+        """print list of all MessageHandlers of this Class"""
+        _c.routerClear("temporary")
+        _c.listDefmessageHandlers("temporary", self.__defclass)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    def PrintAllMessageHandlers(self):
+        """print list of MessageHandlers of this Class and superclasses"""
+        _c.routerClear("temporary")
+        _c.listDefmessageHandlers("temporary", self.__defclass, 1)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    @_accepts_method((str, unicode))
+    @_forces_method(str)
+    def PreviewSend(self, msgname):
+        """print list of MessageHandlers suitable for specified message"""
+        _c.routerClear("temporary")
+        _c.previewSend("temporary", self.__defclass, msgname)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+#}}
+
+
+
+# ========================================================================== #
+# High-level class for instance objects
+# Treat an instance as an object having an Object-Oriented interface.
+#  Implements all the functions needed to access instance objects.
+#{{CLASS
+class Instance(object):
+    """high-level Instance class (represents: instance)"""
+
+    def __init__(self, o):
+        """create an Instance object (internal)"""
+        # this on-the-fly class takes the underlying instance object, which
+        #  should already exist, and accesses its slots through the functions
+        #  provided by the low-level module, thus exposing a dictionary-like
+        #  interface that can be used to access slots at high level
+        #  NOTE: there is a hack that allows the environment version to work
+        #        by trying to access the underlying environment object
+        class __instance_Slots:
+            """access instance Slots"""
+            def __init__(self, io):
+                self.__instance = io
+
+            @_accepts_method((str, unicode), None)
+            @_forces_method(str, None)
+            def __setitem__(self, name, v):
+                _c.directPutSlot(self.__instance, name, _py2cl(v))
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def __getitem__(self, name):
+                return _cl2py(_c.directGetSlot(self.__instance, name))
+
+            def keys(self):
+                return map(
+                    str, list(Instance(self.__instance).Class.Slots.Names()))
+
+            @_accepts_method((str, unicode))
+            @_forces_method(str)
+            def has_key(self, k):
+                return bool(
+                    k in map(str, list(
+                        Instance(self.__instance).Class.Slots.Names())))
+
+            def __repr__(self):
+                return "<Instance [%s] Slots>" \
+                       % _c.getInstanceName(self.__instance)
+
+            def __getstate__(self):
+                raise _c.ClipsError("M03: cannot pickle instance slots")
+        if _c.isInstance(o): self.__instance = o
+        else:
+            raise _c.ClipsError("M01: cannot directly create Instance")
+        self.__Slots = __instance_Slots(self.__instance)
+        # the following try/except blocks are to enable companion versions
+        try:
+            self.__Slots._instance_Slots__env = self.__env
+        except AttributeError: pass
+        try:
+            self.__Slots._instance_Slots__envobject = self.__envobject
+        except AttributeError: pass
+
+    def __str__(self):
+        """string form of Instance"""
+        return _c.getInstanceName(self.__instance)
+
+    def __repr__(self):
+        """representation of Instance"""
+        s = repr(self.__instance)[1:-1]
+        return "<Instance [%s]: %s>" % (
+            _c.getInstanceName(self.__instance), s)
+
+    def __getstate__(self):
+        raise _c.ClipsError("M03: cannot pickle objects of type '%s'"
+            % self.__class__.__name__)
+
+    # Interface
+    def Next(self):
+        """return next Instance"""
+        o = _c.getNextInstance(self.__instance)
+        if o:
+            return Instance(o)
+        else:
+            return None
+
+    def PPForm(self):
+        """return the pretty-print form of Instance"""
+        return _c.getInstancePPForm(self.__instance)
+
+    def IsValid(self):
+        """determine if this Instance is still valid"""
+        return bool(_c.validInstanceAddress(self.__instance))
+
+    def Remove(self):
+        """remove this Instance"""
+        _c.unmakeInstance(self.__instance)
+
+    def DirectRemove(self):
+        """directly remove this Instance"""
+        _c.deleteInstance(self.__instance)
+
+    @_accepts_method((str, unicode))
+    @_forces_method(str)
+    def GetSlot(self, slotname):
+        """retrieve value of specified Slot"""
+        return _cl2py(_c.directGetSlot(self.__instance, slotname))
+    SlotValue = GetSlot
+
+    @_accepts_method((str, unicode), None)
+    @_forces_method(str, None)
+    def PutSlot(self, slotname, value):
+        """set value of specified Slot"""
+        _c.directPutSlot(self.__instance, slotname, _py2cl(value))
+    SetSlotValue = PutSlot
+
+    @_accepts_method((str, unicode), None)
+    @_forces_method(str, None)
+    def Send(self, msg, args=None):
+        """send specified message with the given arguments to Instance"""
+        if args is not None:
+            t = type(args)
+            if t == str:
+                sargs = args
+            elif t == unicode:
+                sargs = str(args)
+            elif isinstance(args, str):
+                sargs = str(args)
+            elif isinstance(args, unicode):
+                sargs = str(args)
+            elif t in (ClipsIntegerType, ClipsFloatType, ClipsStringType,
+                       ClipsSymbolType, ClipsNilType, ClipsInstanceNameType,
+                       ClipsMultifieldType):
+                sargs = _py2clsyntax(args)
+            elif t in (tuple, list):
+                li = []
+                for x in args:
+                    t1 = type(x)
+                    if t1 in (ClipsIntegerType, ClipsFloatType,
+                              ClipsStringType, ClipsSymbolType, ClipsNilType,
+                              ClipsInstanceNameType, ClipsMultifieldType):
+                        li.append(_py2clsyntax(x))
+                    elif t1 in (int, long):
+                        li.append(Integer(int(x)).clsyntax())
+                    elif t1 == float:
+                        li.append(Float(x).clsyntax())
+                    elif t1 in (str, unicode):
+                        li.append(String(x).clsyntax())
+                    elif isinstance(x, int):
+                        li.append(Integer(x).clsyntax())
+                    elif isinstance(x, long):
+                        li.append(Integer(x).clsyntax())
+                    elif isinstance(x, float):
+                        li.append(Float(x).clsyntax())
+                    elif isinstance(x, str):
+                        li.append(String(x).clsyntax())
+                    elif isinstance(x, unicode):
+                        li.append(String(x).clsyntax())
+                    else:
+                        li.append(str(x))
+                sargs = " ".join(li)
+            elif t in (int, long):
+                sargs = Integer(args).clsyntax()
+            elif t == float:
+                sargs = Float(args).clsyntax()
+            elif isinstance(args, str):
+                sargs = str(args)
+            elif isinstance(args, unicode):
+                sargs = str(args)
+            elif isinstance(args, int):
+                sargs = Integer(args).clsyntax()
+            elif isinstance(args, long):
+                sargs = Integer(args).clsyntax()
+            elif isinstance(args, float):
+                sargs = Float(args).clsyntax()
+            else:
+                sargs = str(args)
+            return _cl2py(_c.send(self.__instance, msg, sargs))
+        else:
+            return _cl2py(_c.send(self.__instance, msg))
+
+    def __property_getName(self):
+        return InstanceName(_c.getInstanceName(self.__instance))
+    Name = property(__property_getName, None, None, "retrieve Instance name")
+
+    def __property_getClass(self):
+        return Class(_c.getInstanceClass(self.__instance))
+    Class = property(__property_getClass, None, None,
+                     "retrieve Instance class")
+
+    # access instance slots through the internal object
+    def __property_getSlots(self): return self.__Slots
+    Slots = property(__property_getSlots, None, None,
+                     "Instance Slots information")
+#}}
+
+
+
+# ========================================================================== #
+# High-level class for definstances objects
+# Treat definstances as an object having an Object-Oriented interface.
+#  Implements all the functions needed to access definstances objects.
+#{{CLASS
+class Definstances(object):
+    """high-level Definstances class (represents: definstances)"""
+
+    def __init__(self, o):
+        """create a Definstances object (internal)"""
+        if _c.isDefinstances(o): self.__definstances = o
+        else: raise _c.ClipsError("M01: cannot directly create Definstances")
+
+    def __str__(self):
+        """string form of Definstances"""
+        return _c.getDefinstancesName(self.__definstances)
+
+    def __repr__(self):
+        """representation of Definstances"""
+        s = repr(self.__definstances)[1:-1]
+        return "<Definstances '%s': %s>" % (
+            _c.getDefinstancesName(self.__definstances), s)
+
+    def __getstate__(self):
+        raise _c.ClipsError("M03: cannot pickle objects of type '%s'"
+            % self.__class__.__name__)
+
+    # Interface
+    def Next(self):
+        """return next Definstances"""
+        o = _c.getNextDefinstances(self.__definstances)
+        if o:
+            return Definstances(o)
+        else:
+            return None
+
+    def PPForm(self):
+        """return the pretty-print form of Definstances"""
+        return _c.getDefinstancesPPForm(self.__definstances)
+
+    def Remove(self):
+        """delete this Definstances object"""
+        _c.undefinstances(self.__definstances)
+
+    def __property_getModule(self):
+        return Symbol(_c.definstancesModule(self.__definstances))
+    Module = property(__property_getModule, None, None,
+                      "retrieve Definstances module")
+
+    def __property_getName(self):
+        return Symbol(_c.getDefinstancesName(self.__definstances))
+    Name = property(__property_getName, None, None,
+                    "retrieve Definstances name")
+
+    def __property_getDeletable(self):
+        return bool(_c.isDefinstancesDeletable(self.__definstances))
+    Deletable = property(__property_getDeletable, None, None,
+                         "verify if this Definstances can be deleted")
+#}}
+
+
+
+# ========================================================================== #
+# High-level class for defmodule objects
+# Treat a defmodule as an object having an Object-Oriented interface.
+#  Implements all the functions needed to access defmodule objects.
+#{{CLASS
+class Module(object):
+    """high-level Module class (represents: defmodule)"""
+
+    def __init__(self, o):
+        """create a Module object (internal)"""
+        if _c.isDefmodule(o):
+            self.__defmodule = o
+        else: raise _c.ClipsError("M01: cannot directly create Module")
+
+    def __str__(self):
+        """string form of Module"""
+        return _c.getDefmoduleName(self.__defmodule)
+
+    def __repr__(self):
+        """representation of Module"""
+        s = repr(self.__defmodule)[1:-1]
+        return "<Module '%s': %s>" % (
+            _c.getDefmoduleName(self.__defmodule), s)
+
+    def __getstate__(self):
+        raise _c.ClipsError("M03: cannot pickle objects of type '%s'"
+              % self.__class__.__name__)
+
+    # Interface
+    def Next(self):
+        """return next Module"""
+        o = _c.getNextDefmodule(self.__defmodule)
+        if(o):
+            return Module(o)
+        else:
+            return None
+
+    def PPForm(self):
+        """return the pretty-print form of Module"""
+        return _c.getDefmodulePPForm(self.__defmodule)
+
+    def SetCurrent(self):
+        """make this the current Module"""
+        _c.setCurrentModule(self.__defmodule)
+
+    def SetFocus(self):
+        """set focus to this Module"""
+        _c.focus(self.__defmodule)
+
+    def __property_getName(self):
+        return Symbol(_c.getDefmoduleName(self.__defmodule))
+    Name = property(__property_getName, None, None, "return Module name")
+
+    # Functions involving other entities
+
+    # Templates
+    @_accepts_method((str, unicode), (str, unicode), None)
+    @_forces_method(str, str, None)
+    def BuildTemplate(self, name, text, comment=None):
+        """build a Template object with specified name and body"""
+        if comment:
+            cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+        else:
+            cmtstr = ""
+        mname = self.Name
+        construct = "(deftemplate %s::%s %s %s)" % (mname, name, cmtstr, text)
+        _c.build(construct)
+        return Template(_c.findDeftemplate("%s::%s" % (mname, name)))
+
+    def TemplateList(self):
+        """return list of Template names"""
+        o = _c.getDeftemplateList(self.__defmodule)
+        return Multifield(_cl2py(o))
+
+    def PrintTemplates(self):
+        """print Templates to standard output"""
+        _c.routerClear("temporary")
+        _c.listDeftemplates("temporary", self.__defmodule)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    # Facts
+    def FactList(self):
+        """return list of Facts in this Module"""
+        o, li = _c.getFactList(self.__defmodule), []
+        if o is not None:
+            for x in o[1]:
+                if x[0] == _c.FACT_ADDRESS:
+                    li.append(Fact(x[1]))
+        return li
+
+    # Deffacts
+    @_accepts_method((str, unicode), (str, unicode), None)
+    @_forces_method(str, str, None)
+    def BuildDeffacts(self, name, text, comment=None):
+        """build a Deffacts object with specified name and body"""
+        if comment:
+            cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+        else:
+            cmtstr = ""
+        mname = self.Name
+        construct = "(deffacts %s::%s %s %s)" % (mname, name, cmtstr, text)
+        _c.build(construct)
+        return Deffacts(_c.findDeffacts("%s::%s" % (mname, name)))
+
+    def DeffactsList(self):
+        """return a list of Deffacts names in this Module"""
+        o = _c.getDeffactsList(self.__defmodule)
+        return Multifield(_cl2py(o))
+
+    def PrintDeffacts(self):
+        """print Deffacts to standard output"""
+        _c.routerClear("temporary")
+        _c.listDeffacts("temporary", self.__defmodule)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    # Rules
+    @_accepts_method((str, unicode), (str, unicode), (str, unicode), None)
+    @_forces_method(str, str, str, None)
+    def BuildRule(self, name, lhs, rhs, comment=None):
+        """build a Rule object with specified name and LHS/RHS"""
+        if comment:
+            cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+        else:
+            cmtstr = ""
+        mname = self.Name
+        construct = "(defrule %s::%s %s %s => %s)" % (
+            mname, name, cmtstr, lhs, rhs)
+        _c.build(construct)
+        return Rule(_c.findDefrule("%s::%s" % (mname, name)))
+
+    def RuleList(self):
+        """return a list of Rule names in this Module"""
+        o = _c.getDefruleList(self.__defmodule)
+        return Multifield(_cl2py(o))
+
+    def PrintRules(self):
+        """print Rules to standard output"""
+        _c.routerClear("temporary")
+        _c.listDefrules("temporary", self.__defmodule)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    def PrintBreakpoints(self):
+        """print breakpoints to standard output"""
+        _c.routerClear("temporary")
+        _c.showBreaks("temporary", self.__defmodule)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    # Agenda
+    def PrintAgenda(self):
+        """print Agenda Rules to standard output"""
+        _c.routerClear("temporary")
+        _c.agenda("temporary")
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    def RefreshAgenda(self):
+        """refresh Agenda for this Module"""
+        _c.refreshAgenda(self.__defmodule)
+
+    def ReorderAgenda(self):
+        """reorder Agenda for this Module"""
+        _c.reorderAgenda(self.__defmodule)
+
+    # Globals
+    @_accepts_method((str, unicode), None)
+    @_forces_method(str, None)
+    def BuildGlobal(self, name, value=Nil):
+        """build a Global variable with specified name and value"""
+        mname = self.Name
+        if type(value)  in (str, ClipsStringType):
+            value = '"%s"' % value
+        construct = "(defglobal %s ?*%s* = %s)" % (mname, name, value)
+        _c.build(construct)
+        return Global(_c.findDefglobal("%s::%s" % (mname, name)))
+
+    def GlobalList(self):
+        """return the list of Global variable names"""
+        o = _c.getDefglobalList(self.__defmodule)
+        return Multifield(_cl2py(o))
+
+    def PrintGlobals(self):
+        """print list of Global variables to standard output"""
+        _c.routerClear("temporary")
+        _c.listDefglobals("temporary", self.__defmodule)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    def ShowGlobals(self):
+        """print list of Global variables and values to standard output"""
+        _c.routerClear("temporary")
+        _c.showDefglobals("temporary", self.__defmodule)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    # Functions
+    @_accepts_method((str, unicode), None, (str, unicode), None)
+    @_forces_method(str, None, str, None)
+    def BuildFunction(self, name, args, text, comment=None):
+        """build a Function with specified name, body and arguments"""
+        if comment:
+            cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+        else:
+            cmtstr = ""
+        mname = self.Name
+        if type(args) in (tuple, list):
+            args = " ".join(args)
+        elif args is None:
+            args = ""
+        construct = "(deffunction %s::%s %s (%s) %s)" % (
+            mname, name, cmtstr, args, text)
+        _c.build(construct)
+        return Function(_c.findDeffunction("%s::%s" % (mname, name)))
+
+    def FunctionList(self):
+        """return the list of Function names"""
+        o = _c.getDeffunctionList(self.__defmodule)
+        return Multifield(_cl2py(o))
+
+    def PrintFunctions(self):
+        """print list of Functions to standard output"""
+        _c.routerClear("temporary")
+        _c.listDeffunctions("temporary", self.__defmodule)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    # Generics
+    @_accepts_method((str, unicode), None)
+    @_forces_method(str, None)
+    def BuildGeneric(self, name, comment=None):
+        """build a Generic with specified name"""
+        if comment:
+            cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+        else:
+            cmtstr = ""
+        mname = self.Name
+        construct = "(defgeneric %s::%s %s)" % (mname, name, cmtstr)
+        _c.build(construct)
+        return Generic(_c.findDefgeneric("%s::%s" % (mname, name)))
+
+    def GenericList(self):
+        """return the list of Generic names"""
+        o = _c.getDefgenericList(self.__defmodule)
+        return Multifield(_cl2py(o))
+
+    def PrintGenerics(self):
+        """print list of Generics to standard output"""
+        _c.routerClear("temporary")
+        _c.listDefgenerics("temporary", self.__defmodule)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    # Classes
+    @_accepts_method((str, unicode), (str, unicode), None)
+    @_forces_method(str, str, None)
+    def BuildClass(self, name, text, comment=None):
+        """build a Class with specified name and body"""
+        if comment:
+            cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+        else:
+            cmtstr = ""
+        mname = self.Name
+        construct = "(defclass %s::%s %s %s)" % (mname, name, cmtstr, text)
+        _c.build(construct)
+        return Class(_c.findDefclass("%s::%s" % (mname, name)))
+
+    def ClassList(self):
+        """return the list of Class names"""
+        o = _c.getDefclassList(self.__defmodule)
+        return Multifield(_cl2py(o))
+
+    def PrintClasses(self):
+        """print list of Class to standard output"""
+        _c.routerClear("temporary")
+        _c.listDefclasses("temporary", self.__defmodule)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    # Instances
+    @_accepts_method((str, unicode), None, None)
+    @_forces_method(str, str, None)
+    def BuildInstance(self, name, defclass, overrides=""):
+        """build an Instance of given Class overriding specified Slots"""
+        mname = self.Name
+        cmdstr = "(%s::%s of %s %s)" % (mname, name, defclass, overrides)
+        return Instance(_c.makeInstance(cmdstr))
+
+    @_forces_method(str)
+    def PrintInstances(self, classname=None):
+        """print Instances to standard output"""
+        _c.routerClear("temporary")
+        if classname:
+            _c.instances("temporary", self.__defmodule, classname, False)
+        else:
+            _c.instances("temporary", self.__defmodule)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    @_forces_method(str)
+    def PrintSubclassInstances(self, classname):
+        """print Instances to standard output"""
+        _c.routerClear("temporary")
+        _c.instances("temporary", self.__defmodule, classname, True)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+
+    # Definstances
+    @_accepts_method((str, unicode), (str, unicode), None)
+    @_forces_method(str, str, None)
+    def BuildDefinstances(self, name, text, comment=None):
+        """build a Definstances with specified name and body"""
+        if comment:
+            cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+        else:
+            cmtstr = ""
+        mname = self.Name
+        construct = "(definstances %s::%s %s %s)" % (
+            mname, name, cmtstr, text)
+        _c.build(construct)
+        return Definstances(_c.findDefinstances(name))
+
+    def DefinstancesList(self):
+        """retrieve list of all Definstances names"""
+        o = _c.getDefinstancesList(self.__defmodule)
+        return Multifield(_cl2py(o))
+
+    def PrintDefinstances(self):
+        """print list of all Definstances to standard output"""
+        _c.routerClear("temporary")
+        _c.listDefinstances("temporary", self.__defmodule)
+        s = _c.routerRead("temporary")
+        if s:
+            _sys.stdout.write(s)
+#}}
+
+
+
+# ========================================================================== #
+# some toplevel functions
+# ========================================================================== #
+
+
+# ========================================================================== #
+# 1) functions involving Templates
+
+#{{FUNCTION
+def InitialTemplate():
+    """return first Template in environment"""
+    try:
+        return Template(_c.getNextDeftemplate())
+    except:
+        raise _c.ClipsError("M02: could not find any Template")
+#}}
+
+#{{FUNCTION
+def PrintTemplates():
+    """print Templates to standard output"""
+    _c.routerClear("temporary")
+    _c.listDeftemplates("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+#{{FUNCTION
+def TemplateList():
+    """return a list of Template names"""
+    o = _c.getDeftemplateList()
+    return Multifield(_cl2py(o))    # should be all strings
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def FindTemplate(s):
+    """find a Template by name"""
+    return Template(_c.findDeftemplate(s))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), (str, unicode), None)
+ at _forces(str, str, None)
+def BuildTemplate(name, text, comment=None):
+    """build a Template object with specified name and body"""
+    if comment:
+        cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+    else:
+        cmtstr = ""
+    construct = "(deftemplate %s %s %s)" % (name, cmtstr, text)
+    _c.build(construct)
+    return Template(_c.findDeftemplate(name))
+#}}
+
+
+
+# ========================================================================== #
+# 2) functions involving facts
+
+#{{FUNCTION
+def Assert(o):
+    """assert a Fact from a string or constructed Fact object"""
+    if '_Fact__fact' in dir(o) and _c.isFact(o._Fact__fact):
+        return o.Assert()
+    elif type(o) in (str, unicode):
+        return Fact(_c.assertString(str(o)))
+    else:
+        raise TypeError("expected a string or a Fact")
+#}}
+
+#{{FUNCTION
+def InitialFact():
+    """return first Fact in environment"""
+    try:
+        return Fact(_c.getNextFact())
+    except:
+        raise _c.ClipsError("M02: could not find any Fact")
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def LoadFacts(filename):
+    """load Facts from file"""
+    _c.loadFacts(_os.path.normpath(filename))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def LoadFactsFromString(s):
+    """load Fact objects from a string"""
+    _c.loadFactsFromString(s)
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), (str, unicode))
+ at _forces(str, str)
+def SaveFacts(filename, mode=LOCAL_SAVE):
+    """save current Facts to file"""
+    _c.saveFacts(_os.path.normpath(filename), mode)
+#}}
+
+#{{FUNCTION
+def PrintFacts():
+    """print Facts to standard output"""
+    _c.routerClear("temporary")
+    _c.facts("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+#{{FUNCTION
+def FactListChanged():
+    """test whether Fact list is changed since last call"""
+    rv = bool(_c.getFactListChanged())
+    _c.setFactListChanged(False)
+    return rv
+#}}
+
+#{{FUNCTION
+def FactList():
+    """return list of Facts in current module"""
+    o, li = _c.getFactList(), []
+    if o is not None:
+        for x in o[1]:
+            if x[0] == _c.FACT_ADDRESS:
+                li.append(Fact(x[1]))
+    return li
+#}}
+
+
+
+# ========================================================================== #
+# 3) functions involving deffacts
+
+#{{FUNCTION
+def InitialDeffacts():
+    """return first Deffacts"""
+    try:
+        return Deffacts(_c.getNextDeffacts())
+    except:
+        raise _c.ClipsError("M02: could not find any Deffacts")
+#}}
+
+#{{FUNCTION
+def DeffactsList():
+    """return a list of Deffacts names in current module"""
+    o = _c.getDeffactsList()
+    return Multifield(_cl2py(o))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def FindDeffacts(s):
+    """find a Deffacts by name"""
+    try:
+        return Deffacts(_c.findDeffacts(s))
+    except:
+        raise _c.ClipsError("M02: could not find Deffacts '%s'" % s)
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), (str, unicode), None)
+ at _forces(str, str, None)
+def BuildDeffacts(name, text, comment=None):
+    """build a Deffacts object with specified name and body"""
+    if comment:
+        cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+    else:
+        cmtstr = ""
+    construct = "(deffacts %s %s %s)" % (name, cmtstr, text)
+    _c.build(construct)
+    return Deffacts(_c.findDeffacts(name))
+#}}
+
+#{{FUNCTION
+def PrintDeffacts():
+    """print Deffacts to standard output"""
+    _c.routerClear("temporary")
+    _c.listDeffacts("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+
+
+# ========================================================================== #
+# 4) functions involving Rules
+
+#{{FUNCTION
+def InitialRule():
+    """return first Rule"""
+    try:
+        return Rule(_c.getNextDefrule())
+    except:
+        raise _c.ClipsError("M02: could not find any Rule")
+#}}
+
+#{{FUNCTION
+def RuleList():
+    """return a list of Rule names in current module"""
+    o = _c.getDefruleList()
+    return Multifield(_cl2py(o))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def FindRule(s):
+    """find a Rule by name"""
+    try:
+        return Rule(_c.findDefrule(s))
+    except:
+        raise _c.ClipsError("M02: could not find defrule '%s'" % s)
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), (str, unicode), (str, unicode), None)
+ at _forces(str, str, str, None)
+def BuildRule(name, lhs, rhs, comment=None):
+    """build a Rule object with specified name and body"""
+    if comment:
+        cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+    else:
+        cmtstr = ""
+    construct = "(defrule %s %s %s => %s)" % (name, cmtstr, lhs, rhs)
+    _c.build(construct)
+    return Rule(_c.findDefrule(name))
+#}}
+
+#{{FUNCTION
+def PrintRules():
+    """print Rules to standard output"""
+    _c.routerClear("temporary")
+    _c.listDefrules("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+#{{FUNCTION
+def PrintBreakpoints():
+    """print breakpoints to standard output"""
+    _c.routerClear("temporary")
+    _c.showBreaks("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+
+
+# ========================================================================== #
+# 5) functions involving Modules
+
+#{{FUNCTION
+def InitialModule():
+    """return first Module"""
+    try:
+        return Module(_c.getNextDefmodule())
+    except:
+        raise _c.ClipsError("M02: could not find any Module")
+#}}
+
+#{{FUNCTION
+def ModuleList():
+    """return the list of Module names"""
+    o = _c.getDefmoduleList()
+    return Multifield(_cl2py(o))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def FindModule(name):
+    """find a Module by name"""
+    return Module(_c.findDefmodule(name))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), (str, unicode), None)
+ at _forces(str, str, None)
+def BuildModule(name, text="", comment=None):
+    """build a Module with specified name and body"""
+    if comment:
+        cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+    else:
+        cmtstr = ""
+    construct = "(defmodule %s %s %s)" % (name, cmtstr, text)
+    _c.build(construct)
+    return Module(_c.findDefmodule(name))
+#}}
+
+#{{FUNCTION
+def PrintModules():
+    """print list of Modules to standard output"""
+    _c.routerClear("temporary")
+    _c.listDefmodules("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+
+
+# ========================================================================== #
+# 6) functions involving defglobals
+
+#{{FUNCTION
+def InitialGlobal():
+    """return first Global variable"""
+    try:
+        return Global(_c.getNextDefglobal())
+    except:
+        raise _c.ClipsError("M02: could not find any Global")
+#}}
+
+#{{FUNCTION
+def GlobalList():
+    """return the list of Global variable names"""
+    o = _c.getDefglobalList()
+    return Multifield(_cl2py(o))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def FindGlobal(name):
+    """find a Global variable by name"""
+    return Global(_c.findDefglobal(name))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), None)
+ at _forces(str, None)
+def BuildGlobal(name, value=Nil):
+    """build a Global variable with specified name and body"""
+    if type(value) in (str, unicode, ClipsStringType):
+        value = '"%s"' % str(value)
+    construct = "(defglobal ?*%s* = %s)" % (name, value)
+    _c.build(construct)
+    return Global(_c.findDefglobal("%s" % name))
+#}}
+
+#{{FUNCTION
+def GlobalsChanged():
+    """test whether or not Global variables have changed since last call"""
+    rv = bool(_c.getGlobalsChanged())
+    _c.setGlobalsChanged(False)
+    return rv
+#}}
+
+#{{FUNCTION
+def PrintGlobals():
+    """print list of Global variables to standard output"""
+    _c.routerClear("temporary")
+    _c.listDefglobals("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+#{{FUNCTION
+def ShowGlobals():
+    """print list of Global variables and values to standard output"""
+    _c.routerClear("temporary")
+    _c.showDefglobals("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+
+
+# ========================================================================== #
+# 7) functions involving Functions
+
+#{{FUNCTION
+def InitialFunction():
+    """return first Function"""
+    try:
+        return Function(_c.getNextDeffunction())
+    except:
+        raise _c.ClipsError("M02: could not find any Function")
+#}}
+
+#{{FUNCTION
+def FunctionList():
+    """return the list of Function names"""
+    o = _c.getDeffunctionList()
+    return Multifield(_cl2py(o))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def FindFunction(name):
+    """find a Function by name"""
+    return Function(_c.findDeffunction(name))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), None, (str, unicode), None)
+ at _forces(str, None, str, None)
+def BuildFunction(name, args, text, comment=None):
+    """build a Function with specified name, body and arguments"""
+    if comment:
+        cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+    else:
+        cmtstr = ""
+    if type(args) in (tuple, list):
+        args = " ".join(args)
+    elif args is None:
+        args = ""
+    construct = "(deffunction %s %s (%s) %s)" % (name, cmtstr, args, text)
+    _c.build(construct)
+    return Function(_c.findDeffunction(name))
+#}}
+
+#{{FUNCTION
+def PrintFunctions():
+    """print list of Functions to standard output"""
+    _c.routerClear("temporary")
+    _c.listDeffunctions("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+
+
+# ========================================================================== #
+# 8) functions involving Generics
+
+#{{FUNCTION
+def InitialGeneric():
+    """return first Generic"""
+    try:
+        return Generic(_c.getNextDefgeneric())
+    except:
+        raise _c.ClipsError("M02: could not find any Generic")
+#}}
+
+#{{FUNCTION
+def GenericList():
+    """return the list of Generic names"""
+    o = _c.getDefgenericList()
+    return Multifield(_cl2py(o))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def FindGeneric(name):
+    """find a Generic by name"""
+    return Generic(_c.findDefgeneric(name))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), None)
+ at _forces(str, None)
+def BuildGeneric(name, comment=None):
+    """build a Generic with specified name and body"""
+    if comment:
+        cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+    else:
+        cmtstr = ""
+    construct = "(defgeneric %s %s)" % (name, cmtstr)
+    _c.build(construct)
+    return Generic(_c.findDefgeneric(name))
+#}}
+
+#{{FUNCTION
+def PrintGenerics():
+    """print list of Generics to standard output"""
+    _c.routerClear("temporary")
+    _c.listDefgenerics("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+#{{FUNCTION
+def MethodList():
+    """return the list of all Methods"""
+    o = _cl2py(_c.getDefmethodList())
+    li = Multifield([])
+    l = len(o) / 2
+    for x in range(l):
+        li.append(Multifield([o[2 * x], o[2 * x + 1]]))
+    return li
+#}}
+
+
+
+# ========================================================================== #
+# 9) functions involving Classes
+
+#{{FUNCTION
+def InitialClass():
+    """retrieve first Class"""
+    try:
+        return Class(_c.getNextDefclass())
+    except:
+        raise _c.ClipsError("M02: could not find any Class")
+#}}
+
+#{{FUNCTION
+def ClassList():
+    """return the list of Class names"""
+    o = _c.getDefclassList()
+    return Multifield(_cl2py(o))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def FindClass(name):
+    """find a Class by name"""
+    return Class(_c.findDefclass(name))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), (str, unicode), None)
+ at _forces(str, str, None)
+def BuildClass(name, text, comment=None):
+    """build a Class with specified name and body"""
+    if comment:
+        cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+    else:
+        cmtstr = ""
+    construct = "(defclass %s %s %s)" % (name, cmtstr, text)
+    _c.build(construct)
+    return Class(_c.findDefclass(name))
+#}}
+
+#{{FUNCTION
+def PrintClasses():
+    """print list of Classes to standard output"""
+    _c.routerClear("temporary")
+    _c.listDefclasses("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def BrowseClasses(classname):
+    """print list of Classes that inherit from specified one"""
+    _c.routerClear("temporary")
+    defclass = _c.findDefclass(str(classname))
+    _c.browseClasses("temporary", defclass)
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), None, None, (str, unicode), None, None)
+ at _forces(str, str, None, str, None, None)
+def BuildMessageHandler(name, hclass, args, text, htype=PRIMARY, comment=None):
+    """build a MessageHandler for specified class with arguments and body"""
+    if comment:
+        cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+    else: cmtstr = ""
+    htype = htype.lower()
+    if not htype in (AROUND, BEFORE, PRIMARY, AFTER):
+        raise ValueError("htype must be in AROUND, BEFORE, PRIMARY, AFTER")
+    if type(args) in (tuple, list):
+        sargs = " ".join(args)
+    elif args is None:
+        sargs = ""
+    else:
+        sargs = str(args)
+    construct = "(defmessage-handler %s %s %s %s (%s) %s)" % (
+        hclass, name, htype, cmtstr, sargs, text)
+    _c.build(construct)
+    defclass = _c.findDefclass(hclass)
+    return _c.findDefmessageHandler(defclass, name, htype)
+#}}
+
+#{{FUNCTION
+def MessageHandlerList():
+    """return list of MessageHandler constructs"""
+    o = _c.getDefmessageHandlerList()
+    li, rv = Multifield(_cl2py(o)), []
+    l = len(li) / 3
+    for x in range(0, l):
+        rv.append(Multifield([li[x * 3], li[x * 3 + 1], li[x * 3 + 2]]))
+    return Multifield(rv)
+#}}
+
+#{{FUNCTION
+def PrintMessageHandlers():
+    """print list of all MessageHandlers"""
+    _c.routerClear("temporary")
+    _c.listDefmessageHandlers("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+
+
+# ========================================================================== #
+# 10) functions involving instances
+
+#{{FUNCTION
+def InitialInstance():
+    """retrieve first Instance"""
+    try:
+        return Instance(_c.getNextInstance())
+    except:
+        raise _c.ClipsError("M02: could not find any Instance")
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def BLoadInstances(filename):
+    """load Instances from binary file"""
+    _c.binaryLoadInstances(_os.path.normpath(filename))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), None)
+ at _forces(str, None)
+def BSaveInstances(filename, mode=LOCAL_SAVE):
+    """save Instances to binary file"""
+    _c.binarySaveInstances(_os.path.normpath(filename), mode)
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def LoadInstances(filename):
+    """load Instances from file"""
+    _c.loadInstances(_os.path.normpath(filename))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), None)
+ at _forces(str, None)
+def SaveInstances(filename, mode=LOCAL_SAVE):
+    """save Instances to file"""
+    _c.saveInstances(_os.path.normpath(filename), mode)
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def LoadInstancesFromString(s):
+    """load Instances from the specified string"""
+    _c.loadInstancesFromString(s)
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def RestoreInstancesFromString(s):
+    """restore Instances from the specified string"""
+    _c.restoreInstancesFromString(s)
+#}}
+
+#{{FUNCTION
+def InstancesChanged():
+    """test if Instances have changed since last call"""
+    rv = bool(_c.getInstancesChanged())
+    _c.setInstancesChanged(False)
+    return rv
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), None, (str, unicode))
+ at _forces(str, str, str)
+def BuildInstance(name, defclass, overrides=""):
+    """build an Instance of given class overriding specified slots"""
+    cmdstr = "(%s of %s %s)" % (name, str(defclass), overrides)
+    return Instance(_c.makeInstance(cmdstr))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def FindInstance(name):
+    """find an Instance in all modules (including imported)"""
+    return Instance(_c.findInstance(name, True))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def FindInstanceLocal(name):
+    """find an Instance in non imported modules"""
+    return Instance(_c.findInstance(name, False))
+#}}
+
+#{{FUNCTION
+ at _forces(str)
+def PrintInstances(classname=None):
+    """print Instances to standard output"""
+    _c.routerClear("temporary")
+    if classname:
+        _c.instances("temporary", classname, False)
+    else:
+        _c.instances("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+#{{FUNCTION
+ at _forces(str)
+def PrintSubclassInstances(classname):
+    """print subclass Instances to standard output"""
+    _c.routerClear("temporary")
+    if classname:
+        _c.instances("temporary", classname, True)
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+
+
+# ========================================================================== #
+# 11) functions involving definstances
+
+#{{FUNCTION
+def InitialDefinstances():
+    """retrieve first Definstances"""
+    try:
+        return Definstances(_c.getNextDefinstances())
+    except:
+        raise _c.ClipsError("M02: could not find any Definstances")
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def FindDefinstances(name):
+    """find Definstances by name"""
+    return Definstances(_c.findDefinstances(name))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), (str, unicode), None)
+ at _forces(str, str, None)
+def BuildDefinstances(name, text, comment=None):
+    """build a Definstances with specified name and body"""
+    if comment:
+        cmtstr = '"%s"' % str(comment).replace('"', '\\"')
+    else:
+        cmtstr = ""
+    construct = "(definstances %s %s %s)" % (name, cmtstr, text)
+    _c.build(construct)
+    return Definstances(_c.findDefinstances(name))
+#}}
+
+#{{FUNCTION
+def DefinstancesList():
+    """retrieve list of all Definstances names"""
+    o = _c.getDefinstancesList()
+    return Multifield(_cl2py(o))
+#}}
+
+#{{FUNCTION
+def PrintDefinstances():
+    """print list of all Definstances to standard output"""
+    _c.routerClear("temporary")
+    _c.listDefinstances("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+
+
+# ========================================================================== #
+# 12) Agenda functions
+
+#{{FUNCTION
+def PrintAgenda():
+    """print Agenda Rules to standard output"""
+    _c.routerClear("temporary")
+    _c.agenda("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+#{{FUNCTION
+def AgendaChanged():
+    """test whether or not Agenda is changed since last call"""
+    rv = bool(_c.getAgendaChanged())
+    _c.setAgendaChanged(False)
+    return rv
+#}}
+
+#{{FUNCTION
+def RefreshAgenda():
+    """refresh Agenda Rules for current Module"""
+    _c.refreshAgenda()
+#}}
+
+#{{FUNCTION
+def ReorderAgenda():
+    """reorder Agenda Rules for current Module"""
+    _c.reorderAgenda()
+#}}
+
+#{{FUNCTION
+def Run(limit=None):
+    """execute Rules up to limit (if any)"""
+    if limit is None:
+        return _c.run()
+    else:
+        return _c.run(limit)
+#}}
+
+#{{FUNCTION
+def ClearFocusStack():
+    """clear focus stack"""
+    _c.clearFocusStack()
+#}}
+
+#{{FUNCTION
+def FocusStack():
+    """return list of Module names in focus stack"""
+    return _cl2py(_c.getFocusStack())
+#}}
+
+#{{FUNCTION
+def PrintFocusStack():
+    """print focus stack to standard output"""
+    _c.routerClear("temporary")
+    _c.listFocusStack("temporary")
+    s = _c.routerRead("temporary")
+    if s:
+        _sys.stdout.write(s)
+#}}
+
+#{{FUNCTION
+def PopFocus():
+    """pop focus"""
+    _c.popFocus()
+#}}
+
+#{{FUNCTION
+def InitialActivation():
+    """return first Activation object"""
+    try:
+        return Activation(_c.getNextActivation())
+    except:
+        raise _c.ClipsError("M02: could not find any Activation")
+#}}
+
+#{{FUNCTION
+def CurrentModule():
+    """return current Module"""
+    return Module(_c.getCurrentModule())
+#}}
+
+
+
+# ========================================================================== #
+# 13) True "current environment" functions - as of APG section 4.1
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def BLoad(filename):
+    """binary load the constructs from a file"""
+    _c.bload(_os.path.normpath(filename))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def BSave(filename):
+    """binary save constructs to a file"""
+    _c.bsave(_os.path.normpath(filename))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def Load(filename):
+    """load constructs from a file"""
+    _c.load(_os.path.normpath(filename))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def Save(filename):
+    """save constructs to a file"""
+    _c.save(_os.path.normpath(filename))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def BatchStar(filename):
+    """execute commands stored in file"""
+    _c.batchStar(_os.path.normpath(filename))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def Build(construct):
+    """build construct given in argument"""
+    _c.build(construct)
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode))
+ at _forces(str)
+def Eval(expr):
+    """evaluate expression passed as argument"""
+    return _cl2py(_c.eval(expr))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), None)
+ at _forces(str, None)
+def Call(func, args=None):
+    """call a function with the given argument string or tuple"""
+    if args is not None:
+        t = type(args)
+        if t == str:
+            sargs = args
+        if t == unicode:
+            sargs = str(args)
+        elif t in (ClipsIntegerType, ClipsFloatType, ClipsStringType,
+                   ClipsSymbolType, ClipsNilType, ClipsInstanceNameType,
+                   ClipsMultifieldType):
+            sargs = _py2clsyntax(args)
+        elif isinstance(args, str):
+            sargs = str(args)
+        elif isinstance(args, unicode):
+            sargs = str(args)
+        elif t in (tuple, list):
+            li = []
+            for x in args:
+                t1 = type(x)
+                if t1 in (ClipsIntegerType, ClipsFloatType, ClipsStringType,
+                          ClipsSymbolType, ClipsNilType,
+                          ClipsInstanceNameType, ClipsMultifieldType):
+                    li.append(_py2clsyntax(x))
+                elif t1 in (int, long):
+                    li.append(Integer(int(x)).clsyntax())
+                elif t1 == float:
+                    li.append(Float(x).clsyntax())
+                elif t1 in (str, unicode):
+                    li.append(String(x).clsyntax())
+                elif isinstance(x, int):
+                    li.append(Integer(x).clsyntax())
+                elif isinstance(x, long):
+                    li.append(Integer(x).clsyntax())
+                elif isinstance(x, float):
+                    li.append(Float(x).clsyntax())
+                elif isinstance(x, str):
+                    li.append(String(x).clsyntax())
+                elif isinstance(x, unicode):
+                    li.append(String(x).clsyntax())
+                else:
+                    li.append(str(x))
+            sargs = " ".join(li)
+        elif t in (int, long):
+            sargs = Integer(int(args)).clsyntax()
+        elif t == float:
+            sargs = Float(args).clsyntax()
+        elif isinstance(args, int):
+            sargs = Integer(args).clsyntax()
+        elif isinstance(args, long):
+            sargs = Integer(args).clsyntax()
+        elif isinstance(args, float):
+            sargs = Float(args).clsyntax()
+        else:
+            sargs = str(args)
+        return _cl2py(_c.functionCall(func, sargs))
+    else:
+        return _cl2py(_c.functionCall(func))
+#}}
+
+#{{FUNCTION
+ at _accepts((str, unicode), None)
+ at _forces(str, None)
+def SendCommand(command, verbose=False):
+    """send a command to the engine as if typed at the CLIPS prompt"""
+    _c.sendCommand(command, verbose)
+#}}
+
+#{{FUNCTION
+def Reset():
+    """reset Environment"""
+    _c.reset()
+
+# the environment-aware and toplevel versions of Clear() behave differently
+# as only the toplevel version reinitializes stock classes (see below): this
+# is why a check is performed to test whether or not the 'self' identifier
+# is present (which only happens in the environment-aware version)#}}
+
+#{{FUNCTION
+def Clear():
+    """clear Environment"""
+    _c.clear()
+    if not 'self' in locals().keys():
+        _setStockClasses()
+#}}
+
+
+
+
+# define the only object of the Status type and remove the class definition
+EngineConfig = _clips_Status()
+del _clips_Status
+
+# define the only object of the Debug type and remove the class definition
+DebugConfig = _clips_Debug()
+del _clips_Debug
+
+
+
+# the following is a mechanism to keep stock class names up to date:
+# when the importing module sets this, then its dictionary is modified
+# by the _setStockClasses() function directly; please note that, since
+# the first time this module is imported the stock class names are
+# correct, the __parent_module_dict__ should be set up after importing
+__parent_module_dict__ = None
+def _setParentModuleDict(d):
+    global __parent_module_dict__
+    __parent_module_dict__ = d
+
+
+# provide a way for Environments to do the same as they become current
+def _setStockClasses():
+    """reset stock classes to the ones of current Environment"""
+    global FLOAT_CLASS, INTEGER_CLASS, SYMBOL_CLASS, STRING_CLASS, \
+           MULTIFIELD_CLASS, EXTERNAL_ADDRESS_CLASS, FACT_ADDRESS_CLASS, \
+           INSTANCE_ADDRESS_CLASS, INSTANCE_NAME_CLASS, OBJECT_CLASS, \
+           PRIMITIVE_CLASS, NUMBER_CLASS, LEXEME_CLASS, ADDRESS_CLASS, \
+           INSTANCE_CLASS, USER_CLASS, INITIAL_OBJECT_CLASS
+    # the following definitions are only valid at submodule level
+    FLOAT_CLASS = Class(_c.findDefclass("FLOAT"))
+    INTEGER_CLASS = Class(_c.findDefclass("INTEGER"))
+    SYMBOL_CLASS = Class(_c.findDefclass("SYMBOL"))
+    STRING_CLASS = Class(_c.findDefclass("STRING"))
+    MULTIFIELD_CLASS = Class(_c.findDefclass("MULTIFIELD"))
+    EXTERNAL_ADDRESS_CLASS = Class(_c.findDefclass("EXTERNAL-ADDRESS"))
+    FACT_ADDRESS_CLASS = Class(_c.findDefclass("FACT-ADDRESS"))
+    INSTANCE_ADDRESS_CLASS = Class(_c.findDefclass("INSTANCE-ADDRESS"))
+    INSTANCE_NAME_CLASS = Class(_c.findDefclass("INSTANCE-NAME"))
+    OBJECT_CLASS = Class(_c.findDefclass("OBJECT"))
+    PRIMITIVE_CLASS = Class(_c.findDefclass("PRIMITIVE"))
+    NUMBER_CLASS = Class(_c.findDefclass("NUMBER"))
+    LEXEME_CLASS = Class(_c.findDefclass("LEXEME"))
+    ADDRESS_CLASS = Class(_c.findDefclass("ADDRESS"))
+    INSTANCE_CLASS = Class(_c.findDefclass("INSTANCE"))
+    USER_CLASS = Class(_c.findDefclass("USER"))
+    INITIAL_OBJECT_CLASS = Class(_c.findDefclass("INITIAL-OBJECT"))
+    # modify the importing package namespace using the provided dictionary
+    if __parent_module_dict__:
+        __parent_module_dict__['FLOAT_CLASS'] = FLOAT_CLASS
+        __parent_module_dict__['INTEGER_CLASS'] = INTEGER_CLASS
+        __parent_module_dict__['SYMBOL_CLASS'] = SYMBOL_CLASS
+        __parent_module_dict__['STRING_CLASS'] = STRING_CLASS
+        __parent_module_dict__['MULTIFIELD_CLASS'] = MULTIFIELD_CLASS
+        __parent_module_dict__['EXTERNAL_ADDRESS_CLASS'] = EXTERNAL_ADDRESS_CLASS
+        __parent_module_dict__['FACT_ADDRESS_CLASS'] = FACT_ADDRESS_CLASS
+        __parent_module_dict__['INSTANCE_ADDRESS_CLASS'] = INSTANCE_ADDRESS_CLASS
+        __parent_module_dict__['INSTANCE_NAME_CLASS'] = INSTANCE_NAME_CLASS
+        __parent_module_dict__['OBJECT_CLASS'] = OBJECT_CLASS
+        __parent_module_dict__['PRIMITIVE_CLASS'] = PRIMITIVE_CLASS
+        __parent_module_dict__['NUMBER_CLASS'] = NUMBER_CLASS
+        __parent_module_dict__['LEXEME_CLASS'] = LEXEME_CLASS
+        __parent_module_dict__['ADDRESS_CLASS'] = ADDRESS_CLASS
+        __parent_module_dict__['INSTANCE_CLASS'] = INSTANCE_CLASS
+        __parent_module_dict__['USER_CLASS'] = USER_CLASS
+        __parent_module_dict__['INITIAL_OBJECT_CLASS'] = INITIAL_OBJECT_CLASS
+
+
+
+# set up stock classes now for the module level; please notice that this only
+# is useful when the module is imported directly, thus in the "import clips"
+# form, as it is impossible to modify names defined in the global namespace
+_setStockClasses()
+
+
+
+# ========================================================================== #
+# 14) Functions and classes to access CLIPS input/output
+
+# the simple class to access CLIPS output
+class _clips_Stream(object):
+    """object to access CLIPS output streams"""
+
+    def __init__(self, stream, name=None):
+        """stream object constructor"""
+        self.__stream = stream
+        if name is None:
+            self.__name = 'Internal'
+        else:
+            self.__name = name
+
+    def __repr__(self):
+        return "<%s Stream>" % self.__name
+
+    def Read(self):
+        """read current output from stream"""
+        return _c.routerRead(self.__stream)
+
+
+# the class to write to CLIPS standard input
+class _clips_WriteStream(object):
+    """object to access CLIPS input streams"""
+
+    def __init__(self, stream, name=None):
+        """stream object constructor"""
+        self.__stream = stream
+        if name is None:
+            self.__name = 'Internal'
+        else:
+            self.__name = name
+
+    def __repr__(self):
+        return "<%s Stream>" % self.__name
+
+    def Write(self, s):
+        """write string to stream"""
+        _c.routerWrite(self.__stream, str(s))
+
+
+# actual objects the module user can read from
+StdoutStream = _clips_Stream("stdout", "General Output")
+StdinStream = _clips_WriteStream("stdin", "General Input")
+PromptStream = _clips_Stream("wprompt")     # should not be used
+DialogStream = _clips_Stream("wdialog")     # should not be used
+DisplayStream = _clips_Stream("wdisplay")   # should not be used
+ErrorStream = _clips_Stream("werror", "Error Output")
+WarningStream = _clips_Stream("wwarning", "Warning Output")
+TraceStream = _clips_Stream("wtrace", "Trace Output")
+
+# class definitions can be removed as all possible objects have been built
+del _clips_Stream
+del _clips_WriteStream
+
+
+
+# ========================================================================== #
+# 15) Memory Management - for CLIPS gurus
+class _clips_Memory(object):
+    """object for memory management"""
+
+    __created = False
+
+    def __init__(self):
+        """raise an exception if an object of this type has been created"""
+        if(_clips_Memory.__created):
+            raise TypeError("cannot recreate this object")
+        _clips_Memory.__created = True
+
+    def __repr__(self):
+        return "<Memory Management Object>"
+
+    def __property_getUsed(self):
+        return _c.memUsed()
+    Used = property(__property_getUsed, None, None,
+                    "amount in bytes of memory used by CLIPS")
+
+    def __property_getRequests(self):
+        return _c.memRequests()
+    Requests = property(__property_getRequests, None, None,
+                        "number of requests for memory made by CLIPS")
+
+    def __property_setConserve(self, v):
+        _c.setConserveMemory(v)
+    def __property_getConserve(self):
+        return bool(_c.getConserveMemory())
+    Conserve = property(__property_getConserve, __property_setConserve,
+                        None, "enable/disable caching of some informations")
+
+    def __property_setPPBufferSize(self, v):
+        _c.setPPBufferSize(v)
+    def __property_getPPBufferSize(self):
+        return _c.getPPBufferSize()
+    PPBufferSize = property(__property_getPPBufferSize,
+                            __property_setPPBufferSize,
+                            None, "size of pretty-print buffers")
+
+    def __property_setEnvironmentErrorsEnabled(self, v):
+        _c.setEnableEnvironmentFatalMessages(v)
+    def __property_getEnvironmentErrorsEnabled(self):
+        return bool(_c.getEnableEnvironmentFatalMessages())
+    EnvironmentErrorsEnabled = property(
+        __property_getEnvironmentErrorsEnabled,
+        __property_setEnvironmentErrorsEnabled,
+        None, "whether or not fatal environment errors are printed")
+
+    def __property_getNumberOfEnvironments(self):
+        return _c.getNumberOfEnvironments()
+    NumberOfEnvironments = property(__property_getNumberOfEnvironments, None,
+                                    None, "current number of Environments")
+
+    def Free(self):
+        """free up unneeded memory"""
+        _c.releaseMem(False)
+
+
+# define one only actual object of this type to access memory functions
+Memory = _clips_Memory()
+del _clips_Memory
+
+
+
+# ========================================================================== #
+# 16) External Functions - "all sorts of new and shiny evil"
+ at _accepts(None, (str, unicode))
+ at _forces(None, str)
+def RegisterPythonFunction(func, name=None):
+    """register an external (Python) function to call from within CLIPS"""
+    def _extcall_retval(rv):
+        if rv is None:
+            return Nil.clrepr()
+        else:
+            return _py2cl(rv)
+    if not name:
+        name = func.__name__
+    f = lambda *args: _extcall_retval(func(*tuple(map(_cl2py, list(args)))))
+    _c.addPythonFunction(name, f)
+
+def UnregisterPythonFunction(name):
+    """unregister the given Python function from CLIPS"""
+    if type(name) in (str, unicode):
+        _c.removePythonFunction(str(name))
+    else:
+        _c.removePythonFunction(name.__name__)
+
+def ClearPythonFunctions():
+    """unregister all Python functions from CLIPS"""
+    _c.clearPythonFunctions()
+
+# set or test whether CLIPS python calls should print a traceback or not
+def ExternalTracebackEnabled():
+    """return True if printing tracebacks from within CLIPS is enabled"""
+    return bool(_c.getPrintExternalTraceback())
+def SetExternalTraceback(enable=True):
+    """call with a True value to enable printing tracebacks from CLIPS"""
+    _c.setPrintExternalTraceback(bool(enable))
+
+
+
+# end.
diff --git a/clips/_license.py b/clips/_license.py
new file mode 100644
index 0000000..d5d0a0b
--- /dev/null
+++ b/clips/_license.py
@@ -0,0 +1,362 @@
+# _license.py
+# This file contains the license in a readable form
+
+license = """\
+===========================================================================
+License Information (LGPL)
+===========================================================================
+
+(c) 2002-2008 Francesco Garosi/JKS
+The author's copyright is expressed through the following notice, thus
+giving effective rights to copy and use this software to anyone, as shown
+in the license text.
+
+NOTICE:
+This software is released under the terms of the GNU Lesser General Public
+license; a copy of the text has been released with this package (see file
+_license.py, where the license text also appears), and can be found on the
+GNU web site, at the following address:
+
+           http://www.gnu.org/copyleft/lesser.html
+
+Please refer to the license text for any license information. This notice
+has to be considered part of the license, and should be kept on every copy,
+integral or modified, of the source files. The removal of the reference to
+the license will be considered an infringement of the license itself.
+
+Portions of the code provided with this package may have been released
+under different license terms: in this case it is expressed in the source
+code piece itself. Parts of this source package (eg. the entire CLIPS
+source distribution) are provided under possibly different license terms,
+and different restrictions may apply. These source files are provided as
+the original author(s) packaged them, thus all license information is
+supplied.
+
+If you received the package in binary form, please consult the original
+CLIPS license, which you can find at the CLIPS web site:
+
+                http://clipsrules.sourceforge.net
+
+for the licensing terms regarding use of the CLIPS library.
+
+===========================================================================
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+0. This License Agreement applies to any software library or other program
+which contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Lesser General
+Public License (also called "this License"). Each licensee is addressed as
+"you".
+
+A "library" means a collection of software functions and/or data prepared
+so as to be conveniently linked with application programs (which use some
+of those functions and data) to form executables.
+
+The "Library", below, refers to any such software library or work which has
+been distributed under these terms. A "work based on the Library" means
+either the Library or any derivative work under copyright law: that is to
+say, a work containing the Library or a portion of it, either verbatim or
+with modifications and/or translated straightforwardly into another
+language. (Hereinafter, translation is included without limitation in the
+term "modification".)
+
+"Source code" for a work means the preferred form of the work for making
+modifications to it. For a library, complete source code means all the
+source code for all modules it contains, plus any associated interface
+definition files, plus the scripts used to control compilation and
+installation of the library.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of running a
+program using the Library is not restricted, and output from such a program
+is covered only if its contents constitute a work based on the Library
+(independent of the use of the Library in a tool for writing it). Whether
+that is true depends on what the Library does and what the program that
+uses the Library does.
+
+1. You may copy and distribute verbatim copies of the Library's complete
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the notices
+that refer to this License and to the absence of any warranty; and
+distribute a copy of this License along with the Library.
+
+You may charge a fee for the physical act of transferring a copy, and you
+may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Library or any portion of it,
+thus forming a work based on the Library, and copy and distribute such
+modifications or work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+
+a) The modified work must itself be a software library.
+b) You must cause the files modified to carry prominent notices stating
+   that you changed the files and the date of any change.
+c) You must cause the whole of the work to be licensed at no charge to all
+   third parties under the terms of this License.
+d) If a facility in the modified Library refers to a function or a table of
+   data to be supplied by an application program that uses the facility,
+   other than as an argument passed when the facility is invoked, then you
+   must make a good faith effort to ensure that, in the event an application
+   does not supply such function or table, the facility still operates, and
+   performs whatever part of its purpose remains meaningful.
+
+(For example, a function in a library to compute square roots has a purpose
+that is entirely well-defined independent of the application. Therefore,
+Subsection 2d requires that any application-supplied function or table used
+by this function must be optional: if the application does not supply it,
+the square root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Library, and can be
+reasonably considered independent and separate works in themselves, then
+this License, and its terms, do not apply to those sections when you
+distribute them as separate works. But when you distribute the same sections
+as part of a whole which is a work based on the Library, the distribution
+of the whole must be on the terms of this License, whose permissions for
+other licensees extend to the entire whole, and thus to each and every part
+regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise
+the right to control the distribution of derivative or collective works
+based on the Library.
+
+In addition, mere aggregation of another work not based on the Library with
+the Library (or with a work based on the Library) on a volume of a storage
+or distribution medium does not bring the other work under the scope of
+this License.
+
+3. You may opt to apply the terms of the ordinary GNU General Public License
+instead of this License to a given copy of the Library. To do this, you
+must alter all the notices that refer to this License, so that they refer
+to the ordinary GNU General Public License, version 2, instead of to this
+License. (If a newer version than version 2 of the ordinary GNU General
+Public License has appeared, then you can specify that version instead if
+you wish.) Do not make any other change in these notices.
+
+Once this change is made in a given copy, it is irreversible for that copy,
+so the ordinary GNU General Public License applies to all subsequent copies
+and derivative works made from that copy.
+
+This option is useful when you wish to copy part of the code of the Library
+into a program that is not a library.
+
+4. You may copy and distribute the Library (or a portion or derivative of
+it, under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you accompany it with the complete
+corresponding machine-readable source code, which must be distributed under
+the terms of Sections 1 and 2 above on a medium customarily used for
+software interchange.
+
+If distribution of object code is made by offering access to copy from a
+designated place, then offering equivalent access to copy the source code
+from the same place satisfies the requirement to distribute the source
+code, even though third parties are not compelled to copy the source along
+with the object code.
+
+5. A program that contains no derivative of any portion of the Library, but
+is designed to work with the Library by being compiled or linked with it,
+is called a "work that uses the Library". Such a work, in isolation, is not
+a derivative work of the Library, and therefore falls outside the scope of
+this License.
+
+However, linking a "work that uses the Library" with the Library creates an
+executable that is a derivative of the Library (because it contains portions
+of the Library), rather than a "work that uses the library". The executable
+is therefore covered by this License.Section 6 states terms for distribution
+of such executables.
+
+When a "work that uses the Library" uses material from a header file that
+is part of the Library, the object code for the work may be a derivative
+work of the Library even though the source code is not. Whether this is
+true is especially significant if the work can be linked without the
+Library, or if the work is itself a library. The threshold for this to be
+true is not precisely defined by law.
+
+If such an object file uses only numerical parameters, data structure
+layouts and accessors, and small macros and small inline functions (ten
+lines or less in length), then the use of the object file is unrestricted,
+regardless of whether it is legally a derivative work. (Executables
+containing this object code plus portions of the Library will still fall
+under Section 6.)
+
+Otherwise, if the work is a derivative of the Library, you may distribute
+the object code for the work under the terms of Section 6. Any executables
+containing that work also fall under Section 6, whether or not they are
+linked directly with the Library itself.
+
+6. As an exception to the Sections above, you may also combine or link a
+"work that uses the Library" with the Library to produce a work containing
+portions of the Library, and distribute that work under terms of your
+choice, provided that the terms permit modification of the work for the
+customer's own use and reverse engineering for debugging such modifications.
+
+You must give prominent notice with each copy of the work that the Library
+is used in it and that the Library and its use are covered by this License.
+You must supply a copy of this License.If the work during execution displays
+copyright notices, you must include the copyright notice for the Library
+among them, as well as a reference directing the user to the copy of this
+License. Also, you must do one of these things:
+
+
+a) Accompany the work with the complete corresponding machine-readable
+   source code for the Library including whatever changes were used in the
+   work (which must be distributed under Sections 1 and 2 above); and, if
+   the work is an executable linked with the Library, with the complete
+   machine-readable "work that uses the Library", as object code and/or
+   source code, so that the user can modify the Library and then relink to
+   produce a modified executable containing the modified Library. (It is
+   understood that the user who changes the contents of definitions files
+   in the Library will not necessarily be able to recompile the application
+   to use the modified definitions.)
+b) Use a suitable shared library mechanism for linking with the Library. A
+   suitable mechanism is one that (1) uses at run time a copy of the library
+   already present on the user's computer system, rather than copying
+   library functions into the executable, and (2) will operate properly
+   with a modified version of the library, if the user installs one, as
+   long as the modified version is interface-compatible with the version
+   that the work was made with.
+c) Accompany the work with a written offer, valid for at least three years,
+   to give the same user the materials specified in Subsection 6a, above,
+   for a charge no more than the cost of performing this distribution.
+d) If distribution of the work is made by offering access to copy from a
+   designated place, offer equivalent access to copy the above specified
+   materials from the same place.
+e) Verify that the user has already received a copy of these materials or
+   that you have already sent this user a copy.
+
+For an executable, the required form of the "work that uses the Library"
+must include any data and utility programs needed for reproducing the
+executable from it. However, as a special exception, the materials to be
+distributed need not include anything that is normally distributed (in
+either source or binary form) with the major components (compiler, kernel,
+and so on) of the operating system on which the executable runs, unless
+that component itself accompanies the executable.
+
+It may happen that this requirement contradicts the license restrictions of
+other proprietary libraries that do not normally accompany the operating
+system. Such a contradiction means you cannot use both them and the Library
+together in an executable that you distribute.
+
+7. You may place library facilities that are a work based on the Library
+side-by-side in a single library together with other library facilities not
+covered by this License, and distribute such a combined library, provided
+that the separate distribution of the work based on the Library and of the
+other library facilities is otherwise permitted, and provided that you do
+these two things:
+
+
+a) Accompany the combined library with a copy of the same work based on the
+   Library, uncombined with any other library facilities. This must be
+   distributed under the terms of the Sections above.
+b) Give prominent notice with the combined library of the fact that part of
+   it is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+8. You may not copy, modify, sublicense, link with, or distribute the
+Library except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense, link with, or distribute the Library
+is void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+9. You are not required to accept this License, since you have not signed
+it. However, nothing else grants you permission to modify or distribute the
+Library or its derivative works. These actions are prohibited by law if you
+do not accept this License. Therefore, by modifying or distributing the
+Library (or any work based on the Library), you indicate your acceptance of
+this License to do so, and all its terms and conditions for copying,
+distributing or modifying the Library or works based on it.
+
+10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the original
+licensor to copy, distribute, link with or modify the Library subject to
+these terms and conditions. You may not impose any further restrictions on
+the recipients' exercise of the rights granted herein. You are not
+responsible for enforcing compliance by third parties with this License.
+
+11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot distribute so
+as to satisfy simultaneously your obligations under this License and any
+other pertinent obligations, then as a consequence you may not distribute
+the Library at all. For example, if a patent license would not permit
+royalty-free redistribution of the Library by all those who receive copies
+directly or indirectly through you, then the only way you could satisfy
+both it and this License would be to refrain entirely from distribution of
+the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents
+or other property right claims or to contest validity of any such claims;
+this section has the sole purpose of protecting the integrity of the free
+software distribution system which is implemented by public license
+practices. Many people have made generous contributions to the wide range
+of software distributed through that system in reliance on consistent
+application of that system; it is up to the author/donor to decide if he or
+she is willing to distribute software through any other system and a
+licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+12. If the distribution and/or use of the Library is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Library under this License may add an
+explicit geographical distribution limitation excluding those countries, so
+that distribution is permitted only in or among countries not thus excluded.
+In such case, this License incorporates the limitation as if written in the
+body of this License.
+
+13. The Free Software Foundation may publish revised and/or new versions of
+the Lesser General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Library does not specify a license version
+number, you may choose any version ever published by the Free Software
+Foundation.
+
+14. If you wish to incorporate parts of the Library into other free programs
+whose distribution conditions are incompatible with these, write to the
+author to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO
+THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY
+PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+CORRECTION.
+
+16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER
+SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES."""
+
+__revision__ = "$Id: _license.py 340 2008-02-21 00:39:34Z Franz $"
\ No newline at end of file
diff --git a/clips_or.c b/clips_or.c
new file mode 100644
index 0000000..7f83ba9
--- /dev/null
+++ b/clips_or.c
@@ -0,0 +1,421 @@
+/* clips_or.c
+ * Source of functions from CLIPS explicitly reimplemented for PyCLIPS:
+ * depending on how CLIPS changes in time, some functions may appear or
+ * disappear (or be conditionally compiled) from here. Functions defined
+ * here have the same name as in the CLIPS API followed by _PY, and their
+ * arguments may be different from the official CLIPS ones. However these
+ * functions were actually copied from the original CLIPS sources, and
+ * only slightly changed: therefore I list myself only as a contributing
+ * programmer. Moreover, the license for this file is the one that covers
+ * the CLIPS source (which is BSD-like).
+ * $Id: clips_or.c 323 2007-04-02 22:24:35Z Franz $
+ */
+
+/* NOTE: This file used to be split in three parts, one per function */
+
+
+/*************************************************************/
+/* Principal Programmer(s): Gary D. Riley                    */
+/*                          Brian L. Donnell                 */
+/*                                                           */
+/* Contributing Programmer(s): Francesco Garosi              */
+/*                                                           */
+/*************************************************************/
+
+
+#define _RULECOM_SOURCE_
+#define _CONSTRCT_SOURCE_
+#define _INSCOM_SOURCE_
+
+#include <stdio.h>
+#define _STDIO_INCLUDED_
+#include <string.h>
+
+#include "setup.h"
+
+
+/* many of these might not be needed but they were in the original sources */
+
+#include "argacces.h"
+#include "commline.h"
+#include "classcom.h"
+#include "classfun.h"
+#include "classinf.h"
+#include "constant.h"
+#include "constrct.h"
+#include "crstrtgy.h"
+#include "engine.h"
+#include "envrnmnt.h"
+#include "evaluatn.h"
+#include "extnfunc.h"
+#include "exprnpsr.h"
+#include "insfile.h"
+#include "insfun.h"
+#include "insmngr.h"
+#include "insmoddp.h"
+#include "insmult.h"
+#include "inspsr.h"
+#include "lgcldpnd.h"
+#include "memalloc.h"
+#include "moduldef.h"
+#include "msgcom.h"
+#include "msgfun.h"
+#include "multifld.h"
+#include "pattern.h"
+#include "prcdrfun.h"
+#include "prcdrpsr.h"
+#include "reteutil.h"
+#include "router.h"
+#include "ruledlt.h"
+#include "scanner.h"
+#include "sysdep.h"
+#include "strngrtr.h"
+#include "utility.h"
+#include "watch.h"
+
+#if BLOAD || BLOAD_AND_BSAVE || BLOAD_ONLY
+#include "rulebin.h"
+#endif
+
+#if LOGICAL_DEPENDENCIES
+#include "lgcldpnd.h"
+#endif
+
+#if INCREMENTAL_RESET
+#include "incrrset.h"
+#endif
+
+#include "rulecom.h"
+#include "constrct.h"
+#include "inscom.h"
+
+
+#include "clips_or.h"
+
+
+/* EnvMatches_PY
+ * provides a customized version of the EnvMatches API, that can redirect
+ * its output to a specified output stream. This will be used instead of the
+ * Matches() standard API.
+ */
+
+#if DEFRULE_CONSTRUCT
+
+/********************************/
+/* EnvMatches: C access routine */
+/*   for the matches command.   */
+/********************************/
+globle BOOLEAN EnvMatches_PY(
+  void *theEnv,
+  char *logicalName,
+  void *theRule)
+  {
+   struct defrule *rulePtr, *tmpPtr;
+   struct partialMatch *listOfMatches, **theStorage;
+   struct joinNode *theJoin, *lastJoin;
+   int i, depth;
+   ACTIVATION *agendaPtr;
+   int flag;
+   int matchesDisplayed;
+
+   /*=================================================*/
+   /* Loop through each of the disjuncts for the rule */
+   /*=================================================*/
+
+   for (rulePtr = (struct defrule *) theRule, tmpPtr = rulePtr;
+        rulePtr != NULL;
+        rulePtr = rulePtr->disjunct)
+     {
+      /*======================================*/
+      /* Determine the last join in the rule. */
+      /*======================================*/
+
+      lastJoin = rulePtr->lastJoin;
+
+      /*===================================*/
+      /* Determine the number of patterns. */
+      /*===================================*/
+
+      depth = GetPatternNumberFromJoin(lastJoin);
+
+      /*=========================================*/
+      /* Store the alpha memory partial matches. */
+      /*=========================================*/
+
+      theStorage = (struct partialMatch **)
+                   genalloc(theEnv,(unsigned) (depth * sizeof(struct partialMatch)));
+
+      theJoin = lastJoin;
+      i = depth - 1;
+      while (theJoin != NULL)
+        {
+         if (theJoin->joinFromTheRight)
+           { theJoin = (struct joinNode *) theJoin->rightSideEntryStructure; }
+         else
+           {
+            theStorage[i] = ((struct patternNodeHeader *) theJoin->rightSideEntryStructure)->alphaMemory;
+            i--;
+            theJoin = theJoin->lastLevel;
+           }
+        }
+
+      /*========================================*/
+      /* List the alpha memory partial matches. */
+      /*========================================*/
+
+      for (i = 0; i < depth; i++)
+        {
+         if (GetHaltExecution(theEnv) == TRUE)
+           {
+            genfree(theEnv,theStorage,(unsigned) (depth * sizeof(struct partialMatch)));
+            return(TRUE);
+           }
+
+         EnvPrintRouter(theEnv,logicalName,"Matches for Pattern ");
+         PrintLongInteger(theEnv,logicalName,(long int) i + 1);
+         EnvPrintRouter(theEnv,logicalName,"\n");
+
+         listOfMatches = theStorage[i];
+         if (listOfMatches == NULL) EnvPrintRouter(theEnv,logicalName," None\n");
+
+         while (listOfMatches != NULL)
+           {
+            if (GetHaltExecution(theEnv) == TRUE)
+              {
+               genfree(theEnv,theStorage,(unsigned) (depth * sizeof(struct partialMatch)));
+               return(TRUE);
+              }
+            PrintPartialMatch(theEnv,logicalName,listOfMatches);
+            EnvPrintRouter(theEnv,logicalName,"\n");
+            listOfMatches = listOfMatches->next;
+           }
+        }
+
+      genfree(theEnv,theStorage,(unsigned) (depth * sizeof(struct partialMatch)));
+
+      /*========================================*/
+      /* Store the beta memory partial matches. */
+      /*========================================*/
+
+      depth = lastJoin->depth;
+      theStorage = (struct partialMatch **) genalloc(theEnv,(unsigned) (depth * sizeof(struct partialMatch)));
+
+      theJoin = lastJoin;
+      for (i = depth - 1; i >= 0; i--)
+        {
+         theStorage[i] = theJoin->beta;
+         theJoin = theJoin->lastLevel;
+        }
+
+      /*=======================================*/
+      /* List the beta memory partial matches. */
+      /*=======================================*/
+
+      for (i = 1; i < depth; i++)
+        {
+         if (GetHaltExecution(theEnv) == TRUE)
+           {
+            genfree(theEnv,theStorage,(unsigned) (depth * sizeof(struct partialMatch)));
+            return(TRUE);
+           }
+
+         matchesDisplayed = 0;
+         EnvPrintRouter(theEnv,logicalName,"Partial matches for CEs 1 - ");
+         PrintLongInteger(theEnv,logicalName,(long int) i + 1);
+         EnvPrintRouter(theEnv,logicalName,"\n");
+         listOfMatches = theStorage[i];
+
+         while (listOfMatches != NULL)
+           {
+            if (GetHaltExecution(theEnv) == TRUE)
+              {
+               genfree(theEnv,theStorage,(unsigned) (depth * sizeof(struct partialMatch)));
+               return(TRUE);
+              }
+
+            if (listOfMatches->counterf == FALSE)
+              {
+               matchesDisplayed++;
+               PrintPartialMatch(theEnv,logicalName,listOfMatches);
+               EnvPrintRouter(theEnv,logicalName,"\n");
+              }
+            listOfMatches = listOfMatches->next;
+           }
+
+         if (matchesDisplayed == 0) { EnvPrintRouter(theEnv,logicalName," None\n"); }
+        }
+
+      genfree(theEnv,theStorage,(unsigned) (depth * sizeof(struct partialMatch)));
+     }
+
+   /*===================*/
+   /* List activations. */
+   /*===================*/
+
+   rulePtr = tmpPtr;
+   EnvPrintRouter(theEnv,logicalName,"Activations\n");
+   flag = 1;
+   for (agendaPtr = (struct activation *) EnvGetNextActivation(theEnv,NULL);
+        agendaPtr != NULL;
+        agendaPtr = (struct activation *) EnvGetNextActivation(theEnv,agendaPtr))
+     {
+      if (GetHaltExecution(theEnv) == TRUE) return(TRUE);
+
+      if (((struct activation *) agendaPtr)->theRule->header.name == rulePtr->header.name)
+        {
+         flag = 0;
+         PrintPartialMatch(theEnv,logicalName,GetActivationBasis(agendaPtr));
+         EnvPrintRouter(theEnv,logicalName,"\n");
+        }
+     }
+
+   if (flag) EnvPrintRouter(theEnv,logicalName," None\n");
+
+   return(TRUE);
+  }
+
+#endif /* DEFRULE_CONSTRUCT */
+
+
+
+/* EnvClear_PY
+ * Overrides the EnvClear function that would normally conflict with PyCLIPS.
+ */
+
+/*****************************************************/
+/* EnvClear: C access routine for the clear command. */
+/*****************************************************/
+globle BOOLEAN EnvClear_PY(
+  void *theEnv)
+  {
+   struct callFunctionItem *theFunction;
+
+   /*==========================================*/
+   /* Activate the watch router which captures */
+   /* trace output so that it is not displayed */
+   /* during a clear.                          */
+   /*==========================================*/
+
+#if DEBUGGING_FUNCTIONS
+   EnvActivateRouter(theEnv,WTRACE);
+#endif
+
+   /*===================================*/
+   /* Determine if a clear is possible. */
+   /*===================================*/
+
+   ConstructData(theEnv)->ClearReadyInProgress = TRUE;
+   if (ClearReady(theEnv) == FALSE)
+     {
+      PrintErrorID(theEnv,"CONSTRCT",1,FALSE);
+      EnvPrintRouter(theEnv,WERROR,"Some constructs are still in use. Clear cannot continue.\n");
+#if DEBUGGING_FUNCTIONS
+      EnvDeactivateRouter(theEnv,WTRACE);
+#endif
+      ConstructData(theEnv)->ClearReadyInProgress = FALSE;
+      return FALSE;
+     }
+   ConstructData(theEnv)->ClearReadyInProgress = FALSE;
+
+   /*===========================*/
+   /* Call all clear functions. */
+   /*===========================*/
+
+   ConstructData(theEnv)->ClearInProgress = TRUE;
+
+   for (theFunction = ConstructData(theEnv)->ListOfClearFunctions;
+        theFunction != NULL;
+        theFunction = theFunction->next)
+     {
+      if (theFunction->environmentAware)
+        { (*theFunction->func)(theEnv); }
+      else
+        { (* (void (*)(void)) theFunction->func)(); }
+     }
+
+   /*=============================*/
+   /* Deactivate the watch router */
+   /* for capturing output.       */
+   /*=============================*/
+
+#if DEBUGGING_FUNCTIONS
+   EnvDeactivateRouter(theEnv,WTRACE);
+#endif
+
+   /*===========================================*/
+   /* Perform periodic cleanup if the clear was */
+   /* issued from an embedded controller.       */
+   /*===========================================*/
+
+   if ((EvaluationData(theEnv)->CurrentEvaluationDepth == 0) && (! CommandLineData(theEnv)->EvaluatingTopLevelCommand) &&
+       (EvaluationData(theEnv)->CurrentExpression == NULL))
+     { PeriodicCleanup(theEnv,TRUE,FALSE); }
+
+   /*===========================*/
+   /* Clear has been completed. */
+   /*===========================*/
+
+   ConstructData(theEnv)->ClearInProgress = FALSE;
+   return TRUE;
+  }
+
+
+
+/* EnvGetNextInstanceInClassAndSubclasses_PY
+ * provides a customized version of the EnvGetNextInstanceInClassAndSubclasses
+ * API, that does not "return" a pointer to the subclass. This will be used
+ * instead of the EnvGetNextInstanceInClassAndSubclasses() standard API.
+ */
+
+#if OBJECT_SYSTEM
+
+/***************************************************
+  NAME         : EnvGetNextInstanceInClassAndSubclasses
+  DESCRIPTION  : Finds next instance of class
+                 (or first instance of class) and
+                 all of its subclasses
+  INPUTS       : 1) Class address (DIRECT POINTER!)
+                 2) Instance address
+                    (NULL to get first instance)
+  RETURNS      : The next or first class instance
+  SIDE EFFECTS : None
+  NOTES        : None
+ ***************************************************/
+globle void *EnvGetNextInstanceInClassAndSubclasses_PY(
+  void *theEnv,
+  void *cptr,   /* this has changed */
+  void *iptr,
+  DATA_OBJECT *iterationInfo)
+  {
+   INSTANCE_TYPE *nextInstance;
+   DEFCLASS *theClass;
+
+   theClass = (DEFCLASS *)cptr;
+
+   if (iptr == NULL)
+     {
+      ClassSubclassAddresses(theEnv,theClass,iterationInfo,TRUE);
+      nextInstance = theClass->instanceList;
+     }
+   else if (((INSTANCE_TYPE *) iptr)->garbage == 1)
+     { nextInstance = NULL; }
+   else
+     { nextInstance = ((INSTANCE_TYPE *) iptr)->nxtClass; }
+
+   while ((nextInstance == NULL) &&
+          (GetpDOBegin(iterationInfo) <= GetpDOEnd(iterationInfo)))
+     {
+      theClass = (struct defclass *) GetMFValue(DOPToPointer(iterationInfo),
+                                                GetpDOBegin(iterationInfo));
+      SetpDOBegin(iterationInfo,GetpDOBegin(iterationInfo) + 1);
+      nextInstance = theClass->instanceList;
+     }
+
+   return(nextInstance);
+  }
+
+#endif /* OBJECT_SYSTEM */
+
+
+
+/* end. */
diff --git a/clips_or.h b/clips_or.h
new file mode 100644
index 0000000..9a87bd5
--- /dev/null
+++ b/clips_or.h
@@ -0,0 +1,37 @@
+/* clips_or.h
+ * Header for functions from CLIPS explicitly reimplemented for PyCLIPS:
+ * depending on how CLIPS changes in time, some functions may appear or
+ * disappear (or be conditionally defined) from here.
+ * $Id: clips_or.h 340 2008-02-21 00:39:34Z Franz $
+ */
+
+
+#ifndef BOOLEAN
+#ifdef intBool
+#define BOOLEAN intBool
+#else /* intBool */
+#define BOOLEAN int
+#endif /* intBool */
+#endif  /* BOOLEAN */
+
+
+#if ENVIRONMENT_API_ONLY
+#define Matches_PY(theEnv,s,a) EnvMatches_PY(theEnv,s,a)
+#define Clear_PY(theEnv) EnvClear_PY(theEnv)
+#define GetNextInstanceInClassAndSubclasses_PY(theEnv,a,b,c) \
+        EnvGetNextInstanceInClassAndSubclasses_PY(theEnv,a,b,c)
+#else
+#define Matches_PY(s,a) EnvMatches_PY(GetCurrentEnvironment(),s,a)
+#define Clear_PY() EnvClear_PY(GetCurrentEnvironment())
+#define GetNextInstanceInClassAndSubclasses_PY(a,b,c) \
+        EnvGetNextInstanceInClassAndSubclasses_PY(GetCurrentEnvironment(),a,b,c)
+#endif
+
+
+LOCALE BOOLEAN EnvMatches_PY(void *,char *,void *);
+LOCALE BOOLEAN EnvClear_PY(void *);
+LOCALE void *EnvGetNextInstanceInClassAndSubclasses_PY(
+    void *,void *,void *,DATA_OBJECT *);
+
+
+/* end. */
diff --git a/clipsmodule.c b/clipsmodule.c
new file mode 100644
index 0000000..2275921
--- /dev/null
+++ b/clipsmodule.c
@@ -0,0 +1,19650 @@
+/* clipsmodule.c
+ *
+ * Python module to embed CLIPS into Python.
+ * $Id: clipsmodule.c 345 2008-02-22 17:44:54Z Franz $
+ * (c) 2002-2008 - Francesco Garosi/JKS
+ */
+
+/* LICENSE INFORMATION
+
+# (c) 2002-2008 Francesco Garosi/JKS
+#  The author's copyright is expressed through the following notice, thus
+#  giving effective rights to copy and use this software to anyone, as shown
+#  in the license text.
+#
+# NOTICE:
+#  This software is released under the terms of the GNU Lesser General Public
+#  license; a copy of the text has been released with this package (see file
+#  _license.py, where the license text also appears), and can be found on the
+#  GNU web site, at the following address:
+#
+#           http://www.gnu.org/copyleft/lesser.html
+#
+#  Please refer to the license text for any license information. This notice
+#  has to be considered part of the license, and should be kept on every copy
+#  integral or modified, of the source files. The removal of the reference to
+#  the license will be considered an infringement of the license itself.
+
+*/
+
+
+#include "clipsmodule.h"
+
+
+/* some configuration values that should generally not be changed */
+#define MIN_PPBUFFER_SIZE 256   /* minimum pretty print buffer size */
+
+
+/* the module documentation string, in perfect Python style */
+static char clips__doc__[] =
+"_clips - a low-level portable interface to the CLIPS system for Python\n"
+"         (c) 2002-2008 Francesco Garosi/JKS";
+
+/* the release string, in case it should be used someday */
+static char *clips__revision__ =
+    "$Id: clipsmodule.c 345 2008-02-22 17:44:54Z Franz $";
+
+
+/* module scope exception */
+PyObject *PyExc_ClipsError = NULL;
+PyObject *PyExc_ClipsMemoryError = NULL;
+
+
+/* module scope router dictionary */
+static PyDictObject *clips_Streams = NULL;
+
+
+/* module scope functions dictionary */
+static PyDictObject *clips_PythonFunctions = NULL;
+
+
+/* literal helpers */
+
+/* this is to fail uniformly, assuming there is a "fail:" label */
+#define FAIL() do { goto fail; } while(0)
+#define BEGIN_FAIL fail:
+#define END_FAIL return NULL;
+
+/* to add manifest integer constants to module dictionary */
+#define ADD_MANIFEST_CONSTANT(dict, name) \
+    PyDict_SetItemString((dict), #name, PyInt_FromLong((long)(name)))
+
+/* I always define this */
+#define SKIP()
+
+/* this also might be useful */
+#define TRACE(s) fprintf(stderr, s "\n");
+
+/* perform all the job to return the None object and other standard things */
+#define RETURN_PYOBJECT(_p) do { return (PyObject *)(_p); } while(0)
+#define RETURN_INT(_i) do { return Py_BuildValue("i", (_i)); } while(0)
+#define RETURN_BOOL(_i) do { return Py_BuildValue("i", (_i) ? 1 : 0); } while(0)
+#define RETURN_STR(_s) do { return Py_BuildValue("s", (_s)); } while(0)
+
+/* this is not defined for Python < 2.4 */
+#ifdef Py_RETURN_NONE
+#define RETURN_NONE() Py_RETURN_NONE
+#else
+#define RETURN_NONE() do { Py_INCREF(Py_None); return Py_None; } while(0)
+#endif /* Py_RETURN_NONE */
+
+/* inlining might be useful in some cases */
+#ifdef __GNUC__
+#define F_INLINE __inline__
+#else
+#ifdef _MSC_VER
+#define F_INLINE __inline
+#else
+#define F_INLINE
+#endif /* _MSC_VER */
+#endif /* __GNUC__ */
+
+
+/* some common strings to save space */
+static char _error_object_creation[] = "P01: object could not be created";
+/* static char _error_clips_generic[] = "C00: generic clips error"; */ /* NOT USED */
+static char _error_clips_creation[] = "C01: system object could not be created";
+static char _error_clips_notfound[] = "C02: construct or object could not be found";
+static char _error_clips_readonly[] = "C03: object cannot be modified";
+static char _error_clips_fileio[] = "C04: could not open file";
+static char _error_clips_noenv[] = "C05: could not get current environment";
+static char _error_clips_retval[] = "C06: unable to retrieve value";
+static char _error_clips_parsefile[] = "C07: unable to parse file";
+static char _error_clips_parseexpr[] = "C08: syntax error, or unable to parse expression";
+static char _error_clips_parsearg[] = "C09: unable to understand argument";
+static char _error_clips_evalexpr[] = "C10: unable to evaluate expression";
+static char _error_clips_remove[] = "C11: could not remove construct or object";
+static char _error_clips_assert[] = "C12: could not assert";
+/* static char _error_clips_beyond[] = "C13: beyond last element"; */ /* NOT USED */
+static char _error_clips_funccall[] = "C14: unsuccessful function call";
+static char _error_clips_reassert[] = "C15: cannot reassert or modify fact";
+static char _error_clips_unimplemented[] = "C98: unimplemented feature/function";
+static char _error_clips_impossible[] = "C99: could not perform operation";
+
+/* static char _error_clipssys_generic[] = "S00: generic engine error"; */ /* NOT USED */
+static char _error_clipssys_garbfact[] = "S01: fact does not exist anymore";
+static char _error_clipssys_garbinstance[] = "S02: instance does not exist anymore";
+static char _error_clipssys_envnoclear[] = "S03: environment could not be cleared";
+static char _error_clipssys_badenv[] = "S04: environment is invalid";
+static char _error_clipssys_curenv[] = "S05: aliasing current environment might corrupt system";
+static char _error_clipssys_maxenv[] = "S06: maximum number of environments reached";
+static char _error_clipssys_cleanup[] = "S07: cannot force cleanup while rules are executing";
+
+/* static char _error_clipsmem_generic[] = "X00: generic memory error"; */ /* NOT USED */
+static char _error_clipsmem_out[] = "X01: out of memory, system may be inconsistent";
+
+static char _error_router_invalid[] = "R01: invalid logical buffer operation";
+static char _error_router_nostream[] = "R02: logical buffer not found";
+static char _error_router_readonly[] = "R03: buffer is read-only";
+
+/* common helpers for common exceptions */
+#define ERROR_CLIPS(s) PyErr_SetString(PyExc_ClipsError, (s))
+#define ERROR_CLIPS_MEMORY(s) PyErr_SetString(PyExc_ClipsMemoryError, (s))
+#define ERROR_VALUE(s) PyErr_SetString(PyExc_ValueError, (s))
+#define ERROR_TYPE(s) PyErr_SetString(PyExc_TypeError, (s))
+#define ERROR_IO(s) PyErr_SetString(PyExc_IOError, (s))
+#define ERROR_MEMORY(s) PyErr_SetString(PyExc_MemoryError, (s))
+
+#define ERROR_MEMORY_CREATION() ERROR_MEMORY(_error_object_creation)
+#define ERROR_UNIMPLEMENTED() ERROR_CLIPS(_error_clips_unimplemented)
+#define ERROR_CLIPS_IMPOSSIBLE() ERROR_CLIPS(_error_clips_impossible)
+#define ERROR_CLIPS_GENERIC() ERROR_CLIPS(_error_clips_generic)
+#define ERROR_CLIPS_CREATION() ERROR_CLIPS(_error_clips_creation)
+#define ERROR_CLIPS_NOTFOUND() ERROR_CLIPS(_error_clips_notfound)
+#define ERROR_CLIPS_READONLY() ERROR_CLIPS(_error_clips_readonly)
+#define ERROR_CLIPS_IO() ERROR_IO(_error_clips_fileio)
+#define ERROR_CLIPS_NOENV() ERROR_CLIPS(_error_clips_noenv)
+#define ERROR_CLIPS_RETVAL() ERROR_CLIPS(_error_clips_retval)
+#define ERROR_CLIPS_PARSEF() ERROR_CLIPS(_error_clips_parsefile)
+#define ERROR_CLIPS_PARSEX() ERROR_CLIPS(_error_clips_parseexpr)
+#define ERROR_CLIPS_PARSEA() ERROR_CLIPS(_error_clips_parsearg)
+#define ERROR_CLIPS_EVALX() ERROR_CLIPS(_error_clips_evalexpr)
+#define ERROR_CLIPS_REMOVE() ERROR_CLIPS(_error_clips_remove)
+#define ERROR_CLIPS_ASSERT() ERROR_CLIPS(_error_clips_assert)
+#define ERROR_CLIPS_FUNCCALL() ERROR_CLIPS(_error_clips_funccall)
+#define ERROR_CLIPS_REASSERT() ERROR_CLIPS(_error_clips_reassert)
+#define ERROR_CLIPS_OTHER(s) ERROR_CLIPS("C90: " s)
+
+#define ERROR_CLIPSSYS_GENERIC() ERROR_CLIPS(_error_clipssys_generic)
+#define ERROR_CLIPSSYS_GARBFACT() ERROR_CLIPS(_error_clipssys_garbfact)
+#define ERROR_CLIPSSYS_GARBINSTANCE() ERROR_CLIPS(_error_clipssys_garbinstance)
+#define ERROR_CLIPSSYS_ENVUNINIT() ERROR_CLIPS(_error_clipssys_envuninit)
+#define ERROR_CLIPSSYS_ENVNOCLEAR() ERROR_CLIPS(_error_clipssys_envnoclear)
+#define ERROR_CLIPSSYS_BADENV() ERROR_CLIPS(_error_clipssys_badenv)
+#define ERROR_CLIPSSYS_CURENV() ERROR_CLIPS(_error_clipssys_curenv)
+#define ERROR_CLIPSSYS_MAXENV() ERROR_CLIPS(_error_clipssys_maxenv)
+#define ERROR_CLIPSSYS_CLEANUP() ERROR_CLIPS(_error_clipssys_cleanup)
+
+#define ERROR_CLIPSMEM_OUT() ERROR_CLIPS_MEMORY(_error_clipsmem_out)
+
+#define ERROR_ROUTER_INVALID() ERROR_CLIPS(_error_router_invalid)
+#define ERROR_ROUTER_NOSTREAM() ERROR_CLIPS(_error_router_nostream)
+#define ERROR_ROUTER_READONLY() ERROR_CLIPS(_error_router_readonly)
+
+
+/* unimplemented function builder */
+#define UNIMPLEMENT(s, sn) \
+    static char sn##__doc__[] = \
+    "unimplemented feature/function"; \
+    static PyObject *sn(PyObject *_self, PyObject *_args) { \
+        ERROR_UNIMPLEMENTED(); \
+        return NULL; \
+    }
+
+/* invalid CLIPS version function builder: the error string is hardcoded
+ * in order to avoid a warning
+ */
+#define UNIMPLEMENT_VERSION(s, sn) \
+    static char sn##__doc__[] = \
+    "higher engine version required for feature/function"; \
+    static PyObject *sn(PyObject *_self, PyObject *_args) { \
+        ERROR_CLIPS("C97: higher engine version required"); \
+        return NULL; \
+    }
+
+/* simplify writing entries in the method map */
+#define MMAP_ENTRY(s, sn) { #s, sn, METH_VARARGS, sn##__doc__ }
+
+/* check for no argument and fail if not */
+#define CHECK_NOARGS(_a) do { \
+    if(!PyArg_ParseTuple((_a), "")) FAIL(); } while(0)
+
+#ifdef ALLOW_CURRENT_ENVIRONMENT_ALIASING
+#define CHECK_NOCURENV(_e)
+#else
+/* check for environment not to be current and fail if it is */
+#define CHECK_NOCURENV(_e) do { \
+        if(clips_environment_value(_e) == GetCurrentEnvironment()) { \
+            ERROR_CLIPSSYS_CURENV(); \
+            FAIL(); \
+        } \
+    } while(0)
+#endif /* ALLOW_CURRENT_ENVIRONMENT_ALIASING */
+
+
+/* Macros to enable/disable memory checking on a per-function basis:
+ *  note that the second macro must always be used when the first is
+ *  used, and immediately after each memory allocating function has
+ *  been called. A good point to call the RELEASE part is just before
+ *  returning control to Python, while a good point to call ACQUIRE
+ *  is at the beginning of the memory allocating function.
+ */
+#ifdef USE_MEMORY_ERROR_HANDLER
+#define ACQUIRE_MEMORY_ERROR() do { \
+        if(setjmp(env_OutOfMemory)) { \
+            env_OutOfMemory_isSet = FALSE; \
+            ERROR_CLIPSMEM_OUT(); \
+            FAIL(); \
+        } else \
+            env_OutOfMemory_isSet = TRUE; \
+    } while(0)
+#define RELEASE_MEMORY_ERROR() env_OutOfMemory_isSet = FALSE
+#else
+#define ACQUIRE_MEMORY_ERROR()
+#define RELEASE_MEMORY_ERROR()
+#endif /* USE_MEMORY_ERROR_HANDLER */
+
+
+/* status function builder */
+#define FUNC_GET_ONLY(_py, _sn, _api, _type) \
+    static char _sn##__doc__[] = \
+    "" #_py "()\nequivalent of C API " #_api "()"; \
+    static PyObject *_sn(PyObject *_self, PyObject *_args) { \
+        int _i = 0; \
+        CHECK_NOARGS(_args); \
+        ACQUIRE_MEMORY_ERROR(); \
+        _i = _api(); \
+        RELEASE_MEMORY_ERROR(); \
+        return Py_BuildValue(_type, _i); \
+        BEGIN_FAIL \
+        END_FAIL \
+    }
+#define STATUS_FUNC_GET FUNC_GET_ONLY
+#define STATUS_FUNC_GET_BOOL(_py, _sn, _api) \
+    static char _sn##__doc__[] = \
+    "" #_py "() -> bool\nequivalent of C API " #_api "()"; \
+    static PyObject *_sn(PyObject *_self, PyObject *_args) { \
+        int _i = 0; \
+        CHECK_NOARGS(_args); \
+        ACQUIRE_MEMORY_ERROR(); \
+        _i = _api(); \
+        RELEASE_MEMORY_ERROR(); \
+        return Py_BuildValue("i", _i ? 1 : 0); \
+        BEGIN_FAIL \
+        END_FAIL \
+    }
+
+#define STATUS_FUNC_SET_BOOL(_py, _sn, _api) \
+    static char _sn##__doc__[] = \
+    "" #_py "()\nequivalent of C API " #_api "(bool)"; \
+    static PyObject *_sn(PyObject *_self, PyObject *_args) { \
+        PyObject *_o = NULL; \
+        if(!PyArg_ParseTuple(_args, "O", &_o)) \
+            FAIL(); \
+        ACQUIRE_MEMORY_ERROR(); \
+        _api(PyObject_IsTrue(_o)); \
+        RELEASE_MEMORY_ERROR(); \
+        RETURN_NONE(); \
+        BEGIN_FAIL \
+        END_FAIL \
+    }
+
+#define FUNC_VOID_BOOL(_py, _sn, _api) \
+    static char _sn##__doc__[] = \
+    "" #_py "()\nequivalent of C API " #_api "()"; \
+    static PyObject *_sn(PyObject *_self, PyObject *_args) { \
+        CHECK_NOARGS(_args); \
+        ACQUIRE_MEMORY_ERROR(); \
+        if(!_api()) { \
+            RELEASE_MEMORY_ERROR(); \
+            ERROR_CLIPS(_error_clips_impossible); \
+            FAIL(); \
+        } \
+        RELEASE_MEMORY_ERROR(); \
+        RETURN_NONE(); \
+        BEGIN_FAIL \
+        END_FAIL \
+    }
+#define FUNC_VOID_ONLY(_py, _sn, _api) \
+    static char _sn##__doc__[] = \
+    "" #_py "()\nequivalent of C API " #_api "()"; \
+    static PyObject *_sn(PyObject *_self, PyObject *_args) { \
+        CHECK_NOARGS(_args); \
+        ACQUIRE_MEMORY_ERROR(); \
+        _api(); \
+        RELEASE_MEMORY_ERROR(); \
+        RETURN_NONE(); \
+        BEGIN_FAIL \
+        END_FAIL \
+    }
+
+
+/* environment-version macros */
+/* status function builder */
+#define E_FUNC_GET_ONLY(_py, _sn, _api, _type) \
+    static char _sn##__doc__[] = \
+    "" #_py "()\nequivalent of C API " #_api "()"; \
+    static PyObject *_sn(PyObject *_self, PyObject *_args) { \
+        clips_EnvObject *_env = NULL; \
+        int _i = 0; \
+        if(!PyArg_ParseTuple(_args, "O!", &clips_EnvType, &_env)) \
+            FAIL(); \
+        ACQUIRE_MEMORY_ERROR(); \
+        _i = _api(clips_environment_value(_env)); \
+        RELEASE_MEMORY_ERROR(); \
+        return Py_BuildValue(_type, _i); \
+        BEGIN_FAIL \
+        END_FAIL \
+    }
+#define E_STATUS_FUNC_GET E_FUNC_GET_ONLY
+#define E_STATUS_FUNC_GET_BOOL(_py, _sn, _api) \
+    static char _sn##__doc__[] = \
+    "" #_py "() -> bool\nequivalent of C API " #_api "()"; \
+    static PyObject *_sn(PyObject *_self, PyObject *_args) { \
+        clips_EnvObject *_env = NULL; \
+        int _i = 0; \
+        if(!PyArg_ParseTuple(_args, "O!", &clips_EnvType, &_env)) \
+            FAIL(); \
+        ACQUIRE_MEMORY_ERROR(); \
+        _i = _api(clips_environment_value(_env)); \
+        RELEASE_MEMORY_ERROR(); \
+        return Py_BuildValue("i", _i ? 1 : 0); \
+        BEGIN_FAIL \
+        END_FAIL \
+    }
+
+#define E_STATUS_FUNC_SET_BOOL(_py, _sn, _api) \
+    static char _sn##__doc__[] = \
+    "" #_py "()\nequivalent of C API " #_api "(bool)"; \
+    static PyObject *_sn(PyObject *_self, PyObject *_args) { \
+        PyObject *_o = NULL; \
+        clips_EnvObject *_env = NULL; \
+        if(!PyArg_ParseTuple(_args, "O!O", &clips_EnvType, &_env, &_o)) \
+            FAIL(); \
+        CHECK_NOCURENV(_env); \
+        ACQUIRE_MEMORY_ERROR(); \
+        _api(clips_environment_value(_env), PyObject_IsTrue(_o)); \
+        RELEASE_MEMORY_ERROR(); \
+        RETURN_NONE(); \
+        BEGIN_FAIL \
+        END_FAIL \
+    }
+
+#define E_FUNC_VOID_BOOL(_py, _sn, _api) \
+    static char _sn##__doc__[] = \
+    "" #_py "()\nequivalent of C API " #_api "()"; \
+    static PyObject *_sn(PyObject *_self, PyObject *_args) { \
+        clips_EnvObject *_env = NULL; \
+        if(!PyArg_ParseTuple(_args, "O!", &clips_EnvType, &_env)) \
+            FAIL(); \
+        CHECK_NOCURENV(_env); \
+        ACQUIRE_MEMORY_ERROR(); \
+        if(!_api(clips_environment_value(_env))) { \
+            ERROR_CLIPS(_error_clips_impossible); \
+            RELEASE_MEMORY_ERROR(); \
+            FAIL(); \
+        } \
+        RELEASE_MEMORY_ERROR(); \
+        RETURN_NONE(); \
+        BEGIN_FAIL \
+        END_FAIL \
+    }
+#define E_FUNC_VOID_ONLY(_py, _sn, _api) \
+    static char _sn##__doc__[] = \
+    "" #_py "()\nequivalent of C API " #_api "()"; \
+    static PyObject *_sn(PyObject *_self, PyObject *_args) { \
+        clips_EnvObject *_env = NULL; \
+        if(!PyArg_ParseTuple(_args, "O!", &clips_EnvType, &_env)) \
+            FAIL(); \
+        CHECK_NOCURENV(_env); \
+        ACQUIRE_MEMORY_ERROR(); \
+        _api(clips_environment_value(_env)); \
+        RELEASE_MEMORY_ERROR(); \
+        RETURN_NONE(); \
+        BEGIN_FAIL \
+        END_FAIL \
+    }
+
+
+/* macros used to verify if objects are being garbaged */
+#define CHECK_VALID_FACT(_o) do { \
+        if(!FactExistp(clips_fact_value(_o))) { \
+            ERROR_CLIPSSYS_GARBFACT(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define ENV_CHECK_VALID_FACT(_e, _o) do { \
+        if(!EnvFactExistp(_e, clips_fact_value(_o))) { \
+            ERROR_CLIPSSYS_GARBFACT(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define CHECK_VALID_INSTANCE(_o) do { \
+        if(!ValidInstanceAddress(clips_instance_value(_o))) { \
+            ERROR_CLIPSSYS_GARBINSTANCE(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define ENV_CHECK_VALID_INSTANCE(_e, _o) do { \
+        if(!EnvValidInstanceAddress(_e, clips_instance_value(_o))) { \
+            ERROR_CLIPSSYS_GARBINSTANCE(); \
+            FAIL(); \
+        } \
+    } while(0)
+
+
+/* the following can be helpful when allocating objects */
+#ifdef USE_PYTHON_MEMMGR
+#ifdef NEW
+#undef NEW
+#endif /* NEW */
+#define NEW(x) PyMem_New(x, 1)
+#ifdef NEW_ARRAY
+#undef NEW_ARRAY
+#endif /* NEW_ARRAY */
+#define NEW_ARRAY(x, n) PyMem_New(x, (n))
+#ifdef DELETE
+#undef DELETE
+#endif /* DELETE */
+#define DELETE(x) PyMem_Del(x)
+#ifdef REALLOC
+#undef REALLOC
+#endif /* REALLOC */
+#define REALLOC(p, n) PyMem_Realloc((p), (n))
+#ifdef MALLOC
+#undef MALLOC
+#endif /* MALLOC */
+#define MALLOC(s) PyMem_Malloc(s)
+#ifdef FREE
+#undef FREE
+#endif /* FREE */
+#define FREE(p) PyMem_Free(p)
+#else
+#ifdef NEW
+#undef NEW
+#endif /* NEW */
+#define NEW(x) (((x) *)malloc(sizeof(x)))
+#ifdef NEW_ARRAY
+#undef NEW_ARRAY
+#endif /* NEW_ARRAY */
+#define NEW_ARRAY(x, n) ((x *)malloc((n) * sizeof(x)))
+#ifdef DELETE
+#undef DELETE
+#endif /* DELETE */
+#define DELETE(x) free(x)
+#ifdef REALLOC
+#undef REALLOC
+#endif /* REALLOC */
+#define REALLOC(p, n) realloc((p), (n))
+#ifdef MALLOC
+#undef MALLOC
+#endif /* MALLOC */
+#define MALLOC(s) malloc(s)
+#ifdef FREE
+#undef FREE
+#endif /* FREE */
+#define FREE(p) free(p)
+#endif
+
+
+#ifdef BYTE
+#undef BYTE
+#define BYTE unsigned char
+#endif
+
+
+/* the boolean values */
+#ifndef BOOL
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif
+
+/* maximum supported references */
+#define MAX_REFERENCES (INT_MAX - 1)
+
+/* position of stray fact pointer in CLIPS environment */
+#ifdef USE_NONASSERT_CLIPSGCLOCK
+#define STRAYFACTS_DATA (USER_ENVIRONMENT_DATA + 0)
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+
+/* length of buffers used for string operations */
+static size_t ppbuffer_size = INITIAL_PPBUFFER_SIZE;
+
+/* flag to state whether or not fatal environment errors must be shown */
+static BOOL clips_ShowEnvironmentFatalErrors = FALSE;
+
+
+/* Part One: module internals and helpers */
+
+
+/* The following jump point is used to ensure memory error handling */
+#ifdef USE_MEMORY_ERROR_HANDLER
+static jmp_buf env_OutOfMemory;
+static BOOL env_OutOfMemory_isSet = FALSE;
+#endif /* USE_MEMORY_ERROR_HANDLER */
+
+
+/* This function should be used instead of the standard memory allocator
+ *  within CLIPS in order to let memory errors to be correctly reported by
+ *  Python instead of exiting abnormally. This function is tightly coupled
+ *  with the "out of memory function" implemented here, that jumps back to
+ *  the above defined jump point.
+ */
+void *PyCLIPS_Malloc(size_t s) {
+#ifdef USE_MEMORY_ERROR_HANDLER
+    void *p = MALLOC(s);
+    if(!p && env_OutOfMemory_isSet)
+        longjmp(env_OutOfMemory, 1);
+    return p;
+#else
+    return MALLOC(s);
+#endif /* USE_MEMORY_ERROR_HANDLER */
+}
+void PyCLIPS_Free(void *p) {
+    FREE(p);
+}
+
+
+/* The following function queries the above defined flag to test whether or
+ *  not to show fatal environment errors on stderr (on a patched CLIPS source,
+ *  of course: the unpatched source will have the usual behaviour to write a
+ *  message on stdout) and is called directly by CLIPS before writing anything.
+ */
+int PyCLIPS_EnableFatal(void) {
+#ifdef USE_FATAL_ERROR_INHIBITION
+    return clips_ShowEnvironmentFatalErrors;
+#else
+    return TRUE;
+#endif /* USE_FATAL_ERROR_INHIBITION */
+}
+
+
+/* THE FOLLOWING ARE DEFINED HERE AS IN CLIPS main.c */
+
+/*********************************************************/
+/* UserFunctions: Informs the expert system environment  */
+/*   of any user defined functions. In the default case, */
+/*   there are no user defined functions. To define      */
+/*   functions, either this function must be replaced by */
+/*   a function with the same name within this file, or  */
+/*   this function can be deleted from this file and     */
+/*   included in another file.                           */
+/*********************************************************/
+void UserFunctions(void) { }
+
+
+/***********************************************************/
+/* EnvUserFunctions: Informs the expert system environment */
+/*   of any user defined functions. In this case, there is */
+/*   only a function which invokes real Python functions.  */
+/***********************************************************/
+void EnvPythonExternalCall(void *, DATA_OBJECT_PTR);
+void EnvUserFunctions(void *env) {
+    EnvDefineFunction2(env, "python-call", 'u', PTIEF EnvPythonExternalCall,
+                       "EnvPythonExternalCall", "1*uw");
+}
+
+
+/* NOTE:
+ *  The following literally included file contains a rough implementation
+ *  of an hash-table driven method of storing pointers in order to possibly
+ *  apply a function to all contained elements. This is done in order to
+ *  avoid access violations when accessing fact objects after a call to the
+ *  CLIPS Clear() function. The behaviour of CLIPS in this occasion is known
+ *  and not considered a bug; however there is no way to determine whether
+ *  or not a fact has still valid slots or not. Keeping track of which facts
+ *  have still not been asserted seemed the only way to determine when they
+ *  could be corrupted. Of course this is a time consuming operation, but
+ *  handling it via the structure define in "loptr.c" seemed a way to keep
+ *  the time overhead as small as possible. Most of the "time waste" occurs
+ *  when either Assert() or CreateFact() or Clear() are called.
+ */
+#ifdef USE_NONASSERT_CLIPSGCLOCK
+#include "loptr.c"
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+
+
+
+/* a Python type representing a standalone CLIPS environment */
+staticforward PyTypeObject clips_EnvType;
+
+typedef struct {
+    PyObject_HEAD
+    void *value;
+    BOOL valid;
+#ifdef USE_NONASSERT_CLIPSGCLOCK
+    unsigned long clips_NotAssertedFacts;
+    BOOL clips_GCLocked;
+    LOPTR_HASH_TABLE(clips_StrayFacts);
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+} clips_EnvObject;
+
+#define clips_environment_value(v) (((clips_EnvObject *)(v))->value)
+#define clips_environment_valid(v) (((clips_EnvObject *)(v))->valid)
+#define clips_environment_check(v) \
+    (((v)->ob_type == &clips_EnvType) && clips_environment_valid(v))
+
+#ifdef USE_NONASSERT_CLIPSGCLOCK
+#define clips_environment_New(p) \
+    do { \
+        p = PyObject_New(clips_EnvObject, &clips_EnvType); \
+        if(p) { \
+            clips_environment_valid(p) = TRUE; \
+            p->clips_NotAssertedFacts = 0;\
+            p->clips_GCLocked = FALSE; \
+            INIT_LOPTR_HASH_TABLE(p->clips_StrayFacts); \
+        } \
+    } while(0)
+#define CLEAR_LOST_FACTS() LOPTR_reset_hash_table(clips_StrayFacts)
+#define ENV_CLEAR_LOST_FACTS(_pe) \
+    LOPTR_reset_hash_table((_pe)->clips_StrayFacts)
+#else
+#define clips_environment_New(p) \
+    do { \
+        p = PyObject_New(clips_EnvObject, &clips_EnvType); \
+        if(p) \
+            clips_environment_valid(p) = TRUE; \
+    } while(0)
+#define CLEAR_LOST_FACTS()
+#define ENV_CLEAR_LOST_FACTS(_pe)
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+
+static void clips_EnvObject_dealloc(PyObject *self) {
+    /* only the Python object is destroyed: environments are forever */
+    ENV_CLEAR_LOST_FACTS((clips_EnvObject *)self);
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_EnvType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "environment",
+    sizeof(clips_EnvObject),
+    0,
+    clips_EnvObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS deftemplate object */
+staticforward PyTypeObject clips_DeftemplType;
+
+typedef struct {
+    PyObject_HEAD
+    void *value;
+} clips_DeftemplObject;
+
+#define clips_deftemplate_check(v) ((v)->ob_type == &clips_DeftemplType)
+#define clips_deftemplate_value(v) (((clips_DeftemplObject *)(v))->value)
+
+#define clips_deftemplate_New(p) \
+    p = PyObject_New(clips_DeftemplObject, &clips_DeftemplType)
+
+static void clips_DeftemplObject_dealloc(PyObject *self) {
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_DeftemplType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "deftemplate",
+    sizeof(clips_DeftemplObject),
+    0,
+    clips_DeftemplObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS fact object */
+staticforward PyTypeObject clips_FactType;
+
+typedef struct {
+    PyObject_HEAD
+    BOOL readonly;
+    BOOL locked;
+    void *value;
+    void *creation_env;
+#ifdef USE_NONASSERT_CLIPSGCLOCK
+    BOOL lost;
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+} clips_FactObject;
+
+#define clips_fact_check(v) ((v)->ob_type == &clips_FactType)
+#define clips_fact_value(v) (((clips_FactObject *)(v))->value)
+#define clips_fact_env(v) (((clips_FactObject *)(v))->creation_env)
+#define clips_fact_readonly(v) (((clips_FactObject *)(v))->readonly)
+#define clips_fact_verify(v) (!((struct fact *) \
+                              (((clips_FactObject *)(v))->value))->garbage)
+
+/* assign a pointer to a CLIPS fact to this object */
+#define clips_fact_assign(e, p) do { \
+        EnvIncrementFactCount(clips_fact_env(e), p); \
+        clips_fact_value(e) = p; \
+    } while(0)
+
+/* lock/unlock a fact object */
+#define clips_fact_locked(v) (((clips_FactObject *)(v))->locked)
+#define clips_fact_lock(v) do { \
+        ((clips_FactObject *)(v))->locked = TRUE; \
+    } while(0)
+#define clips_fact_unlock(v) do { \
+        ((clips_FactObject *)(v))->locked = FALSE; \
+    } while(0)
+
+/* facts behave differently than instances upon call to Clear */
+#ifdef USE_NONASSERT_CLIPSGCLOCK
+#define clips_fact_lost(v) (((clips_FactObject *)(v))->lost)
+#define clips_fact_New(e, p) do { \
+        p = PyObject_New(clips_FactObject, &clips_FactType); \
+        clips_fact_readonly(p) = FALSE; \
+        clips_fact_lost(p) = FALSE; \
+        clips_fact_env(p) = e; \
+        clips_fact_value(p) = NULL; \
+        clips_fact_locked(p) = FALSE; \
+    } while(0)
+
+/* This function will be called for every not asserted fact upon clear:
+ *  it has to be a function (and not an inlineable one) because its address
+ *  will be passed to a function that calls it for each fact that is
+ *  supposedly lost. Moreover, although we actually don't need it, the
+ *  function has to be a BOOL()(void *), since this is the accepted type
+ *  for the final calling function.
+ */
+static BOOL lose_fact(void *p) {
+    clips_fact_lost(p) = TRUE;  /* explicitly casts to clips_FactObject */
+    return TRUE;
+}
+
+#else
+#define clips_fact_New(e, p) do { \
+        p = PyObject_New(clips_FactObject, &clips_FactType); \
+        clips_fact_readonly(p) = FALSE; \
+        clips_fact_env(p) = e; \
+        clips_fact_value(p) = NULL; \
+        clips_fact_locked(p) = FALSE; \
+    } while(0)
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+
+#ifdef USE_NONASSERT_CLIPSGCLOCK
+/* allow to assert facts without losing defined but non asserted ones */
+
+static unsigned long clips_NotAssertedFacts = 0;
+static BOOL clips_GCLocked = FALSE;
+LOPTR_HASH_TABLE(clips_StrayFacts) = { 0 };
+
+F_INLINE void clips_lock_gc(clips_EnvObject *pyenv) {
+    if(pyenv) {
+        if(!pyenv->clips_GCLocked && pyenv->clips_NotAssertedFacts > 0) {
+            EnvIncrementGCLocks(clips_environment_value(pyenv));
+            pyenv->clips_GCLocked = TRUE;
+        }
+    } else {
+        if(!clips_GCLocked && clips_NotAssertedFacts > 0) {
+            IncrementGCLocks();
+            clips_GCLocked = TRUE;
+        }
+    }
+}
+F_INLINE void clips_unlock_gc(clips_EnvObject *pyenv) {
+    if(pyenv) {
+        if(pyenv->clips_GCLocked && pyenv->clips_NotAssertedFacts == 0) {
+            pyenv->clips_GCLocked = FALSE;
+            EnvDecrementGCLocks(clips_environment_value(pyenv));
+        }
+    } else {
+        if(clips_GCLocked && clips_NotAssertedFacts == 0) {
+            clips_GCLocked = FALSE;
+            DecrementGCLocks();
+        }
+    }
+}
+F_INLINE BOOL add_FactObject_lock(clips_EnvObject *pyenv) {
+    if(pyenv)
+        pyenv->clips_NotAssertedFacts++;
+    else
+        clips_NotAssertedFacts++;
+    return TRUE;
+}
+F_INLINE BOOL remove_FactObject_lock(clips_EnvObject *pyenv) {
+    if(pyenv) {
+        if(pyenv->clips_NotAssertedFacts > 0) {
+            pyenv->clips_NotAssertedFacts--;
+            return TRUE;
+        }
+    } else {
+        if(clips_NotAssertedFacts > 0) {
+            clips_NotAssertedFacts--;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+F_INLINE BOOL reset_FactObject_lock(clips_EnvObject *pyenv) {
+    if(pyenv) {
+        if(pyenv->clips_NotAssertedFacts > 0) {
+            pyenv->clips_NotAssertedFacts = 0;
+            if(pyenv->clips_GCLocked) {
+                pyenv->clips_GCLocked = FALSE;
+                EnvDecrementGCLocks(clips_environment_value(pyenv));
+            }
+            return TRUE;
+        }
+    } else {
+        if(clips_NotAssertedFacts > 0) {
+            clips_NotAssertedFacts = 0;
+            if(clips_GCLocked) {
+                clips_GCLocked = FALSE;
+                DecrementGCLocks();
+            }
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+/* through the loptr.c utility we can check whether or not a fact is lost */
+#define APPEND_HASH_FACT(_p) LOPTR_append(clips_StrayFacts, (void *)(_p))
+#define REMOVE_HASH_FACT(_p) LOPTR_remove(clips_StrayFacts, (void *)(_p))
+#define LOSE_HASH_FACTS() LOPTR_apply(clips_StrayFacts, lose_fact)
+#define ENV_APPEND_HASH_FACT(_pe, _p) \
+    LOPTR_append((_pe)->clips_StrayFacts, (void *)(_p))
+#define ENV_REMOVE_HASH_FACT(_pe, _p) \
+    LOPTR_remove((_pe)->clips_StrayFacts, (void *)(_p))
+#define ENV_LOSE_HASH_FACTS(_pe) \
+    LOPTR_apply((_pe)->clips_StrayFacts, lose_fact)
+/* the following is needed for facts to auto-deregister */
+#define SPEC_REMOVE_HASH_FACT(_sfl, _p) LOPTR_remove((_sfl), (void *)(_p))
+
+/* check if a fact is lost: the ENV version is for completeness only */
+#define CHECK_LOST_FACT(_o) do { \
+        if(clips_fact_lost(_o)) { \
+            ERROR_CLIPSSYS_GARBFACT(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define ENV_CHECK_LOST_FACT(_e, _o) do { \
+        if(clips_fact_lost(_o)) { \
+            ERROR_CLIPSSYS_GARBFACT(); \
+            FAIL(); \
+        } \
+    } while(0)
+
+/* and these are needed to inform the system about creation or assertion */
+#define ADD_NONASSERTED_FACT() add_FactObject_lock(NULL)
+#define REMOVE_JUSTASSERTED_FACT() remove_FactObject_lock(NULL)
+#define ENV_ADD_NONASSERTED_FACT(_pe) add_FactObject_lock(_pe)
+#define ENV_REMOVE_JUSTASSERTED_FACT(_pe) remove_FactObject_lock(_pe)
+
+#define RESET_ASSERTED_FACTS() reset_FactObject_lock(NULL)
+#define ENV_RESET_ASSERTED_FACTS(_pe) reset_FactObject_lock(_pe)
+
+#define CLIPS_LOCK_GC() clips_lock_gc(NULL)
+#define CLIPS_UNLOCK_GC() clips_unlock_gc(NULL)
+#define ENV_CLIPS_LOCK_GC(_pe) clips_lock_gc(_pe)
+#define ENV_CLIPS_UNLOCK_GC(_pe) clips_unlock_gc(_pe)
+
+#define COPY_ADDITIONAL_ENVIRONMENT_DATA(_pe) do \
+    { \
+        clips_NotAssertedFacts = (_pe)->clips_NotAssertedFacts; \
+        clips_GCLocked = (_pe)->clips_GCLocked; \
+        COPY_LOPTR_HASH_TABLE(clips_StrayFacts, (_pe)->clips_StrayFacts); \
+    } while(0)
+#define INJECT_ADDITIONAL_ENVIRONMENT_DATA(_pe) do \
+    { \
+        (_pe)->clips_NotAssertedFacts = clips_NotAssertedFacts; \
+        (_pe)->clips_GCLocked = clips_GCLocked; \
+        COPY_LOPTR_HASH_TABLE((_pe)->clips_StrayFacts, clips_StrayFacts); \
+    } while(0)
+
+#else
+
+/* symbols to always force that garbage collector in CLIPS to be locked */
+#ifdef USE_CLIPSGCLOCK
+#define CLIPS_LOCK_GC() IncrementGCLocks()
+#define CLIPS_UNLOCK_GC() DecrementGCLocks()
+#define ENV_CLIPS_LOCK_GC(_pe) EnvIncrementGCLocks(clips_environment_value(_pe))
+#define ENV_CLIPS_UNLOCK_GC(_pe) EnvDecrementGCLocks(clips_environment_value(_pe))
+#else
+#define CLIPS_LOCK_GC()
+#define CLIPS_UNLOCK_GC()
+#define ENV_CLIPS_LOCK_GC(_pe)
+#define ENV_CLIPS_UNLOCK_GC(_pe)
+#endif /* USE_CLIPSGCLOCK */
+
+#define ADD_NONASSERTED_FACT()
+#define REMOVE_JUSTASSERTED_FACT()
+#define RESET_ASSERTED_FACTS()
+#define ENV_ADD_NONASSERTED_FACT(_pe)
+#define ENV_REMOVE_JUSTASSERTED_FACT(_pe)
+#define ENV_RESET_ASSERTED_FACTS(_pe)
+
+#define COPY_ADDITIONAL_ENVIRONMENT_DATA(_pe)
+#define INJECT_ADDITIONAL_ENVIRONMENT_DATA(_pe)
+
+#define APPEND_HASH_FACT(_p)
+#define REMOVE_HASH_FACT(_p)
+#define LOSE_HASH_FACTS()
+#define ENV_APPEND_HASH_FACT(_pe, _p)
+#define ENV_REMOVE_HASH_FACT(_pe, _p)
+#define SPEC_REMOVE_HASH_FACT(_sfl, _p)
+#define ENV_LOSE_HASH_FACTS(_pe)
+#define CHECK_LOST_FACT(_o)
+#define ENV_CHECK_LOST_FACT(_e, _o)
+
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+
+/* The fact removal process might seem tricky. However there is a reason
+ *  for this complicated routine: when a fact is created, and before its
+ *  assertion, it is put in the fact hash map in order to be invalidated
+ *  during actions that would cause a CLIPS garbage collection (see comments
+ *  above). Whenever a Python Fact object is destroyed, it has to deregister
+ *  itself from the corresponding hash map. Information about the said hash
+ *  map is carried along with the CLIPS managed environment, via specifically
+ *  allocated data - which just contains a pointer to the corresponding map.
+ *  That a fact at the end contains information about its hash map is not a
+ *  problem when environments are made current: all data in the Environment
+ *  object (note the capital E, for Python corresponding objects) is copied
+ *  to the current Environment, including the hash map (clips_StrayFacts),
+ *  and everything remains consistent.
+ */
+static void clips_FactObject_dealloc(PyObject *self) {
+    void *p = clips_fact_value(self);
+#ifdef USE_NONASSERT_CLIPSGCLOCK
+    LOPTR_ITEM ***hm = 
+        (LOPTR_ITEM ***)GetEnvironmentData(
+            clips_fact_env(self), STRAYFACTS_DATA);
+    SPEC_REMOVE_HASH_FACT(*hm, self);
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+    if(p)
+        EnvDecrementFactCount(clips_fact_env(self), p);
+    clips_fact_unlock(self);
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_FactType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "fact",
+    sizeof(clips_FactObject),
+    0,
+    clips_FactObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS address object */
+staticforward PyTypeObject clips_AddressType;
+
+typedef struct {
+    PyObject_HEAD
+    int ob_addrtype;
+    void *value;
+} clips_AddressObject;
+
+#define clips_address_check(v) ((v)->ob_type == &clips_AddressType)
+#define clips_address_value(v) (((clips_AddressObject *)(v))->value)
+#define clips_address_addrtype(v) (((clips_AddressObject *)(v))->ob_addrtype)
+
+#define clips_address_New(p) do { \
+        p = PyObject_New(clips_AddressObject, &clips_AddressType); \
+        clips_address_addrtype(p) = 0; \
+    } while(0)
+
+static void clips_AddressObject_dealloc(PyObject *self) {
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_AddressType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "address",
+    sizeof(clips_AddressObject),
+    0,
+    clips_AddressObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS deffacts object */
+staticforward PyTypeObject clips_DeffactsType;
+
+typedef struct {
+    PyObject_HEAD
+    void *value;
+} clips_DeffactsObject;
+
+#define clips_deffacts_check(v) ((v)->ob_type == &clips_DeffactsType)
+#define clips_deffacts_value(v) (((clips_DeffactsObject *)(v))->value)
+
+#define clips_deffacts_New(p) \
+    p = PyObject_New(clips_DeffactsObject, &clips_DeffactsType)
+
+static void clips_DeffactsObject_dealloc(PyObject *self) {
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_DeffactsType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "deffacts",
+    sizeof(clips_DeffactsObject),
+    0,
+    clips_DeffactsObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS defrule object */
+staticforward PyTypeObject clips_DefruleType;
+
+typedef struct {
+    PyObject_HEAD
+    void *value;
+} clips_DefruleObject;
+
+#define clips_defrule_check(v) ((v)->ob_type == &clips_DeffactsType)
+#define clips_defrule_value(v) (((clips_DefruleObject *)(v))->value)
+
+#define clips_defrule_New(p) \
+    p = PyObject_New(clips_DefruleObject, &clips_DefruleType)
+
+static void clips_DefruleObject_dealloc(PyObject *self) {
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_DefruleType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "defrule",
+    sizeof(clips_DefruleObject),
+    0,
+    clips_DefruleObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS activation object */
+staticforward PyTypeObject clips_ActivationType;
+
+typedef struct {
+    PyObject_HEAD
+    void *value;
+} clips_ActivationObject;
+
+#define clips_activation_check(v) ((v)->ob_type == &clips_ActivationType)
+#define clips_activation_value(v) (((clips_ActivationObject *)(v))->value)
+
+#define clips_activation_New(p) \
+    p = PyObject_New(clips_ActivationObject, &clips_ActivationType)
+
+static void clips_ActivationObject_dealloc(PyObject *self) {
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_ActivationType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "activation",
+    sizeof(clips_ActivationObject),
+    0,
+    clips_ActivationObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS defglobal object */
+staticforward PyTypeObject clips_DefglobalType;
+
+typedef struct {
+    PyObject_HEAD
+    void *value;
+} clips_DefglobalObject;
+
+#define clips_defglobal_check(v) ((v)->ob_type == &clips_DefglobalType)
+#define clips_defglobal_value(v) (((clips_DefglobalObject *)(v))->value)
+
+#define clips_defglobal_New(p) \
+    p = PyObject_New(clips_DefglobalObject, &clips_DefglobalType)
+
+static void clips_DefglobalObject_dealloc(PyObject *self) {
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_DefglobalType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "defglobal",
+    sizeof(clips_DefglobalObject),
+    0,
+    clips_DefglobalObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS deffunction object */
+staticforward PyTypeObject clips_DeffunctionType;
+
+typedef struct {
+    PyObject_HEAD
+    void *value;
+} clips_DeffunctionObject;
+
+#define clips_deffunction_check(v) ((v)->ob_type == &clips_DeffunctionType)
+#define clips_deffunction_value(v) (((clips_DeffunctionObject *)(v))->value)
+
+#define clips_deffunction_New(p) \
+    p = PyObject_New(clips_DeffunctionObject, &clips_DeffunctionType)
+
+static void clips_DeffunctionObject_dealloc(PyObject *self) {
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_DeffunctionType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "deffunction",
+    sizeof(clips_DeffunctionObject),
+    0,
+    clips_DeffunctionObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS defgeneric object */
+staticforward PyTypeObject clips_DefgenericType;
+
+typedef struct {
+    PyObject_HEAD
+    void *value;
+} clips_DefgenericObject;
+
+#define clips_defgeneric_check(v) ((v)->ob_type == &clips_DefgenericType)
+#define clips_defgeneric_value(v) (((clips_DefgenericObject *)(v))->value)
+
+#define clips_defgeneric_New(p) \
+    p = PyObject_New(clips_DefgenericObject, &clips_DefgenericType)
+
+static void clips_DefgenericObject_dealloc(PyObject *self) {
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_DefgenericType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "defgeneric",
+    sizeof(clips_DefgenericObject),
+    0,
+    clips_DefgenericObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS defmethod object */
+staticforward PyTypeObject clips_DefmethodType;
+
+typedef struct {
+    PyObject_HEAD
+    void *value;
+} clips_DefmethodObject;
+
+#define clips_defmethod_check(v) ((v)->ob_type == &clips_DefmethodType)
+#define clips_defmethod_value(v) (((clips_DefmethodObject *)(v))->value)
+
+#define clips_defmethod_New(p) \
+    p = PyObject_New(clips_DefmethodObject, &clips_DefmethodType)
+
+static void clips_DefmethodObject_dealloc(PyObject *self) {
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_DefmethodType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "defmethod",
+    sizeof(clips_DefmethodObject),
+    0,
+    clips_DefmethodObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS defclass object */
+staticforward PyTypeObject clips_DefclassType;
+
+typedef struct {
+    PyObject_HEAD
+    void *value;
+} clips_DefclassObject;
+
+#define clips_defclass_check(v) ((v)->ob_type == &clips_DefclassType)
+#define clips_defclass_value(v) (((clips_DefclassObject *)(v))->value)
+
+#define clips_defclass_New(p) \
+    p = PyObject_New(clips_DefclassObject, &clips_DefclassType)
+
+static void clips_DefclassObject_dealloc(PyObject *self) {
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_DefclassType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "defclass",
+    sizeof(clips_DefclassObject),
+    0,
+    clips_DefclassObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS instance object */
+staticforward PyTypeObject clips_InstanceType;
+
+typedef struct {
+    PyObject_HEAD
+    BOOL locked;
+    void *value;
+    void *creation_env;
+} clips_InstanceObject;
+
+#define clips_instance_check(v) ((v)->ob_type == &clips_InstanceType)
+#define clips_instance_value(v) (((clips_InstanceObject *)(v))->value)
+#define clips_instance_env(v) (((clips_InstanceObject *)(v))->creation_env)
+#define clips_instance_verify(v) (!((struct instance *) \
+                                  (((clips_InstanceObject *)(v))->value))->garbage)
+
+/* assign a pointer to a CLIPS instance to this object */
+#define clips_instance_assign(v, p) do { \
+        EnvIncrementInstanceCount(clips_instance_env(v), p); \
+        clips_instance_value(v) = p; \
+    } while(0)
+
+/* lock/unlock an instance object */
+#define clips_instance_locked(v) (((clips_InstanceObject *)(v))->locked)
+#define clips_instance_lock(v) do { \
+        ((clips_InstanceObject *)(v))->locked = TRUE; \
+    } while(0)
+#define clips_instance_unlock(v) do { \
+        ((clips_InstanceObject *)(v))->locked = FALSE; \
+    } while(0)
+
+#define clips_instance_New(env, p) do { \
+        p = PyObject_New(clips_InstanceObject, &clips_InstanceType); \
+        clips_instance_env(p) = env; \
+        clips_instance_value(p) = NULL; \
+        ((clips_InstanceObject *)(p))->locked = FALSE; \
+    } while(0)
+
+static void clips_InstanceObject_dealloc(PyObject *self) {
+    void *p = clips_instance_value(self);
+    if(p)
+        EnvDecrementInstanceCount(clips_instance_env(self), p);
+    clips_instance_unlock(self);
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_InstanceType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "instance",
+    sizeof(clips_InstanceObject),
+    0,
+    clips_InstanceObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS definstances object */
+staticforward PyTypeObject clips_DefinstancesType;
+
+typedef struct {
+    PyObject_HEAD
+    void *value;
+} clips_DefinstancesObject;
+
+#define clips_definstances_check(v) ((v)->ob_type == &clips_DefinstancesType)
+#define clips_definstances_value(v) (((clips_DefinstancesObject *)(v))->value)
+
+#define clips_definstances_New(p) \
+    p = PyObject_New(clips_DefinstancesObject, &clips_DefinstancesType)
+
+static void clips_DefinstancesObject_dealloc(PyObject *self) {
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_DefinstancesType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "definstances",
+    sizeof(clips_DefinstancesObject),
+    0,
+    clips_DefinstancesObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* a Python Type representing a CLIPS defmodule object */
+staticforward PyTypeObject clips_DefmoduleType;
+
+typedef struct {
+    PyObject_HEAD
+    void *value;
+} clips_DefmoduleObject;
+
+#define clips_defmodule_check(v) ((v)->ob_type == &clips_DefmoduleType)
+#define clips_defmodule_value(v) (((clips_DefmoduleObject *)(v))->value)
+
+#define clips_defmodule_New(p) \
+    p = PyObject_New(clips_DefmoduleObject, &clips_DefmoduleType)
+
+static void clips_DefmoduleObject_dealloc(PyObject *self) {
+    PyObject_Del(self);
+}
+
+static PyTypeObject clips_DefmoduleType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "defmodule",
+    sizeof(clips_DefmoduleObject),
+    0,
+    clips_DefmoduleObject_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* ATTENTION!
+ *  all the following helpers do not acquire the memory error handler function
+ *  because they are internal helpers: however all functions that invoke these
+ *  helpers (in both directions) should actually take care of the acquisition.
+ */
+
+/* helpers to convert DATA_OBJECTs into Python objects */
+PyObject *i_do2py_mfhelp_e(void *env, void *ptr, int pos) {
+    PyObject *p = NULL;
+    int t = GetMFType(ptr, pos);
+    clips_AddressObject *a = NULL;
+    clips_FactObject *fo = NULL;
+    clips_InstanceObject *io = NULL;
+
+    /* check for return type and build a PyObject to return */
+    switch(t) {
+    case INTEGER:
+        p = Py_BuildValue("(ii)", t, ValueToLong(GetMFValue(ptr, pos)));
+        break;
+    case FLOAT:
+        p = Py_BuildValue("(id)", t, ValueToDouble(GetMFValue(ptr, pos)));
+        break;
+    case STRING:
+    case SYMBOL:
+    case INSTANCE_NAME:
+        p = Py_BuildValue("(is)", t, ValueToString(GetMFValue(ptr, pos)));
+        break;
+    case INSTANCE_ADDRESS:
+        if(!ptr)
+            FAIL();
+        if(env) {
+            clips_instance_New(env, io);
+            if(!io)
+                FAIL();
+            clips_instance_assign(io, GetMFValue(ptr, pos));
+            ENV_CHECK_VALID_INSTANCE(env, io);
+        } else {
+            clips_instance_New(GetCurrentEnvironment(), io);
+            if(!io)
+                FAIL();
+            clips_instance_assign(io, GetMFValue(ptr, pos));
+            CHECK_VALID_INSTANCE(io);
+        }
+        clips_instance_lock(io);
+        p = Py_BuildValue("(iO)", t, clips_instance_value(io));
+        break;
+    case EXTERNAL_ADDRESS:
+        if(!ptr)
+            FAIL();
+        clips_address_New(a);
+        if(!a)
+            FAIL();
+        clips_address_addrtype(a) = t;
+        clips_address_value(a) = GetMFValue(ptr, pos);
+        p = Py_BuildValue("(iO)", t, a);
+        break;
+    case FACT_ADDRESS:
+        if(!ptr)
+            FAIL();
+        if(env) {
+            clips_fact_New(env, fo);
+            if(!fo)
+                FAIL();
+            clips_fact_assign(fo, GetMFValue(ptr, pos));
+            ENV_CHECK_VALID_FACT(env, fo);
+        } else {
+            clips_fact_New(GetCurrentEnvironment(), fo);
+            if(!fo)
+                FAIL();
+            clips_fact_assign(fo, GetMFValue(ptr, pos));
+            CHECK_VALID_FACT(fo);
+        }
+        clips_fact_readonly(fo) = TRUE;
+        clips_fact_lock(fo);
+        p = Py_BuildValue("(iO)", t, fo);
+        break;
+    case MULTIFIELD:
+        FAIL();     /* this should not be called for MFs */
+        break;
+    default:
+        FAIL();     /* something wrong? */
+        break;
+    }
+
+    return p;
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+    Py_XDECREF(a);
+    Py_XDECREF(io);
+    Py_XDECREF(fo);
+END_FAIL
+}
+
+
+PyObject *i_do2py_e(void *env, DATA_OBJECT *o) {
+    PyObject *p = NULL, *p1 = NULL, *q = NULL;
+    void *ptr = NULL;
+    int i = 0, n = 0, begin = 0, t = GetpType(o);
+    clips_AddressObject *a = NULL;
+    clips_FactObject *fo = NULL;
+    clips_InstanceObject *io = NULL;
+
+    /* check for return type and build a PyObject to return */
+    switch(t) {
+    case INTEGER:
+        p = Py_BuildValue("(il)", t, DOPToLong(o));
+        break;
+    case FLOAT:
+        p = Py_BuildValue("(id)", t, DOPToDouble(o));
+        break;
+    case STRING:
+    case SYMBOL:
+    case INSTANCE_NAME:
+        p = Py_BuildValue("(is)", t, DOPToString(o));
+        break;
+    case MULTIFIELD:
+        n = GetpDOLength(o);
+        begin = GetpDOBegin(o);
+        ptr = GetpValue(o);
+        if(!ptr)
+            FAIL();
+        q = PyList_New(n);
+        if(!q)
+            FAIL();
+        for(i=0; i<n; i++) {
+            if(!(p1 = i_do2py_mfhelp_e(env, ptr, begin + i)))
+                FAIL();
+            PyList_SET_ITEM(q, i, p1);
+        }
+        p = Py_BuildValue("(iO)", t, q);
+        break;
+    case INSTANCE_ADDRESS:
+        ptr = DOPToPointer(o);
+        if(!ptr)
+            FAIL();
+        if(env) {
+            clips_instance_New(env, io);
+            if(!io)
+                FAIL();
+            clips_instance_assign(io, ptr);
+            ENV_CHECK_VALID_INSTANCE(env, io);
+        } else {
+            clips_instance_New(GetCurrentEnvironment(), io);
+            if(!io)
+                FAIL();
+            clips_instance_assign(io, ptr);
+            CHECK_VALID_INSTANCE(io);
+        }
+        clips_instance_lock(io);
+        p = Py_BuildValue("(iO)", t, io);
+        break;
+    case EXTERNAL_ADDRESS:
+        ptr = DOPToPointer(o);
+        if(!ptr)
+            FAIL();
+        clips_address_New(a);
+        if(!a)
+            FAIL();
+        clips_address_addrtype(a) = t;
+        clips_address_value(a) = ptr;
+        p = Py_BuildValue("(iO)", t, a);
+        break;
+    case FACT_ADDRESS:
+        ptr = DOPToPointer(o);
+        if(!ptr)
+            FAIL();
+        if(env) {
+            clips_fact_New(env, fo);
+            if(!fo)
+                FAIL();
+            clips_fact_assign(fo, ptr);
+            ENV_CHECK_VALID_FACT(env, fo);
+        } else {
+            clips_fact_New(GetCurrentEnvironment(), fo);
+            if(!fo)
+                FAIL();
+            clips_fact_assign(fo, ptr);
+            CHECK_VALID_FACT(fo);
+        }
+        clips_fact_readonly(fo) = TRUE;
+        clips_fact_lock(fo);
+        p = Py_BuildValue("(iO)", t, fo);
+        break;
+    default:
+        FAIL();     /* something wrong? */
+        break;
+    }
+
+    return p;
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+    Py_XDECREF(a);
+    Py_XDECREF(io);
+    Py_XDECREF(fo);
+END_FAIL
+}
+
+#define i_do2py(_o) i_do2py_e(NULL, _o)
+
+
+/* helpers to convert couples (type, value) to DATA_OBJECTs:
+ *  first, a "simple" macro to check if something can be really
+ *  converted to a DATA_OBJECT: that is, it should be a pair and
+ *  its first element has to be an integer. Then, macros to extract
+ *  the elements from the tuple itself.
+ */
+#define IS_PY_DATA_OBJECT(_p) \
+    (PyTuple_Check(_p) && PyTuple_Size(_p) == 2 \
+     && PyInt_Check(PyTuple_GetItem(_p, 0)))
+#define PY_DATA_OBJECT_TYPE(_p) ((int)PyInt_AsLong(PyTuple_GetItem(_p, 0)))
+#define PY_DATA_OBJECT_VALUE(_p) ((PyObject *)PyTuple_GetItem(_p, 1))
+/* then the actual functions to put data in the DATA_OBJECT structure */
+BOOL i_py2do_mfhelp_e(void *env, PyObject *p, void *mfptr, int fieldpos) {
+    int type = 0;
+    PyObject *value = NULL;
+    void *do_value = NULL;
+    long i = 0;
+    double d = 0;
+    char *s = NULL;
+
+    if(!IS_PY_DATA_OBJECT(p)) goto fail;
+    type = PY_DATA_OBJECT_TYPE(p);
+    value = PY_DATA_OBJECT_VALUE(p);
+    switch(type) {
+    case INTEGER:
+        if(!PyInt_Check(value))
+            goto fail;
+        i = PyInt_AsLong(value);
+        do_value = EnvAddLong(env, i);
+        break;
+    case FLOAT:
+        if(!PyFloat_Check(value))
+            goto fail;
+        d = PyFloat_AsDouble(value);
+        do_value = EnvAddDouble(env, d);
+        break;
+    case STRING:
+    case SYMBOL:
+    case INSTANCE_NAME:
+        if(!PyString_Check(value))
+            goto fail;
+        s = PyString_AsString(value);
+        do_value = EnvAddSymbol(env, s);
+        break;
+    case INSTANCE_ADDRESS:
+        if(!clips_instance_check(value))
+            goto fail;
+        do_value = clips_instance_value(value);
+        break;
+    case FACT_ADDRESS:
+        if(!clips_fact_check(value))
+            goto fail;
+        do_value = clips_fact_value(value);
+        break;
+    case EXTERNAL_ADDRESS:
+        if(!clips_address_check(value))
+            goto fail;
+        do_value = clips_address_value(value);
+        break;
+    default:
+        goto fail;
+    }
+
+    SetMFType(mfptr, fieldpos, type);
+    SetMFValue(mfptr, fieldpos, do_value);
+    return TRUE;
+
+fail:
+    return FALSE;
+}
+
+
+BOOL i_py2do_e(void *env, PyObject *p, DATA_OBJECT *o) {
+    int type = 0;
+    PyObject *value = NULL, *item = NULL;
+    void *do_value = NULL;
+    long i = 0, n = 0;
+    double d = 0;
+    char *s = NULL;
+
+    if(!IS_PY_DATA_OBJECT(p)) goto fail;
+    type = PY_DATA_OBJECT_TYPE(p);
+    value = PY_DATA_OBJECT_VALUE(p);
+    switch(type) {
+    case INTEGER:
+        if(!PyInt_Check(value))
+            goto fail;
+        i = PyInt_AsLong(value);
+        do_value = EnvAddLong(env, i);
+        break;
+    case FLOAT:
+        if(!PyFloat_Check(value))
+            goto fail;
+        d = PyFloat_AsDouble(value);
+        do_value = EnvAddDouble(env, d);
+        break;
+    case STRING:
+    case SYMBOL:
+    case INSTANCE_NAME:
+        if(!PyString_Check(value))
+            goto fail;
+        s = PyString_AsString(value);
+        do_value = EnvAddSymbol(env, s);
+        break;
+    case MULTIFIELD:
+        if(!PyList_Check(value))
+            goto fail;
+        n = PyList_Size(value);
+        if(n == 0) goto fail;
+        if(!(do_value = EnvCreateMultifield(env, n)))
+            goto fail;
+        for(i = 0; i < n; i++) {
+            item = PyList_GetItem(value, i);
+            if(!item)
+                goto fail;
+            if(!i_py2do_mfhelp_e(env, item, do_value, (int)(i + 1)))
+                goto fail;
+        }
+        break;  /* n is still good for below */
+    case INSTANCE_ADDRESS:
+        if(!clips_instance_check(value))
+            goto fail;
+        do_value = clips_instance_value(value);
+        break;
+    case FACT_ADDRESS:
+        if(!clips_fact_check(value))
+            goto fail;
+        do_value = clips_fact_value(value);
+        break;
+    case EXTERNAL_ADDRESS:
+        if(!clips_address_check(value))
+            goto fail;
+        do_value = clips_address_value(value);
+        break;
+    default:
+        goto fail;
+    }
+
+    SetpType(o, type);
+    SetpValue(o, do_value);
+    if(type == MULTIFIELD) {
+        SetpDOBegin(o, 1);
+        SetpDOEnd(o, n);
+    }
+
+    return TRUE;
+
+fail:
+    return FALSE;
+}
+
+#define i_py2do(_p, _o) i_py2do_e(GetCurrentEnvironment(), _p, _o)
+
+
+/* Part Two: the implementation */
+
+/* Part Two - Section 1: Globals */
+
+
+/* 4.1 - Environment Functions */
+
+/* AddClearFunction */
+UNIMPLEMENT(addClearFunction, g_addClearFunction)
+/* AddPeriodicFunction */
+UNIMPLEMENT(addPeriodicFunction, g_addPeriodicFunction)
+/* AddResetFunction */
+UNIMPLEMENT(addResetFunction, g_addResetFunction)
+
+/* bload */
+static char g_bload__doc__[] = "\
+bload(filename)\n\
+load a binary image of environment constructs\n\
+arguments:\n\
+  filename (str) - the name of binary file to load from";
+static PyObject *g_bload(PyObject *self, PyObject *args) {
+    char *fn = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &fn))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Bload(fn)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* bsave */
+static char g_bsave__doc__[] = "\
+bsave(filename)\n\
+save a binary image of environment constructs\n\
+arguments:\n\
+  filename (str) - the name of binary file to save to";
+static PyObject *g_bsave(PyObject *self, PyObject *args) {
+    char *fn = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &fn))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Bsave(fn)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* clear */
+static char g_clear__doc__[] = "\
+clear()\n\
+clear environment";
+static PyObject *g_clear(PyObject *self, PyObject *args) {
+
+    CHECK_NOARGS(args);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Clear_PY()) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPSSYS_ENVNOCLEAR();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+#ifdef USE_CLEAR_RESETGCCOUNTERS
+    RESET_ASSERTED_FACTS();
+#endif /* USE_CLEAR_RESETGCCOUNTERS */
+    LOSE_HASH_FACTS();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* functionCall */
+static char g_functionCall__doc__[] = "\
+functionCall(funcname [, args]) -> (type, value)\n\
+call an internal function\n\
+returns: the function result, as a pair (type, return value)\n\
+arguments:\n\
+  funcname (str) - the internal function or operator name\n\
+  args (str) - string containing a blank separated list of arguments";
+static PyObject *g_functionCall(PyObject *self, PyObject *args) {
+    char *func = NULL, *fargs = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "s|s", &func, &fargs))
+        FAIL();
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(FunctionCall(func, fargs, &o)) {
+        SetEvaluationError(GetCurrentEnvironment(), FALSE);
+        SetHaltExecution(GetCurrentEnvironment(), FALSE);
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_FUNCCALL();
+        FAIL();
+    }
+    SetEvaluationError(GetCurrentEnvironment(), FALSE);
+    SetHaltExecution(GetCurrentEnvironment(), FALSE);
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    p = i_do2py(&o);
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    SKIP();
+    Py_XDECREF(p);
+END_FAIL
+}
+
+
+/* getAutoFloatDividend */
+STATUS_FUNC_GET_BOOL(getAutoFloatDividend,
+                     g_getAutoFloatDividend,
+                     GetAutoFloatDividend)
+
+/* getDynamicConstraintChecking */
+STATUS_FUNC_GET_BOOL(getDynamicConstraintChecking,
+                     g_getDynamicConstraintChecking,
+                     GetDynamicConstraintChecking)
+
+/* getSequenceOperatorRecognition */
+STATUS_FUNC_GET_BOOL(getSequenceOperatorRecognition,
+                     g_getSequenceOperatorRecognition,
+                     GetSequenceOperatorRecognition)
+
+/* getStaticConstraintChecking */
+STATUS_FUNC_GET_BOOL(getStaticConstraintChecking,
+                     g_getStaticConstraintChecking,
+                     GetStaticConstraintChecking)
+
+/* initializeEnvironment: NEVER TO BE IMPLEMENTED
+ *  the main environment is initialized at module load time
+ */
+
+/* load */
+static char g_load__doc__[] = "\
+load(filename)\n\
+load constructs into environment\n\
+arguments:\n\
+  filename (str) - the name of file to load constructs from";
+static PyObject *g_load(PyObject *self, PyObject *args) {
+    char *fn = NULL;
+    int rv;
+
+
+    if(!PyArg_ParseTuple(args, "s", &fn))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    rv = Load(fn);
+    RELEASE_MEMORY_ERROR();
+    if(rv == 0) {
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    if(rv < 0) {
+        ERROR_CLIPS_PARSEF();
+        FAIL();
+    }
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* removeClearFunction */
+UNIMPLEMENT(removeClearFunction, g_removeClearFunction)
+
+/* removePeriodicFunction */
+UNIMPLEMENT(removePeriodicFunction, g_removePeriodicFunction)
+
+/* removeResetFunction */
+UNIMPLEMENT(removeResetFunction, g_removeResetFunction)
+
+/* reset */
+static char g_reset__doc__[] = "\
+reset()\n\
+reset environment";
+static PyObject *g_reset(PyObject *self, PyObject *args) {
+
+    /* this function may cause CLIPS to allocate memory */
+
+    CHECK_NOARGS(args);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    Reset();
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* save */
+static char g_save__doc__[] = "\
+save(filename)\n\
+save constructs to a file\n\
+arguments:\n\
+  filename (str) - the name of file to save constructs to";
+static PyObject *g_save(PyObject *self, PyObject *args) {
+    char *fn = NULL;
+    void *env = NULL;
+
+    /* this function may cause CLIPS to allocate memory */
+
+    if(!PyArg_ParseTuple(args, "s", &fn))
+        FAIL();
+    env = GetCurrentEnvironment();
+    if(!env) {
+        ERROR_CLIPS_NOENV();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvSave(env, fn)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setAutoFloatDividend */
+STATUS_FUNC_SET_BOOL(setAutoFloatDividend,
+                     g_setAutoFloatDividend,
+                     SetAutoFloatDividend)
+
+/* setDynamicConstraintChecking */
+STATUS_FUNC_SET_BOOL(setDynamicConstraintChecking,
+                     g_setDynamicConstraintChecking,
+                     SetDynamicConstraintChecking)
+
+/* setSequenceOperatorRecognition */
+STATUS_FUNC_SET_BOOL(setSequenceOperatorRecognition,
+                     g_setSequenceOperatorRecognition,
+                     SetSequenceOperatorRecognition)
+
+/* setStaticConstraintChecking */
+STATUS_FUNC_SET_BOOL(setStaticConstraintChecking,
+                     g_setStaticConstraintChecking,
+                     SetStaticConstraintChecking)
+
+/* batchStar */
+static char g_batchStar__doc__[] = "\
+batchStar(filename)\n\
+batch execute commands stored in specified file\n\
+arguments:\n\
+  filename (str) - the name of file to read commands from";
+static PyObject *g_batchStar(PyObject *self, PyObject *args) {
+    char *fn = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &fn))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    if(!BatchStar(fn)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* build */
+static char g_build__doc__[] = "\
+build(construct)\n\
+define specified construct\n\
+arguments:\n\
+  construct (str) - the construct to be added";
+static PyObject *g_build(PyObject *self, PyObject *args) {
+    char *cons = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &cons))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Build(cons)) {
+        SetEvaluationError(GetCurrentEnvironment(), FALSE);
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_PARSEX();
+        FAIL();
+    }
+    SetEvaluationError(GetCurrentEnvironment(), FALSE);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* eval */
+static char g_eval__doc__[] = "\
+eval(expression) -> (type, value)\n\
+evaluate the provided expression\n\
+returns: a pair holding the result in the form (type, return value)\n\
+arguments:\n\
+  expression (str) - the expression to evaluate";
+static PyObject *g_eval(PyObject *self, PyObject *args) {
+    char *expr = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "s", &expr))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Eval(expr, &o)) {
+        SetEvaluationError(GetCurrentEnvironment(), FALSE);
+        SetHaltExecution(GetCurrentEnvironment(), FALSE);
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_EVALX();
+        FAIL();
+    }
+    SetEvaluationError(GetCurrentEnvironment(), FALSE);
+    SetHaltExecution(GetCurrentEnvironment(), FALSE);
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p)
+        RETURN_NONE();
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* 4.2 - Debugging Functions */
+
+/* dribbleActive */
+STATUS_FUNC_GET_BOOL(dribbleActive, g_dribbleActive, DribbleActive)
+
+/* dribbleOff */
+FUNC_VOID_BOOL(dribbleOff, g_dribbleOff, DribbleOff)
+
+/* dribbleOn */
+static char g_dribbleOn__doc__[] = "\
+dribbleOn(filename)\n\
+turn the dribble function on\n\
+arguments:\n\
+  filename (str) - the name of file to write dribble information to";
+static PyObject *g_dribbleOn(PyObject *self, PyObject *args) {
+    char *fn = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &fn))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    if(!DribbleOn(fn)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getWatchItem */
+static char g_getWatchItem__doc__[] = "\
+getWatchItem(item) -> bool\n\
+tell whether the specified item is watched or not\n\
+returns: True if specified item is being watched, False otherwise\n\
+arguments:\n\
+  item (str) - the item to monitor the status of, can be one of\n\
+               the following: facts, rules, focus, activations,\n\
+               compilations, statistics, globals, slots, instances,\n\
+               messages, message-handlers, generic-functions,\n\
+               method or deffunctions.";
+static PyObject *g_getWatchItem(PyObject *self, PyObject *args) {
+    char *item = NULL;
+    int rv = 0;
+
+    if(!PyArg_ParseTuple(args, "s", &item))
+        FAIL();
+    rv = GetWatchItem(item);
+    if(rv < 0) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    return Py_BuildValue("i", rv ? 1 : 0);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* unwatch */
+static char g_unwatch__doc__[] = "\
+unwatch(item)\n\
+turn off tracing for specified item\n\
+arguments:\n\
+  item (str) - the item to disable tracing for, can be one of\n\
+               the following: facts, rules, focus, activations,\n\
+               compilations, statistics, globals, slots, instances,\n\
+               messages, message-handlers, generic-functions,\n\
+               method or deffunctions.";
+static PyObject *g_unwatch(PyObject *self, PyObject *args) {
+    char *item = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &item))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Unwatch(item)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* watch */
+static char g_watch__doc__[] = "\
+watch(item)\n\
+turn on tracing for specified item\n\
+arguments:\n\
+  item (str) - the item to enable tracing for, can be one of\n\
+               the following: facts, rules, focus, activations,\n\
+               compilations, statistics, globals, slots, instances,\n\
+               messages, message-handlers, generic-functions,\n\
+               method or deffunctions.";
+static PyObject *g_watch(PyObject *self, PyObject *args) {
+    char *item = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &item))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Watch(item)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.3 - Deftemplate functions */
+
+/* helper to check whether there is still this deftemplate */
+F_INLINE void *deftemplateExists(void *ptr) {
+	void *rv = GetNextDeftemplate(NULL);
+	while(rv != NULL) {
+		if(rv == ptr) return rv;
+		else rv = GetNextDeftemplate(rv);
+	}
+	return NULL;
+}
+#define PYDEFTEMPLATE_EXISTS(_p) deftemplateExists(clips_deftemplate_value(_p))
+#define CHECK_DEFTEMPLATE(_p) do { \
+        if(!PYDEFTEMPLATE_EXISTS(_p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define CHECK_RM_DEFTEMPLATE(_p) do { \
+        if(_p && !PYDEFTEMPLATE_EXISTS(_p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* actual function with documentation */
+
+/* deftemplateModule */
+static char g_deftemplateModule__doc__[] = "\
+deftemplateModule(deftemplate) -> str\n\
+retrieve the name of the module where the provided deftemplate resides\n\
+returns: a string containing a module name\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect";
+static PyObject *g_deftemplateModule(PyObject *self, PyObject *args) {
+    char *module = NULL;
+    clips_DeftemplObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    module = DeftemplateModule(clips_deftemplate_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!module) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(module);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+#if CLIPS_MINOR > 23
+
+/* deftemplateSlotAllowedValues */
+static char g_deftemplateSlotAllowedValues__doc__[] = "\
+deftemplateSlotAllowedValues(deftemplate, name) -> (MULTIFIELD, list)\n\
+retrieve the allowed values for a slot of given deftemplate\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *g_deftemplateSlotAllowedValues(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    DeftemplateSlotAllowedValues(clips_deftemplate_value(p), name, &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotCardinality */
+static char g_deftemplateSlotCardinality__doc__[] = "\
+deftemplateSlotCardinality(deftemplate, name) -> (MULTIFIELD, list)\n\
+retrieve the cardinality for a slot of given deftemplate\n\
+returns: MULTIFIELD and a list of pairs of pairs (type, value)\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *g_deftemplateSlotCardinality(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    DeftemplateSlotCardinality(clips_deftemplate_value(p), name, &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotDefaultP */
+static char g_deftemplateSlotDefaultP__doc__[] = "\
+deftemplateSlotCardinality(deftemplate, name) -> int\n\
+tell whether or not a slot of given deftemplate has a default value\n\
+returns: one of NO_DEFAULT, STATIC_DEFAULT or DYNAMIC_DEFAULT\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *g_deftemplateSlotDefaultP(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    int rv = 0;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    rv = DeftemplateSlotDefaultP(clips_deftemplate_value(p), name);
+    RELEASE_MEMORY_ERROR();
+    RETURN_INT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotDefaultValue */
+static char g_deftemplateSlotDefaultValue__doc__[] = "\
+deftemplateSlotDefaultValue(deftemplate, name) -> (MULTIFIELD, list)\n\
+retrieve default value(s) for a slot of given deftemplate\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *g_deftemplateSlotDefaultValue(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    DeftemplateSlotDefaultValue(clips_deftemplate_value(p), name, &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotExistP */
+static char g_deftemplateSlotExistP__doc__[] = "\
+deftemplateSlotExistP(deftemplate, name) -> bool\n\
+tell whether or not the given deftemplate has the specified slot\n\
+returns: True if the slot is present, False otherwise\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *g_deftemplateSlotExistP(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    int rv = 0;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    rv = DeftemplateSlotExistP(clips_deftemplate_value(p), name);
+    RELEASE_MEMORY_ERROR();
+    RETURN_BOOL(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotMultiP */
+static char g_deftemplateSlotMultiP__doc__[] = "\
+deftemplateSlotMultiP(deftemplate, name) -> bool\n\
+tell whether or not the specified slot of given deftemplate is multifield\n\
+returns: True if it is multifield, False otherwise\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *g_deftemplateSlotMultiP(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    int rv = 0;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    rv = DeftemplateSlotMultiP(clips_deftemplate_value(p), name);
+    RELEASE_MEMORY_ERROR();
+    RETURN_BOOL(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotNames */
+static char g_deftemplateSlotNames__doc__[] = "\
+deftemplateSlotNames(deftemplate) -> (MULTIFIELD, list)\n\
+retrieve the names of slots in given deftemplate (special case if implied)\n\
+returns: MULTIFIELD and a list of pairs or a pair (SYMBOL, 'implied')\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect";
+static PyObject *g_deftemplateSlotNames(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    DeftemplateSlotNames(clips_deftemplate_value(p), &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotRange */
+static char g_deftemplateSlotRange__doc__[] = "\
+deftemplateSlotRange(deftemplate, name) -> (MULTIFIELD, list)\n\
+retrieve the numeric range information for a slot of given deftemplate\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *g_deftemplateSlotRange(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    DeftemplateSlotRange(clips_deftemplate_value(p), name, &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotSingleP */
+static char g_deftemplateSlotSingleP__doc__[] = "\
+deftemplateSlotSingleP(deftemplate, name) -> bool\n\
+tell whether or not the specified slot of given deftemplate is single field\n\
+returns: True if it is single field, False otherwise\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *g_deftemplateSlotSingleP(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    int rv = 0;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    rv = DeftemplateSlotSingleP(clips_deftemplate_value(p), name);
+    RELEASE_MEMORY_ERROR();
+    RETURN_BOOL(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotTypes */
+static char g_deftemplateSlotTypes__doc__[] = "\
+deftemplateSlotTypes(deftemplate, name) -> (MULTIFIELD, list)\n\
+retrieve names of the data types allowed for a slot of given deftemplate\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *g_deftemplateSlotTypes(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    DeftemplateSlotTypes(clips_deftemplate_value(p), name, &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+#else
+UNIMPLEMENT_VERSION(deftemplateSlotAllowedValues,
+                    g_deftemplateSlotAllowedValues)
+UNIMPLEMENT_VERSION(deftemplateSlotCardinality,
+                    g_deftemplateSlotCardinality)
+UNIMPLEMENT_VERSION(deftemplateSlotDefaultP,
+                    g_deftemplateSlotDefaultP)
+UNIMPLEMENT_VERSION(deftemplateSlotDefaultValue,
+                    g_deftemplateSlotDefaultValue)
+UNIMPLEMENT_VERSION(deftemplateSlotExistP,
+                    g_deftemplateSlotExistP)
+UNIMPLEMENT_VERSION(deftemplateSlotMultiP,
+                    g_deftemplateSlotMultiP)
+UNIMPLEMENT_VERSION(deftemplateSlotNames,
+                    g_deftemplateSlotNames)
+UNIMPLEMENT_VERSION(deftemplateSlotRange,
+                    g_deftemplateSlotRange)
+UNIMPLEMENT_VERSION(deftemplateSlotSingleP,
+                    g_deftemplateSlotSingleP)
+UNIMPLEMENT_VERSION(deftemplateSlotTypes,
+                    g_deftemplateSlotTypes)
+#endif /* CLIPS_MINOR > 23 */
+
+/* findDeftemplate */
+static char g_findDeftemplate__doc__[] = "\
+findDeftemplate(name) -> deftemplate\n\
+retrieve deftemplate object corresponding to the specified name\n\
+returns: the deftemplate as a new object\n\
+arguments:\n\
+  name (str) - the name of the deftemplate to look for";
+static PyObject *g_findDeftemplate(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DeftemplObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = FindDeftemplate(name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_deftemplate_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deftemplate_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDeftemplateList */
+static char g_getDeftemplateList__doc__[] = "\
+getDeftemplateList([module]) -> (MULTIFIELD, list)\n\
+retrieve list of deftemplate names in specified defmodule\n\
+returns: value MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_getDeftemplateList(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    GetDeftemplateList(&o, module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDeftemplateName */
+static char g_getDeftemplateName__doc__[] = "\
+getDeftemplateName(deftemplate) -> str\n\
+retrieve the name of given deftemplate object\n\
+returns: a string containing the name\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate object";
+static PyObject *g_getDeftemplateName(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    clips_DeftemplObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    name = GetDeftemplateName(clips_deftemplate_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP()
+END_FAIL
+}
+
+/* getDeftemplatePPForm */
+static char g_getDeftemplatePPForm__doc__[] = "\
+getDeftemplatePPForm(deftemplate) -> str\n\
+retrieve the pretty-print form of given deftemplate object\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate object";
+static PyObject *g_getDeftemplatePPForm(PyObject *self, PyObject *args) {
+    char *s = NULL;
+    clips_DeftemplObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = GetDeftemplatePPForm(clips_deftemplate_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP()
+END_FAIL
+}
+
+/* getDeftemplateWatch */
+static char g_getDeftemplateWatch__doc__[] = "\
+getDeftemplateWatch(deftemplate) -> bool\n\
+tell if deftemplate is being watched\n\
+returns: True if the deftemplate is being watched, False otherwise\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate object";
+static PyObject *g_getDeftemplateWatch(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    i = GetDeftemplateWatch(clips_deftemplate_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP()
+END_FAIL
+}
+
+/* getNextDeftemplate */
+static char g_getNextDeftemplate__doc__[] = "\
+getNextDeftemplate([deftemplate]) -> deftemplate\n\
+find next deftemplate in the list, first if argument is omitted\n\
+returns: next deftemplate object, None if already at last deftemplate\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to start from";
+static PyObject *g_getNextDeftemplate(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DeftemplType, &p))
+        FAIL();
+    if(p)
+        CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextDeftemplate(p ? clips_deftemplate_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) RETURN_NONE();
+    clips_deftemplate_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deftemplate_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* isDeftemplateDeletable */
+static char g_isDeftemplateDeletable__doc__[] = "\
+isDeftemplateDeletable(deftemplate) -> bool\n\
+tell whether or not given deftemplate object can be deleted\n\
+returns: True when deftemplate can be deleted, False otherwise\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate object";
+static PyObject *g_isDeftemplateDeletable(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    i = IsDeftemplateDeletable(clips_deftemplate_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* listDeftemplates */
+static char g_listDeftemplates__doc__[] = "\
+listDeftemplates(logicalname [, module])\n\
+list deftemplates to output identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_listDeftemplates(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!", &lname, &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ListDeftemplates(lname, module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setDeftemplateWatch */
+static char g_setDeftemplateWatch__doc__[] = "\
+setDeftemplateWatch(state, deftemplate)\n\
+set the specified deftemplate to a new watch state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  deftemplate (deftemplate) - the deftemplate object";
+static PyObject *g_setDeftemplateWatch(PyObject *self, PyObject *args) {
+    PyObject *state = NULL;
+    clips_DeftemplObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "OO!", &state, &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_DEFTEMPLATE(p);
+    ACQUIRE_MEMORY_ERROR();
+    SetDeftemplateWatch(PyObject_IsTrue(state), clips_deftemplate_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* undeftemplate */
+static char g_undeftemplate__doc__[] = "\
+undeftemplate([deftemplate])\n\
+remove a deftemplate or all deftemplates from the system\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to remove, all if omitted";
+static PyObject *g_undeftemplate(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DeftemplType, &p)) FAIL();
+    CHECK_RM_DEFTEMPLATE(p);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Undeftemplate(p ? clips_deftemplate_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.4 - Fact Functions */
+
+/* assertFact */
+static char g_assertFact__doc__[] = "\
+assertFact(fact) -> fact\n\
+add a fact to the fact list\n\
+returns: the asserted fact as a new object\n\
+arguments:\n\
+  fact (fact) - the fact to assert";
+static PyObject *g_assertFact(PyObject *self, PyObject *args) {
+    clips_FactObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_FactType, &p)) FAIL();
+    CHECK_VALID_FACT(p);
+    /* if fact is read-only, it was previously asserted and can't be reused */
+    if(clips_fact_readonly(p)) {
+        ERROR_CLIPS_REASSERT();
+        FAIL();
+    }
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = Assert(clips_fact_value(p));
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    if(!ptr) {
+        ERROR_CLIPS_ASSERT();
+        FAIL();
+    }
+    REMOVE_JUSTASSERTED_FACT();
+    REMOVE_HASH_FACT(p);
+    /* now the old fact cannot be modified anymore, even on possible failure */
+    clips_fact_readonly(p) = TRUE;
+    clips_fact_New(GetCurrentEnvironment(), q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_fact_readonly(q) = TRUE;
+    clips_fact_assign(q, ptr);
+    clips_fact_lock(q);
+    CHECK_VALID_FACT(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* assertString */
+static char g_assertString__doc__[] = "\
+assertString(expr) -> fact\n\
+add a fact to the fact list using a string\n\
+returns: the asserted fact as a new object\n\
+arguments:\n\
+  expr (str) - string containing a list of primitive datatypes";
+static PyObject *g_assertString(PyObject *self, PyObject *args) {
+    char *expr = NULL;
+    clips_FactObject *p = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &expr))
+        FAIL();
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = AssertString(expr);
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    if(!ptr) {
+        ERROR_CLIPS_ASSERT();
+        FAIL();
+    }
+    clips_fact_New(GetCurrentEnvironment(), p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_fact_readonly(p) = TRUE;
+    clips_fact_assign(p, ptr);
+    clips_fact_lock(p);
+    CHECK_VALID_FACT(p);
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* assignFactSlotDefaults */
+static char g_assignFactSlotDefaults__doc__[] = "\
+assignFactSlotDefaults(fact)\n\
+assign default values to the slots of a fact\n\
+arguments:\n\
+  fact (fact) - the fact whose slots are to reset to default values";
+static PyObject *g_assignFactSlotDefaults(PyObject *self, PyObject *args) {
+    clips_FactObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_FactType, &p))
+        FAIL();
+    CHECK_VALID_FACT(p);
+    if(clips_fact_readonly(p)) {
+        ERROR_CLIPS_READONLY();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    if(!AssignFactSlotDefaults(clips_fact_value(p))) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_OTHER("could not assign default values to fact");
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* createFact */
+static char g_createFact__doc__[] = "\
+createFact(deftemplate) -> fact\n\
+create a new fact object using the provided deftemplate\n\
+returns: a new fact object\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate defining the fact type";
+static PyObject *g_createFact(PyObject *self, PyObject *args) {
+    clips_FactObject *p = NULL;
+    clips_DeftemplObject *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeftemplType, &q)) FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = CreateFact(clips_deftemplate_value(q));
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_CREATION();
+        FAIL();
+    }
+    clips_fact_New(GetCurrentEnvironment(), p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_fact_assign(p, ptr);
+    clips_fact_lock(p);
+    CHECK_VALID_FACT(p);
+    ADD_NONASSERTED_FACT();
+    APPEND_HASH_FACT(p);
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* decrementFactCount */
+UNIMPLEMENT(decrementFactCount, g_decrementFactCount)
+
+/* factIndex */
+static char g_factIndex__doc__[] = "\
+factIndex(fact) -> int\n\
+retrieve the index of specified fact in fact list\n\
+arguments:\n\
+  fact (fact) - the fact to look for";
+static PyObject *g_factIndex(PyObject *self, PyObject *args) {
+    clips_FactObject *p = NULL;
+    long int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_FactType, &p))
+        FAIL();
+    CHECK_VALID_FACT(p);
+    ACQUIRE_MEMORY_ERROR();
+    i = FactIndex(clips_fact_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* facts */
+static char g_facts__doc__[] = "\
+facts(logicalname [, module [, start [, end [, max]]]])\n\
+list facts to the output stream identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule, None for all modules\n\
+  start (int) - first fact, -1 for no restriction\n\
+  end (int) - last fact, -1 for no restriction\n\
+  max (int) - maximum number of facts, -1 for no restriction";
+static PyObject *g_facts(PyObject *self, PyObject *args) {
+    PyObject *module = NULL;
+    char *lname = NULL;
+    int start = -1, end = -1, max = -1;
+
+    if(!PyArg_ParseTuple(args, "s|O!iii", &lname,
+                         &clips_DefmoduleType, &module,
+                         &start, &end, &max))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    Facts(lname,
+          module && module != Py_None ? clips_defmodule_value(module) : NULL,
+          start, end, max);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getFactDuplication */
+STATUS_FUNC_GET_BOOL(getFactDuplication,
+                     g_getFactDuplication,
+                     GetFactDuplication)
+
+/* getFactListChanged */
+STATUS_FUNC_GET_BOOL(getFactListChanged,
+                     g_getFactListChanged,
+                     GetFactListChanged)
+
+/* getFactPPForm */
+static char g_getFactPPForm__doc__[] = "\
+getFactPPForm(fact) -> str\n\
+retrieve the pretty-print form of given fact\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  fact (fact) - the fact object to inspect";
+static PyObject *g_getFactPPForm(PyObject *self, PyObject *args) {
+    char *buffer = NEW_ARRAY(char, ppbuffer_size);
+    clips_FactObject *p = NULL;
+    PyObject *rv = NULL;
+
+    if(!buffer) {
+        ERROR_MEMORY("cannot allocate buffer");
+        FAIL();
+    }
+    if(!PyArg_ParseTuple(args, "O!", &clips_FactType, &p))
+        FAIL();
+    CHECK_VALID_FACT(p);
+    CHECK_LOST_FACT(p);
+    ACQUIRE_MEMORY_ERROR();
+    GetFactPPForm(buffer, ppbuffer_size-1, clips_fact_value(p));
+    RELEASE_MEMORY_ERROR();
+    rv = Py_BuildValue("s", buffer);
+    DELETE(buffer);
+    return rv;
+
+BEGIN_FAIL
+    if(buffer) DELETE(buffer);
+    SKIP();
+END_FAIL
+}
+
+/* getFactSlot */
+static char g_getFactSlot__doc__[] = "\
+getFactSlot(fact [, slotname]) -> (type, value)\n\
+get the slot value for the specified fact given the slot name\n\
+returns: a value or a multifield in the form (type, return value)\n\
+arguments:\n\
+  fact (fact) - the fact to inspect\n\
+  slotname (str) - the name of the slot to retrieve, should be omitted\n\
+                   for the implied multifield slot of an implied\n\
+                   deftemplate";
+static PyObject *g_getFactSlot(PyObject *self, PyObject *args) {
+    clips_FactObject *p = NULL;
+    char *slotname = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|s", &clips_FactType, &p, &slotname))
+        FAIL();
+    CHECK_VALID_FACT(p);
+    CHECK_LOST_FACT(p);
+    /* we make some considerations about this call, to avoid nasty errors */
+    /* check that the slot name can be really omitted (see docstring) */
+    if(!slotname && !
+        ((struct deftemplate *)
+            ((struct fact *)clips_fact_value(p))->whichDeftemplate
+        )->implied) {
+            ERROR_VALUE("cannot omit slot name using this fact");
+            FAIL();
+        }
+    /* end of considerations */
+    ACQUIRE_MEMORY_ERROR();
+    if(!GetFactSlot(clips_fact_value(p), slotname, &o)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    Py_XDECREF(rv);
+END_FAIL
+}
+
+/* getNextFact */
+static char g_getNextFact__doc__[] = "\
+getNextFact([fact]) -> fact\n\
+retrieve next fact object, first if argument is omitted\n\
+returns: a fact object, None if already at last fact\n\
+arguments:\n\
+  fact (fact) - the fact to start from";
+static PyObject *g_getNextFact(PyObject *self, PyObject *args) {
+    clips_FactObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_FactType, &p))
+        FAIL();
+    if(p)
+        CHECK_VALID_FACT(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextFact(p ? clips_fact_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_fact_New(GetCurrentEnvironment(), q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_fact_readonly(q) = TRUE;
+    clips_fact_assign(q, ptr);
+    clips_fact_lock(q);
+    CHECK_VALID_FACT(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* 4.4.12a - getNextFactInTemplate */
+static char g_getNextFactInTemplate__doc__[] = "\
+getNextFactInTemplate(deftemplate [, fact]) -> fact\n\
+retrieve next fact object for a deftemplate, first if fact is omitted\n\
+returns: a fact object, None if already at last fact\n\
+arguments:\n\
+  deftemplate (deftemplate) - the template to find facts of\n\
+  fact (fact) - the fact to start from";
+static PyObject *g_getNextFactInTemplate(PyObject *self, PyObject *args) {
+    clips_FactObject *p = NULL, *q = NULL;
+    clips_DeftemplObject *t = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_DeftemplType, &t, &clips_FactType, &p))
+        FAIL();
+    CHECK_DEFTEMPLATE(t);
+    if(p)
+        CHECK_VALID_FACT(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextFactInTemplate(
+        clips_deftemplate_value(t), p ? clips_fact_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_fact_New(GetCurrentEnvironment(), q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_fact_readonly(q) = TRUE;
+    clips_fact_assign(q, ptr);
+    clips_fact_lock(q);
+    CHECK_VALID_FACT(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* incrementFactCount */
+UNIMPLEMENT(incrementFactCount, g_incrementFactCount)
+
+/* loadFacts */
+static char g_loadFacts__doc__[] = "\
+loadFacts(filename)\n\
+load facts from specified file\n\
+arguments:\n\
+  filename (str) - the name of file to load facts from";
+static PyObject *g_loadFacts(PyObject *self, PyObject *args) {
+    char *fn = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &fn))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    if(!LoadFacts(fn)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+#if CLIPS_MINOR > 23
+
+/* ppFact */
+static char g_ppFact__doc__[] = "\
+ppFact(fact, output [, ignoredefault])\n\
+write the pretty-print form of given fact to logical output\n\
+arguments:\n\
+  fact (fact) - the fact to write\n\
+  output (str) - logical name of stream to output to\n\
+  ignoredefault (bool) - True to skip slots whose values equal defaults";
+static PyObject *g_ppFact(PyObject *self, PyObject *args) {
+    clips_FactObject *p = NULL;
+    char *s = NULL;
+    PyObject *o = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O", &clips_FactType, &p, &s, &o))
+        FAIL();
+    CHECK_VALID_FACT(p);
+    CHECK_LOST_FACT(p);
+    ACQUIRE_MEMORY_ERROR();
+    PPFact(clips_fact_value(p), s, o ? PyObject_IsTrue(o) : FALSE);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+#else
+UNIMPLEMENT_VERSION(ppFact, g_ppFact)
+#endif /* CLIPS_MINOR > 23 */
+
+/* putFactSlot */
+static char g_putFactSlot__doc__[] = "\
+putFactSlot(fact, name, value)\n\
+changes the value of specified slot in given fact\n\
+arguments:\n\
+  fact (fact) - the fact to change: must have been created with createFact\n\
+  name (str) - the name of the slot to change\n\
+  value (pair) - a pair (type, value) containing the value to assign";
+static PyObject *g_putFactSlot(PyObject *self, PyObject *args) {
+    DATA_OBJECT o = { 0 };
+    clips_FactObject *f = NULL;
+    PyObject *p = NULL;
+    char *s;
+
+    /* note that function i_py2do checks for last argument validity */
+    if(!PyArg_ParseTuple(args, "O!sO", &clips_FactType, &f, &s, &p))
+        FAIL();
+    CHECK_VALID_FACT(f);
+    CHECK_LOST_FACT(f);
+    if(clips_fact_readonly(f)) {
+        ERROR_CLIPS_READONLY();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    if(!i_py2do(p, &o)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    if(!PutFactSlot(clips_fact_value(f), s, &o)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_OTHER("fact slot could not be modified");
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* retract */
+static char g_retract__doc__[] = "\
+retract(fact)\n\
+retract provided fact\n\
+arguments:\n\
+  fact (fact) - the fact to retract";
+static PyObject *g_retract(PyObject *self, PyObject *args) {
+    clips_FactObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_FactType, &p))
+        FAIL();
+    CHECK_VALID_FACT(p);
+    CHECK_LOST_FACT(p);
+    clips_fact_lock(p);
+    /* if the fact was actually asserted it must now be read-only */
+    if(!clips_fact_readonly(p)) {
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    if(!Retract(clips_fact_value(p))) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* saveFacts */
+static char g_saveFacts__doc__[] = "\
+saveFacts(filename, scope)\n\
+save the facts in the specified scope\n\
+arguments:\n\
+  filename (str) - the name of the file to save to\n\
+  scope (int) - can be one of LOCAL_SAVE or VISIBLE_SAVE";
+static PyObject *g_saveFacts(PyObject *self, PyObject *args) {
+    int scope = 0;
+    char *fn = NULL;
+
+    if(!PyArg_ParseTuple(args, "si", &fn, &scope))
+        FAIL();
+    if(scope != LOCAL_SAVE && scope != VISIBLE_SAVE) {
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    if(!SaveFacts(fn, scope, NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setFactDuplication */
+STATUS_FUNC_SET_BOOL(setFactDuplication,
+                     g_setFactDuplication,
+                     SetFactDuplication)
+
+/* setFactListChanged */
+STATUS_FUNC_SET_BOOL(setFactListChanged,
+                     g_setFactListChanged,
+                     SetFactListChanged)
+
+/* factDeftemplate */
+static char g_factDeftemplate__doc__[] = "\
+factDeftemplate(fact) -> deftemplate\n\
+return the deftemplate associated with a particular fact\n\
+returns: a deftemplate object, None if no deftemplate associated\n\
+arguments:\n\
+  fact (fact) - the fact to examine";
+static PyObject *g_factDeftemplate(PyObject *self, PyObject *args) {
+    clips_FactObject *p = NULL;
+    clips_DeftemplObject *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_FactType, &p))
+        FAIL();
+    CHECK_VALID_FACT(p);
+    CHECK_LOST_FACT(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = FactDeftemplate(clips_fact_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!ptr || !deftemplateExists(ptr))
+        RETURN_NONE();
+    clips_deftemplate_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deftemplate_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* factExistp */
+static char g_factExistp__doc__[] = "\
+factExistp(fact) -> bool\n\
+tell whether a fact is in the list or has been retracted\n\
+returns: True if the fact exixts, False if it was retracted\n\
+arguments:\n\
+  fact (fact) - the fact to check";
+static PyObject *g_factExistp(PyObject *self, PyObject *args) {
+    clips_FactObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_FactType, &p))
+        FAIL();
+    i = FactExistp(clips_fact_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* factSlotNames */
+static char g_factSlotNames__doc__[] = "\
+factSlotNames(fact) -> (MULTIFIELD, list)\n\
+get the slot names for the specified fact\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  fact (fact) - the fact to inspect";
+static PyObject *g_factSlotNames(PyObject *self, PyObject *args) {
+    clips_FactObject *p = NULL;
+    PyObject *q = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_FactType, &p))
+        FAIL();
+    CHECK_VALID_FACT(p);
+    CHECK_LOST_FACT(p);
+    ACQUIRE_MEMORY_ERROR();
+    FactSlotNames(clips_fact_value(p), &o);
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* getFactList */
+static char g_getFactList__doc__[] = "\
+getFactList([module]) -> (type, list)\n\
+retrieve list of fact identifiers in specified defmodule\n\
+returns:  MULTIFIELD and a list of pairs (STRING, identifier)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_getFactList(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    PyObject *q = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    GetFactList(&o, module ? clips_defmodule_value(module) : NULL);
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* loadFactsFromString */
+static char g_loadFactsFromString__doc__[] = "\
+loadFactsFromString(str)\n\
+load facts from specified string into the fact list\n\
+arguments:\n\
+  string (str) - string to load facts from";
+static PyObject *g_loadFactsFromString(PyObject *self, PyObject *args) {
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &s))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    if(!LoadFactsFromString(s, -1)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_PARSEX();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.5 - Deffacts functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *deffactsExists(void *ptr) {
+	void *rv = GetNextDeffacts(NULL);
+	while(rv != NULL) {
+		if(rv == ptr) return rv;
+		else rv = GetNextDeffacts(rv);
+	}
+	return NULL;
+}
+#define PYDEFFACTS_EXISTS(_p) deffactsExists(clips_deffacts_value(_p))
+#define CHECK_DEFFACTS(_p) do { \
+        if(!PYDEFFACTS_EXISTS(_p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define CHECK_RM_DEFFACTS(_p) do { \
+        if(_p && !PYDEFFACTS_EXISTS(_p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* actual function with documentation */
+
+/* deffactsModule */
+static char g_deffactsModule__doc__[] = "\
+deffactsModule(deffacts) -> str\n\
+retrieve the module where the specified deffacts object is defined\n\
+returns: the module name\n\
+arguments:\n\
+  deffacts (deffacts) - the deffacts object to inspect";
+static PyObject *g_deffactsModule(PyObject *self, PyObject *args) {
+    clips_DeffactsObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeffactsType, &p))
+        FAIL();
+    CHECK_DEFFACTS(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = DeffactsModule(clips_deffacts_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* findDeffacts */
+static char g_findDeffacts__doc__[] = "\
+findDeffacts(name) -> deffacts\n\
+find the deffacts object whose name is specified\n\
+returns: the deffacts as a new object\n\
+arguments:\n\
+  name (str) - the name of the deffacts to look for";
+static PyObject *g_findDeffacts(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DeffactsObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = FindDeffacts(name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_deffacts_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deffacts_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDeffactsList */
+static char g_getDeffactsList__doc__[] = "\
+getDeffactsList([module]) -> (MULTIFIELD, list)\n\
+retrieve the list of deffacts in specified defmodule\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_getDeffactsList(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    GetDeffactsList(&o, module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDeffactsName */
+static char g_getDeffactsName__doc__[] = "\
+getDeffactsName(deffacts) -> str\n\
+retrieve the name of deffacts object\n\
+returns: the deffacts name\n\
+arguments:\n\
+  deffacts (deffacts) - the deffacts to inspect";
+static PyObject *g_getDeffactsName(PyObject *self, PyObject *args) {
+    clips_DeffactsObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeffactsType, &p))
+        FAIL();
+    CHECK_DEFFACTS(p);
+    ACQUIRE_MEMORY_ERROR();
+    name = GetDeffactsName(clips_deffacts_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDeffactsPPForm */
+static char g_getDeffactsPPForm__doc__[] = "\
+getDeffactsPPForm(deffacts) -> str\n\
+retrieve the pretty-print form of deffacts object\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  deffacts (deffacts) - the deffacts to inspect";
+static PyObject *g_getDeffactsPPForm(PyObject *self, PyObject *args) {
+    clips_DeffactsObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeffactsType, &p))
+        FAIL();
+    CHECK_DEFFACTS(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = GetDeffactsPPForm(clips_deffacts_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getNextDeffacts */
+static char g_getNextDeffacts__doc__[] = "\
+getNextDeffacts([deffacts]) -> deffacts\n\
+retrieve next deffacts object in list, first if argument is omitted\n\
+returns: a deffacts object, None if already at last deffacts\n\
+arguments:\n\
+  deffacts (deffacts) - the deffacts to start from";
+static PyObject *g_getNextDeffacts(PyObject *self, PyObject *args) {
+    clips_DeffactsObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DeffactsType, &p))
+        FAIL();
+    if(p)
+        CHECK_DEFFACTS(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextDeffacts(p ? clips_deffacts_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) RETURN_NONE();
+    clips_deffacts_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deffacts_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* isDeffactsDeletable */
+static char g_isDeffactsDeletable__doc__[] = "\
+isDeffactsDeletable(deffacts) -> bool\n\
+tell whether or not given deffacts object can be deleted\n\
+returns: True when deffacts can be deleted, False otherwise\n\
+arguments:\n\
+  deffacts (deffacts) - the deffacts object";
+static PyObject *g_isDeffactsDeletable(PyObject *self, PyObject *args) {
+    clips_DeffactsObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeffactsType, &p))
+        FAIL();
+    CHECK_DEFFACTS(p);
+    i = IsDeffactsDeletable(clips_deffacts_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* listDeffacts */
+static char g_listDeffacts__doc__[] = "\
+listDeffacts(output [, module])\n\
+list deffacts objects in specified defmodule to logical output\n\
+arguments:\n\
+  output (str) - logical name of stream to output to\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_listDeffacts(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!", &s, &clips_DefmoduleType, &p))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ListDeffacts(s, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* undeffacts */
+static char g_undeffacts__doc__[] = "\
+undeffacts([deffacts])\n\
+delete a deffacts object or all deffacts objects\n\
+arguments:\n\
+  deffacts (deffacts) - the deffacts to be deleted, all if omitted";
+static PyObject *g_undeffacts(PyObject *self, PyObject *args) {
+    clips_DeffactsObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeffactsType, &p))
+        FAIL();
+    CHECK_RM_DEFFACTS(p);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Undeffacts(p ? clips_deffacts_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.6 - Defrule functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *defruleExists(void *ptr) {
+    void *rv = GetNextDefrule(NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = GetNextDefrule(rv);
+    }
+    return NULL;
+}
+#define PYDEFRULE_EXISTS(_p) defruleExists(clips_defrule_value(_p))
+#define CHECK_DEFRULE(_p) do { \
+        if(!PYDEFRULE_EXISTS(_p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define CHECK_RM_DEFRULE(_p) do { \
+        if(_p && !PYDEFRULE_EXISTS(_p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* actual function with documentation */
+
+/* defruleHasBreakpoint */
+static char g_defruleHasBreakpoint__doc__[] = "\
+defruleHasBreakpoint(defrule) -> bool\n\
+test whether or not the given defrule has a breakpoint\n\
+returns: True if the defrule has a breakpoint, False otherwise\n\
+arguments:\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *g_defruleHasBreakpoint(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    ACQUIRE_MEMORY_ERROR();
+    i = DefruleHasBreakpoint(clips_defrule_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* defruleModule */
+static char g_defruleModule__doc__[] = "\
+defruleModule(defrule) -> str\n\
+retrieve the module where the defrule is defined\n\
+returns: the requested name of module\n\
+arguments:\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *g_defruleModule(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    ACQUIRE_MEMORY_ERROR();
+    name = DefruleModule(clips_defrule_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* findDefrule */
+static char g_findDefrule__doc__[] = "\
+findDefrule(name) -> defrule\n\
+find the defrule with the specified name\n\
+returns: the defrule as a new object\n\
+arguments:\n\
+  name (str) - the name of defrule to look for";
+static PyObject *g_findDefrule(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    clips_DefruleObject *p = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = FindDefrule(name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    clips_defrule_New(p);
+    clips_defrule_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefruleList */
+static char g_getDefruleList__doc__[] = "\
+getDefruleList([module]) -> (MULTIFIELD, list)\n\
+retrieve the list of defrule objects in the specified defmodule\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_getDefruleList(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    GetDefruleList(&o, module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefruleName */
+static char g_getDefruleName__doc__[] = "\
+getDefruleName(defrule) -> str\n\
+retrieve the name of specified defrule\n\
+returns: a string containing the defrule name\n\
+arguments:\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *g_getDefruleName(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    ACQUIRE_MEMORY_ERROR();
+    name = GetDefruleName(clips_defrule_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefrulePPForm */
+static char g_getDefrulePPForm__doc__[] = "\
+getDefrulePPForm(defrule) -> str\n\
+retrieve the pretty-print form of specified defrule\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *g_getDefrulePPForm(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = GetDefrulePPForm(clips_defrule_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefruleWatchActivations */
+static char g_getDefruleWatchActivations__doc__[] = "\
+getDefruleWatchActivations(defrule) -> bool\n\
+tell whether the specified defrule is watched for activations\n\
+returns: True if activations are watched, False otherwise\n\
+arguments:\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *g_getDefruleWatchActivations(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    i = GetDefruleWatchActivations(clips_defrule_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefruleWatchFirings */
+static char g_getDefruleWatchFirings__doc__[] = "\
+getDefruleWatchFirings(defrule) -> bool\n\
+tell whether the specified defrule is watched for firings\n\
+returns: True if rule firings are watched, False otherwise\n\
+arguments:\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *g_getDefruleWatchFirings(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    i = GetDefruleWatchFirings(clips_defrule_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getIncrementalReset */
+STATUS_FUNC_GET_BOOL(getIncrementalReset,
+                     g_getIncrementalReset,
+                     GetIncrementalReset)
+
+/* getNextDefrule */
+static char g_getNextDefrule__doc__[] = "\
+getNextDefrule([defrule]) -> defrule\n\
+retrieve next defrule object in list, first if argument is omitted\n\
+returns: a defrule object, None if already at last defrule\n\
+arguments:\n\
+  defrule (defrule) - the defrule to start from";
+static PyObject *g_getNextDefrule(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefruleType, &p))
+        FAIL();
+    if(p)
+        CHECK_DEFRULE(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextDefrule(p ? clips_defrule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_defrule_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defrule_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* isDefruleDeletable */
+static char g_isDefruleDeletable__doc__[] = "\
+isDefruleDeletable(defrule) -> bool\n\
+tell whether or not given defrule object can be deleted\n\
+returns: True when defrule can be deleted, False otherwise\n\
+arguments:\n\
+  defrule (defrule) - the defrule object";
+static PyObject *g_isDefruleDeletable(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    i = IsDefruleDeletable(clips_defrule_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* listDefrules */
+static char g_listDefrules__doc__[] = "\
+listDefrules(output [, module])\n\
+list defrule objects in specified defmodule to logical output\n\
+arguments:\n\
+  output (str) - logical name of stream to output to\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_listDefrules(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!", &s, &clips_DefmoduleType, &p))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ListDefrules(s, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* matches */
+static char g_matches__doc__[] = "\
+matches(output, defrule)\n\
+list defrule partial matches\n\
+arguments:\n\
+  output (str) - logical name of stream to output to\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *g_matches(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "sO!", &s, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    ACQUIRE_MEMORY_ERROR();
+    if(!Matches_PY(s, clips_defrule_value(p))) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* refresh */
+static char g_refresh__doc__[] = "\
+refresh(defrule)\n\
+refresh a defrule\n\
+arguments:\n\
+  defrule (defrule) - the defrule to refresh";
+static PyObject *g_refresh(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    ACQUIRE_MEMORY_ERROR();
+    if(!Refresh(clips_defrule_value(p))) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* removeBreak */
+static char g_removeBreak__doc__[] = "\
+removeBreak(defrule)\n\
+remove the breakpoint from a defrule\n\
+arguments:\n\
+  defrule (defrule) - the defrule to access";
+static PyObject *g_removeBreak(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    ACQUIRE_MEMORY_ERROR();
+    if(!RemoveBreak(clips_defrule_value(p))) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setBreak */
+static char g_setBreak__doc__[] = "\
+setBreak(defrule)\n\
+set a breakpoint to a defrule\n\
+arguments:\n\
+  defrule (defrule) - the defrule to access";
+static PyObject *g_setBreak(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    ACQUIRE_MEMORY_ERROR();
+    SetBreak(clips_defrule_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setDefruleWatchActivations */
+static char g_setDefruleWatchActivations__doc__[] = "\
+setDefruleWatchActivations(state, defrule)\n\
+set activations watch of a defrule to a new state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defrule (defrule) - the defrule to access";
+static PyObject *g_setDefruleWatchActivations(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+    PyObject *state = NULL;
+
+    if(!PyArg_ParseTuple(args, "OO!", &state, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    SetDefruleWatchActivations(
+        PyObject_IsTrue(state), clips_defrule_value(p));
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setDefruleWatchFirings */
+static char g_setDefruleWatchFirings__doc__[] = "\
+setDefruleWatchFirings(state, defrule)\n\
+set firings watch of a defrule to a new state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defrule (defrule) - the defrule to access";
+static PyObject *g_setDefruleWatchFirings(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+    PyObject *state = NULL;
+
+    if(!PyArg_ParseTuple(args, "OO!", &state, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_DEFRULE(p);
+    SetDefruleWatchFirings(PyObject_IsTrue(state), clips_defrule_value(p));
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setIncrementalReset */
+STATUS_FUNC_SET_BOOL(setIncrementalReset,
+                     g_setIncrementalReset,
+                     SetIncrementalReset)
+
+/* showBreaks */
+static char g_showBreaks__doc__[] = "\
+showBreaks(output [, module])\n\
+list breakpoints in specified defmodule to logical output\n\
+arguments:\n\
+  output (str) - logical name of stream to output to\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_showBreaks(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!", &s, &clips_DefmoduleType, &p))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ShowBreaks(s, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* undefrule */
+static char g_undefrule__doc__[] = "\
+undefrule([defrule])\n\
+delete a defrule object or all defrule objects\n\
+arguments:\n\
+  defrule (defrule) - the defrule to be deleted, all if omitted";
+static PyObject *g_undefrule(PyObject *self, PyObject *args) {
+    clips_DefruleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefruleType, &p)) FAIL();
+    CHECK_RM_DEFRULE(p);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Undefrule(p ? clips_defrule_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.7 - Agenda Functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *activationExists(void *ptr) {
+    void *rv = GetNextActivation(NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = GetNextActivation(rv);
+    }
+    return NULL;
+}
+#define PYACTIVATION_EXISTS(_p) activationExists(clips_activation_value(_p))
+#define CHECK_ACTIVATION(_p) do { \
+        if(!PYACTIVATION_EXISTS(_p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define CHECK_RM_ACTIVATION(_p) do { \
+        if(_p && !PYACTIVATION_EXISTS(_p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* actual function with documentation */
+
+/* addRunFunction */
+UNIMPLEMENT(addRunFunction, g_addRunFunction)
+
+/* agenda */
+static char g_agenda__doc__[] = "\
+agenda(output [, module])\n\
+list agenda rules in specified defmodule to logical output\n\
+arguments:\n\
+  output (str) - logical name of stream to output to\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_agenda(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *p = NULL;
+    char *s = NULL;
+    void *env = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!", &s, &clips_DefmoduleType, &p))
+        FAIL();
+    env = GetCurrentEnvironment();
+    if(!env) {
+        ERROR_CLIPS_NOENV();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    EnvAgenda(env, s, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* clearFocusStack */
+FUNC_VOID_ONLY(clearFocusStack, g_clearFocusStack, ClearFocusStack)
+
+/* deleteActivation */
+static char g_deleteActivation__doc__[] = "\
+deleteActivation(activation)\n\
+remove activation from agenda\n\
+arguments:\n\
+  activation (activation) - the activation to delete";
+static PyObject *g_deleteActivation(PyObject *self, PyObject *args) {
+    clips_ActivationObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_ActivationType, &p))
+        FAIL();
+    CHECK_RM_ACTIVATION(p);
+    ACQUIRE_MEMORY_ERROR();
+    if(!DeleteActivation(p ? clips_activation_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* focus */
+static char g_focus__doc__[] = "\
+focus(module)\n\
+set current focus\n\
+arguments:\n\
+  module (defmodule) - the defmodule to set focus to";
+static PyObject *g_focus(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefmoduleType, &p))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    Focus(clips_defmodule_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getActivationName */
+static char g_getActivationName__doc__[] = "\
+getActivationName(activation) -> str\n\
+retrieve the name of specified activation\n\
+returns: name as a string\n\
+arguments:\n\
+  activation (activation) - the activation to inspect";
+static PyObject *g_getActivationName(PyObject *self, PyObject *args) {
+    clips_ActivationObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_ActivationType, &p))
+        FAIL();
+    CHECK_ACTIVATION(p);
+    ACQUIRE_MEMORY_ERROR();
+    name = GetActivationName(clips_defrule_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getActivationPPForm */
+static char g_getActivationPPForm__doc__[] = "\
+getActivationPPForm(activation) -> str\n\
+retrieve the pretty-print form of specified activation\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  activation (activation) - the activation to inspect";
+static PyObject *g_getActivationPPForm(PyObject *self, PyObject *args) {
+    clips_ActivationObject *p = NULL;
+    char *buffer = NEW_ARRAY(char, ppbuffer_size);
+    PyObject *rv = NULL;
+
+    if(!buffer) {
+        ERROR_MEMORY("cannot allocate buffer");
+        FAIL();
+    }
+    if(!PyArg_ParseTuple(args, "O!", &clips_ActivationType, &p))
+        FAIL();
+    CHECK_ACTIVATION(p);
+    ACQUIRE_MEMORY_ERROR();
+    GetActivationPPForm(buffer, ppbuffer_size-1, clips_activation_value(p));
+    RELEASE_MEMORY_ERROR();
+    rv = Py_BuildValue("s", buffer);
+    DELETE(buffer);
+    return rv;
+
+BEGIN_FAIL
+    if(buffer) DELETE(buffer);
+    SKIP();
+END_FAIL
+}
+
+/* getActivationSalience */
+static char g_getActivationSalience__doc__[] = "\
+getActivationSalience(activation) -> int\n\
+retrieve the salience value of specified activation\n\
+returns: salience as integer\n\
+arguments:\n\
+  activation (activation) - the activation to inspect";
+static PyObject *g_getActivationSalience(PyObject *self, PyObject *args) {
+    clips_ActivationObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_ActivationType, &p))
+        FAIL();
+    CHECK_ACTIVATION(p);
+    ACQUIRE_MEMORY_ERROR();
+    i = GetActivationSalience(clips_defrule_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getAgendaChanged */
+STATUS_FUNC_GET_BOOL(getAgendaChanged, g_getAgendaChanged, GetAgendaChanged)
+
+/* getFocus */
+static char g_getFocus__doc__[] = "\
+getFocus() -> defmodule\n\
+retrieve the module with associated focus\n\
+returns: the defmodule with focus as a new object";
+static PyObject *g_getFocus(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *p = NULL;
+    void *ptr = NULL;
+
+    CHECK_NOARGS(args);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetFocus();
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    clips_defmodule_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defmodule_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getFocusStack */
+static char g_getFocusStack__doc__[] = "\
+getFocusStack() -> (MULTIFIELD, list)\n\
+retrieve the module names in the focus stack\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)";
+static PyObject *g_getFocusStack(PyObject *self, PyObject *args) {
+    DATA_OBJECT o = { 0 };
+    PyObject *p = NULL;
+    void *env = NULL;
+
+    CHECK_NOARGS(args);
+    env = GetCurrentEnvironment();
+    if(!env) {
+        ERROR_CLIPS_NOENV();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetFocusStack(env, &o);
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getNextActivation */
+static char g_getNextActivation__doc__[] = "\
+getNextActivation([activation]) -> activation\n\
+retrieve next activation object in list, first if argument is omitted\n\
+returns: an activation object, None if already at last activation\n\
+arguments:\n\
+  activation (activation) - the activation to start from";
+static PyObject *g_getNextActivation(PyObject *self, PyObject *args) {
+    clips_ActivationObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_ActivationType, &p))
+        FAIL();
+    if(p) { CHECK_ACTIVATION(p); }
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextActivation(p ? clips_activation_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_activation_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_activation_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* getSalienceEvaluation */
+STATUS_FUNC_GET(getSalienceEvaluation,
+                g_getSalienceEvaluation,
+                GetSalienceEvaluation,
+                "i")
+
+/* getStrategy */
+FUNC_GET_ONLY(getStrategy, g_getStrategy, GetStrategy, "i")
+
+/* listFocusStack */
+static char g_listFocusStack__doc__[] = "\
+listFocusStack(output)\n\
+print current focus stack\n\
+arguments:\n\
+  output (str) - logical name of output stream";
+static PyObject *g_listFocusStack(PyObject *self, PyObject *args) {
+    char *output = NULL;
+    void *env = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &output))
+        FAIL();
+    env = GetCurrentEnvironment();
+    if(!env) {
+        ERROR_CLIPS_NOENV();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    EnvListFocusStack(env, output);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* popFocus */
+FUNC_VOID_ONLY(popFocus, g_popFocus, PopFocus)
+
+/* refreshAgenda */
+static char g_refreshAgenda__doc__[] = "\
+refreshAgenda([module])\n\
+refresh agenda for specified defmodule\n\
+arguments:\n\
+  module (defmodule) - the defmodule to process, all if omitted";
+static PyObject *g_refreshAgenda(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    void *env = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefmoduleType, &module))
+        FAIL();
+    env = GetCurrentEnvironment();
+    if(!env) {
+        ERROR_CLIPS_NOENV();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    EnvRefreshAgenda(env, module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* removeRunFunction */
+UNIMPLEMENT(removeRunFunction, g_removeRunFunction)
+
+/* reorderAgenda */
+static char g_reorderAgenda__doc__[] = "\
+reorderAgenda([module])\n\
+reorder agenda for specified defmodule\n\
+arguments:\n\
+  module (defmodule) - the defmodule to process, all if omitted";
+static PyObject *g_reorderAgenda(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    void *env = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefmoduleType, &module))
+        FAIL();
+    env = GetCurrentEnvironment();
+    if(!env) {
+        ERROR_CLIPS_NOENV();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    EnvReorderAgenda(env, module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* run */
+static char g_run__doc__[] = "\
+run([limit]) -> fired\n\
+execute rules\n\
+returns: the number of fired rules\n\
+arguments:\n\
+  limit (int) - number of rules to fire, all if omitted";
+static PyObject *g_run(PyObject *self, PyObject *args) {
+    long runlimit = -1;
+
+    if(!PyArg_ParseTuple(args, "|i", &runlimit))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    runlimit = Run(runlimit);
+    RELEASE_MEMORY_ERROR();
+    RETURN_INT(runlimit);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setActivationSalience */
+static char g_setActivationSalience__doc__[] = "\
+setActivationSalience(activation, salience) -> int\n\
+set the new activation salience\n\
+returns: the old value\n\
+arguments:\n\
+  activation (activation) - an activation object\n\
+  salience (int) - the new activation salience";
+static PyObject *g_setActivationSalience(PyObject *self, PyObject *args) {
+    clips_ActivationObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!i", &clips_ActivationType, &p, &i))
+        FAIL();
+    CHECK_ACTIVATION(p);
+    ACQUIRE_MEMORY_ERROR();
+    i = SetActivationSalience(clips_activation_value(p), i);
+    RELEASE_MEMORY_ERROR();
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setAgendaChanged */
+STATUS_FUNC_SET_BOOL(setAgendaChanged, g_setAgendaChanged, SetAgendaChanged)
+
+/* setSalienceEvaluation */
+static char g_setSalienceEvaluation__doc__[] = "\
+setSalienceEvaluation(mode)\n\
+set the new salience evaluation mode\n\
+arguments:\n\
+  mode (int) - the new evaluation mode";
+static PyObject *g_setSalienceEvaluation(PyObject *self, PyObject *args) {
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "i", &i))
+        FAIL();
+    if(i != WHEN_DEFINED && i != WHEN_ACTIVATED && i != EVERY_CYCLE) {
+        ERROR_VALUE("invalid evaluation mode");
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    SetSalienceEvaluation(i);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setStrategy */
+static char g_setStrategy__doc__[] = "\
+setStrategy(mode)\n\
+set the new strategy\n\
+arguments:\n\
+  strategy (int) - the new strategy";
+static PyObject *g_setStrategy(PyObject *self, PyObject *args) {
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "i", &i)) FAIL();
+    if(i != DEPTH_STRATEGY && i != BREADTH_STRATEGY && i != LEX_STRATEGY &&
+       i != MEA_STRATEGY && i != COMPLEXITY_STRATEGY &&
+       i != SIMPLICITY_STRATEGY && i != RANDOM_STRATEGY) {
+        ERROR_VALUE("invalid strategy");
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    SetStrategy(i);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.8 Defglobal Functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *defglobalExists(void *ptr) {
+    void *rv = GetNextDefglobal(NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = GetNextDefglobal(rv);
+    }
+    return NULL;
+}
+#define PYDEFGLOBAL_EXISTS(_p) defglobalExists(clips_defglobal_value(_p))
+#define CHECK_DEFGLOBAL(_p) do { \
+        if(!PYDEFGLOBAL_EXISTS(_p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define CHECK_RM_DEFGLOBAL(_p) do { \
+        if(_p && !PYDEFGLOBAL_EXISTS(_p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* actual function with documentation */
+
+/* defglobalModule */
+static char g_defglobalModule__doc__[] = "\
+defglobalModule(defglobal) -> str\n\
+retrieve the module name where specified defglobal is defined\n\
+returns: module name as string\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to inspect";
+static PyObject *g_defglobalModule(PyObject *self, PyObject *args) {
+    clips_DefglobalObject *p = NULL;
+    char *module = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_DEFGLOBAL(p);
+    ACQUIRE_MEMORY_ERROR();
+    module = DefglobalModule(clips_defglobal_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!module) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    return Py_BuildValue("s", module);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* findDefglobal */
+static char g_findDefglobal__doc__[] = "\
+findDefglobal(name) -> defglobal\n\
+return the defglobal object associated with name\n\
+returns: the defglobal as a new object\n\
+arguments:\n\
+  name (str) - the name to look for";
+static PyObject *g_findDefglobal(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DefglobalObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = FindDefglobal(name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_defglobal_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defglobal_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefglobalList */
+static char g_getDefglobalList__doc__[] = "\
+getDefglobalList([module]) -> (MULTIFIELD, list)\n\
+retrieve the list of defglobal objects in the specified defmodule\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_getDefglobalList(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    GetDefglobalList(&o, module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefglobalName */
+static char g_getDefglobalName__doc__[] = "\
+getDefglobalName(defglobal) -> str\n\
+retrieve the name of specified defglobal\n\
+returns: name as a string\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to inspect";
+static PyObject *g_getDefglobalName(PyObject *self, PyObject *args) {
+    clips_DefglobalObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_DEFGLOBAL(p);
+    name = GetDefglobalName(clips_defglobal_value(p));
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefglobalPPForm */
+static char g_getDefglobalPPForm__doc__[] = "\
+getDefglobalPPForm(defglobal) -> str\n\
+retrieve the pretty-print form of specified defglobal\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to inspect";
+static PyObject *g_getDefglobalPPForm(PyObject *self, PyObject *args) {
+    clips_DefglobalObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_DEFGLOBAL(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = GetDefglobalPPForm(clips_defglobal_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefglobalValue */
+static char g_getDefglobalValue__doc__[] = "\
+getDefglobalValue(name) -> (type, value)\n\
+retrieve the value of specified defglobal\n\
+returns: value as a pair (type, value)\n\
+arguments:\n\
+  name (str) - the name of the defglobal";
+static PyObject *g_getDefglobalValue(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+    void *env = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    env = GetCurrentEnvironment();
+    if(!env) {
+        ERROR_CLIPS_NOENV();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvGetDefglobalValue(env, name, &o)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefglobalValueForm */
+static char g_getDefglobalValueForm__doc__[] = "\
+getDefglobalValueForm(defglobal) -> str\n\
+retrieve the pretty-print form of specified defglobal\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to inspect";
+static PyObject *g_getDefglobalValueForm(PyObject *self, PyObject *args) {
+    clips_DefglobalObject *p = NULL;
+    char *buffer = NEW_ARRAY(char, ppbuffer_size);
+    PyObject *rv = NULL;
+
+    if(!buffer) {
+        ERROR_MEMORY("cannot allocate buffer");
+        FAIL();
+    }
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_DEFGLOBAL(p);
+    ACQUIRE_MEMORY_ERROR();
+    GetDefglobalValueForm(buffer, ppbuffer_size-1, clips_defglobal_value(p));
+    RELEASE_MEMORY_ERROR();
+    rv = Py_BuildValue("s", buffer);
+    DELETE(buffer);
+    return rv;
+
+BEGIN_FAIL
+    if(buffer) DELETE(buffer);
+    SKIP();
+END_FAIL
+}
+
+/* getDefglobalWatch */
+static char g_getDefglobalWatch__doc__[] = "\
+getDefglobalWatch(defglobal) -> bool\n\
+tell whether or not the defglobal is being watched\n\
+returns: True if the defglobal is being watched, False otherwise\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to inspect";
+static PyObject *g_getDefglobalWatch(PyObject *self, PyObject *args) {
+    clips_DefglobalObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_DEFGLOBAL(p);
+    i = GetDefglobalWatch(clips_defglobal_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getGlobalsChanged */
+STATUS_FUNC_GET_BOOL(getGlobalsChanged, g_getGlobalsChanged, GetGlobalsChanged)
+
+/* getNextDefglobal */
+static char g_getNextDefglobal__doc__[] = "\
+getNextDefglobal([defglobal]) -> defglobal\n\
+retrieve next defglobal object in list, first if argument is omitted\n\
+returns: a defglobal object, None if already at last defglobal\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to start from";
+static PyObject *g_getNextDefglobal(PyObject *self, PyObject *args) {
+    clips_DefglobalObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefglobalType, &p))
+        FAIL();
+    if(p)
+        CHECK_DEFGLOBAL(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextDefglobal(p ? clips_defglobal_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_defglobal_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defglobal_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* getResetGlobals */
+STATUS_FUNC_GET_BOOL(getResetGlobals, g_getResetGlobals, GetResetGlobals)
+
+/* isDefglobalDeletable */
+static char g_isDefglobalDeletable__doc__[] = "\
+isDefglobalDeletable(defglobal) -> bool\n\
+tell whether or not the defglobal is deletable\n\
+returns: True if the defglobal can be deleted, False otherwise\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to be inspected";
+static PyObject *g_isDefglobalDeletable(PyObject *self, PyObject *args) {
+    clips_DefglobalObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_DEFGLOBAL(p);
+    i = IsDefglobalDeletable(clips_defglobal_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* listDefglobals */
+static char g_listDefglobals__doc__[] = "\
+listDefglobals(logicalname [, module])\n\
+list defglobals to output identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_listDefglobals(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!", &lname, &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ListDefglobals(lname, module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setDefglobalValue */
+static char g_setDefglobalValue__doc__[] = "\
+setDefglobalValue(name, value)\n\
+set the value of passed in defglobal\n\
+arguments:\n\
+  name (str) - the name of defglobal to change\n\
+  value (pair) - a pair (type, value)";
+static PyObject *g_setDefglobalValue(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "sO", &name, &p))
+        FAIL();
+    if(!i_py2do(p, &o)) {
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!SetDefglobalValue(name, &o)) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    Py_XDECREF(p);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* setDefglobalWatch */
+static char g_setDefglobalWatch__doc__[] = "\
+setDefglobalWatch(state, defglobal)\n\
+set the specified defglobal to a particular watch state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defglobal (defglobal) - the defglobal object";
+static PyObject *g_setDefglobalWatch(PyObject *self, PyObject *args) {
+    PyObject *state = NULL;
+    clips_DefglobalObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "OO!", &state, &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_DEFGLOBAL(p);
+    SetDefglobalWatch(PyObject_IsTrue(state), clips_defglobal_value(p));
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setGlobalsChanged */
+STATUS_FUNC_SET_BOOL(setGlobalsChanged, g_setGlobalsChanged, SetGlobalsChanged)
+
+/* setResetGlobals */
+STATUS_FUNC_SET_BOOL(setResetGlobals, g_setResetGlobals, SetResetGlobals)
+
+/* showDefglobals */
+static char g_showDefglobals__doc__[] = "\
+showDefglobals(output [, module])\n\
+list defglobals in specified defmodule to logical output\n\
+arguments:\n\
+  output (str) - logical name of stream to output to\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_showDefglobals(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!", &s, &clips_DefmoduleType, &p))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ShowDefglobals(s, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* undefglobal */
+static char g_undefglobal__doc__[] = "\
+undefglobal([defglobal])\n\
+delete a defglobal object or all defglobal objects\n\
+arguments:\n\
+  defglobal (defglobal) - object to be deleted, all if omitted";
+static PyObject *g_undefglobal(PyObject *self, PyObject *args) {
+    clips_DefglobalObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_RM_DEFGLOBAL(p);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Undefglobal(p ? clips_defglobal_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.9 Deffunction Functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *deffunctionExists(void *ptr) {
+    void *rv = GetNextDeffunction(NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = GetNextDeffunction(rv);
+    }
+    return NULL;
+}
+#define PYDEFFUNCTION_EXISTS(_p) deffunctionExists(clips_deffunction_value(_p))
+#define CHECK_DEFFUNCTION(_p) do { \
+        if(!PYDEFFUNCTION_EXISTS(_p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define CHECK_RM_DEFFUNCTION(_p) do { \
+        if(_p && !PYDEFFUNCTION_EXISTS(_p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* actual function with documentation */
+
+/* deffunctionModule */
+static char g_deffunctionModule__doc__[] = "\
+deffunctionModule(deffunction) -> str\n\
+retrieve the module name where specified deffunction is defined\n\
+returns: module name as string\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to inspect";
+static PyObject *g_deffunctionModule(PyObject *self, PyObject *args) {
+    clips_DeffunctionObject *p = NULL;
+    char *module = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_DEFFUNCTION(p);
+    ACQUIRE_MEMORY_ERROR();
+    module = DeffunctionModule(clips_deffunction_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!module) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    return Py_BuildValue("s", module);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* findDeffunction */
+static char g_findDeffunction__doc__[] = "\
+findDeffunction(name) -> deffunction\n\
+return the deffunction object associated with name\n\
+returns: the deffunction as a new object\n\
+arguments:\n\
+  name (str) - the name to look for";
+static PyObject *g_findDeffunction(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DeffunctionObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = FindDeffunction(name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_deffunction_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deffunction_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDeffunctionList */
+static char g_getDeffunctionList__doc__[] = "\
+getDeffunctionList([module]) -> (MULTIFIELD, list)\n\
+retrieve the list of deffunction objects in the specified defmodule\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_getDeffunctionList(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    GetDeffunctionList(&o, module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDeffunctionName */
+static char g_getDeffunctionName__doc__[] = "\
+getDeffunctionName(deffunction) -> str\n\
+retrieve the name of specified deffunction\n\
+returns: name as a string\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to inspect";
+static PyObject *g_getDeffunctionName(PyObject *self, PyObject *args) {
+    clips_DeffunctionObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_DEFFUNCTION(p);
+    ACQUIRE_MEMORY_ERROR();
+    name = GetDeffunctionName(clips_deffunction_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDeffunctionPPForm */
+static char g_getDeffunctionPPForm__doc__[] = "\
+getDeffunctionPPForm(deffunction) -> str\n\
+retrieve the pretty-print form of specified deffunction\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to inspect";
+static PyObject *g_getDeffunctionPPForm(PyObject *self, PyObject *args) {
+    clips_DeffunctionObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_DEFFUNCTION(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = GetDeffunctionPPForm(clips_deffunction_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDeffunctionWatch */
+static char g_getDeffunctionWatch__doc__[] = "\
+getDeffunctionWatch(deffunction) -> bool\n\
+tell whether or not the deffunction is being watched\n\
+returns: True if the deffunction is being watched, False otherwise\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to inspect";
+static PyObject *g_getDeffunctionWatch(PyObject *self, PyObject *args) {
+    clips_DeffunctionObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeffunctionType, &p))
+        FAIL();
+    i = GetDeffunctionWatch(clips_deffunction_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getNextDeffunction */
+static char g_getNextDeffunction__doc__[] = "\
+getNextDeffunction([deffunction]) -> deffunction\n\
+retrieve next deffunction object in list, first if argument is omitted\n\
+returns: a deffunction object, None if already at last deffunction\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to start from";
+static PyObject *g_getNextDeffunction(PyObject *self, PyObject *args) {
+    clips_DeffunctionObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DeffunctionType, &p))
+        FAIL();
+    if(p) CHECK_DEFFUNCTION(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextDeffunction(p ? clips_deffunction_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_deffunction_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deffunction_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* isDeffunctionDeletable */
+static char g_isDeffunctionDeletable__doc__[] = "\
+isDeffunctionDeletable(deffunction) -> bool\n\
+tell whether or not the deffunction is deletable\n\
+returns: True if the deffunction can be deleted, False otherwise\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to be inspected";
+static PyObject *g_isDeffunctionDeletable(PyObject *self, PyObject *args) {
+    clips_DeffunctionObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_DEFFUNCTION(p);
+    i = IsDeffunctionDeletable(clips_deffunction_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* listDeffunctions */
+static char g_listDeffunctions__doc__[] = "\
+listDeffunctions(logicalname [, module])\n\
+list deffunctions to output identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_listDeffunctions(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!", &lname, &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ListDeffunctions(lname, module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setDeffunctionWatch */
+static char g_setDeffunctionWatch__doc__[] = "\
+setDeffunctionWatch(state, deffunction)\n\
+set the specified deffunction to a particular watch state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  deffunction (deffunction) - the deffunction object";
+static PyObject *g_setDeffunctionWatch(PyObject *self, PyObject *args) {
+    PyObject *state = NULL;
+    clips_DeffunctionObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "OO!", &state, &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_DEFFUNCTION(p);
+    ACQUIRE_MEMORY_ERROR();
+    SetDeffunctionWatch(PyObject_IsTrue(state), clips_deffunction_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* undeffunction */
+static char g_undeffunction__doc__[] = "\
+undeffunction([deffunction])\n\
+delete a deffunction object or all deffunction objects\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to delete, all if omitted";
+static PyObject *g_undeffunction(PyObject *self, PyObject *args) {
+    clips_DeffunctionObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_RM_DEFFUNCTION(p);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Undeffunction(p ? clips_deffunction_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.10 Defgeneric Functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *defgenericExists(void *ptr) {
+    void *rv = GetNextDefgeneric(NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = GetNextDefgeneric(rv);
+    }
+    return NULL;
+}
+#define PYDEFGENERIC_EXISTS(_p) defgenericExists(clips_defgeneric_value(_p))
+#define CHECK_DEFGENERIC(_p) do { \
+        if(!PYDEFGENERIC_EXISTS(_p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define CHECK_RM_DEFGENERIC(_p) do { \
+        if(_p && !PYDEFGENERIC_EXISTS(_p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* actual function with documentation */
+
+/* defgenericModule */
+static char g_defgenericModule__doc__[] = "\
+defgenericModule(defgeneric) -> str\n\
+retrieve the module name where specified defgeneric is defined\n\
+returns: module name as string\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *g_defgenericModule(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL;
+    char *module = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_DEFGENERIC(p);
+    ACQUIRE_MEMORY_ERROR();
+    module = DefgenericModule(clips_defgeneric_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!module) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    return Py_BuildValue("s", module);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* findDefgeneric */
+static char g_findDefgeneric__doc__[] = "\
+findDefgeneric(name) -> defgeneric\n\
+return the defgeneric object associated with name\n\
+returns: the defgeneric as a new object\n\
+arguments:\n\
+  name (str) - the name to look for";
+static PyObject *g_findDefgeneric(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DefgenericObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = FindDefgeneric(name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_defgeneric_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defgeneric_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefgenericList */
+static char g_getDefgenericList__doc__[] = "\
+getDefgenericList([module]) -> (MULTIFIELD, list)\n\
+retrieve the list of defgeneric objects in the specified defmodule\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_getDefgenericList(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    GetDefgenericList(&o, module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefgenericName */
+static char g_getDefgenericName__doc__[] = "\
+getDefgenericName(defgeneric) -> str\n\
+retrieve the name of specified defgeneric\n\
+returns: name as a string\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *g_getDefgenericName(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_DEFGENERIC(p);
+    ACQUIRE_MEMORY_ERROR();
+    name = GetDefgenericName(clips_deffunction_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefgenericPPForm */
+static char g_getDefgenericPPForm__doc__[] = "\
+getDefgenericPPForm(defgeneric) -> str\n\
+retrieve the pretty-print form of specified defgeneric\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *g_getDefgenericPPForm(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_DEFGENERIC(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = GetDefgenericPPForm(clips_defgeneric_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefgenericWatch */
+static char g_getDefgenericWatch__doc__[] = "\
+getDefgenericWatch(defgeneric) -> bool\n\
+tell whether or not the defgeneric is being watched\n\
+returns: True if the defgeneric is being watched, False otherwise\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *g_getDefgenericWatch(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_DEFGENERIC(p);
+    i = GetDefgenericWatch(clips_deffunction_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getNextDefgeneric */
+static char g_getNextDefgeneric__doc__[] = "\
+getNextDefgeneric([defgeneric]) -> defgeneric\n\
+retrieve next defgeneric object in list, first if argument is omitted\n\
+returns: a defgeneric object, None if already at last defgeneric\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to start from";
+static PyObject *g_getNextDefgeneric(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefgenericType, &p))
+        FAIL();
+    if(p)
+        CHECK_DEFGENERIC(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextDefgeneric(p ? clips_defgeneric_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_defgeneric_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defgeneric_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* isDefgenericDeletable */
+static char g_isDefgenericDeletable__doc__[] = "\
+isDefgenericDeletable(defgeneric) -> bool\n\
+tell whether or not the defgeneric is deletable\n\
+returns: True if the defgeneric can be deleted, False otherwise\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to be inspected";
+static PyObject *g_isDefgenericDeletable(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_DEFGENERIC(p);
+    i = IsDefgenericDeletable(clips_defgeneric_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* listDefgenerics */
+static char g_listDefgenerics__doc__[] = "\
+listDefgenerics(logicalname [, module])\n\
+list defgeneric objects to output identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_listDefgenerics(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!", &lname, &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ListDefgenerics(lname, module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setDefgenericWatch */
+static char g_setDefgenericWatch__doc__[] = "\
+setDefgenericWatch(state, defgeneric)\n\
+set the specified defgeneric to a particular watch state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defgeneric (defgeneric) - the defgeneric object";
+static PyObject *g_setDefgenericWatch(PyObject *self, PyObject *args) {
+    PyObject *state = NULL;
+    clips_DefgenericObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "OO!", &state, &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_DEFGENERIC(p);
+    ACQUIRE_MEMORY_ERROR();
+    SetDefgenericWatch(PyObject_IsTrue(state), clips_defgeneric_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* undefgeneric */
+static char g_undefgeneric__doc__[] = "\
+undefgeneric([defgeneric])\n\
+delete a defgeneric object or all defgeneric objects\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to delete, all if omitted";
+static PyObject *g_undefgeneric(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_RM_DEFGENERIC(p);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Undefgeneric(p ? clips_defgeneric_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.11 - Defmethod functions */
+
+/* getDefmethodDescription */
+static char g_getDefmethodDescription__doc__[] = "\
+getDefmethodDescription(index, defgeneric) -> str\n\
+describe method parameter restrictions\n\
+returns: the description as a string\n\
+arguments:\n\
+  index (int) - index of method\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *g_getDefmethodDescription(PyObject *self, PyObject *args) {
+    char *buffer = NEW_ARRAY(char, ppbuffer_size);
+    PyObject *rv = NULL;
+    int i = 0;
+    clips_DefgenericObject *p = NULL;
+
+    if(!buffer) {
+        ERROR_MEMORY("cannot allocate buffer");
+        FAIL();
+    }
+    if(!PyArg_ParseTuple(args, "iO!", &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    GetDefmethodDescription(buffer, ppbuffer_size-1, clips_defgeneric_value(p), i);
+    RELEASE_MEMORY_ERROR();
+    rv = Py_BuildValue("s", buffer);
+    DELETE(buffer);
+    return rv;
+
+BEGIN_FAIL
+    if(buffer) DELETE(buffer);
+    SKIP();
+END_FAIL
+}
+
+/* getDefmethodList */
+static char g_getDefmethodList__doc__[] = "\
+getDefmethodList([defgeneric]) -> (MULTIFIELD, list)\n\
+retrieve the list of defmethods in the specified defgeneric\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to inspect, all if omitted";
+static PyObject *g_getDefmethodList(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *g = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefgenericType, &g))
+        FAIL();
+    if(g)
+        CHECK_DEFGENERIC(g);
+    ACQUIRE_MEMORY_ERROR();
+    GetDefmethodList(g ? clips_defgeneric_value(g) : NULL, &o);
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefmethodPPForm */
+static char g_getDefmethodPPForm__doc__[] = "\
+getDefmethodPPForm(index, defgeneric) -> str\n\
+retrieve the pretty-print form of specified defmethod\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  index (int) - index of method\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *g_getDefmethodPPForm(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "iO!", &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_DEFGENERIC(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = GetDefmethodPPForm(clips_defgeneric_value(p), i);
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefmethodWatch */
+static char g_getDefmethodWatch__doc__[] = "\
+getDefmethodWatch(index, defgeneric) -> bool\n\
+tell whether or not a defgeneric method is being watched\n\
+returns: True if the method is being watched, False otherwise\n\
+arguments:\n\
+  index (int) - index of method\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *g_getDefmethodWatch(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL;
+    int i = 0, j = 0;
+
+    if(!PyArg_ParseTuple(args, "iO!", &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_DEFGENERIC(p);
+    j = GetDefmethodWatch(clips_defgeneric_value(p), i);
+    RETURN_BOOL(j);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getMethodRestrictions */
+static char g_getMethodRestrictions__doc__[] = "\
+getMethodRestrictions(index, defgeneric) -> (MULTIFIELD, list)\n\
+retrieve restriction for specified defmethod\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  index (int) - index of method\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *g_getMethodRestrictions(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL;
+    PyObject *q = NULL;
+    int i = 0;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "i|O!", &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_DEFGENERIC(p);
+    ACQUIRE_MEMORY_ERROR();
+    GetMethodRestrictions(p ? clips_defgeneric_value(p) : NULL, i, &o);
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* getNextDefmethod */
+static char g_getNextDefmethod__doc__[] = "\
+getNextDefmethod(index, defgeneric) -> int\n\
+return index of next defmethod in defgeneric object\n\
+returns: an integer value\n\
+arguments:\n\
+  index (int) - index of method, zero for first method\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *g_getNextDefmethod(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL;
+    int i = 0, j = 0;
+
+    if(!PyArg_ParseTuple(args, "iO!", &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i < 0) {
+        ERROR_VALUE("index must be positive or zero");
+        FAIL();
+    }
+    CHECK_DEFGENERIC(p);
+    ACQUIRE_MEMORY_ERROR();     /* needed? */
+    j = GetNextDefmethod(p ? clips_defgeneric_value(p) : NULL, i);
+    RELEASE_MEMORY_ERROR();
+    return Py_BuildValue("i", j);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* isDefmethodDeletable */
+static char g_isDefmethodDeletable__doc__[] = "\
+isDefmethodDeletable(index, defgeneric) -> bool\n\
+tell whether the specified method is deletable or not\n\
+returns: True if the method can be deleted, False otherwise\n\
+arguments:\n\
+  index (int) - index of method, zero for first method\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *g_isDefmethodDeletable(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL;
+    int i = 0, j = 0;
+
+    if(!PyArg_ParseTuple(args, "iO!", &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i < 0) {
+        ERROR_VALUE("index must be positive or zero");
+        FAIL();
+    }
+    CHECK_DEFGENERIC(p);
+    j = IsDefmethodDeletable(p ? clips_defgeneric_value(p) : NULL, i);
+    RETURN_BOOL(j);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* listDefmethods */
+static char g_listDefmethods__doc__[] = "\
+listDefmethods(output, defgeneric)\n\
+list the defmethod in the defgeneric object\n\
+arguments:\n\
+  output (str) - logical name of output stream\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *g_listDefmethods(PyObject *self, PyObject *args) {
+    clips_DefgenericObject *p = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!", &lname, &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_DEFGENERIC(p);
+    ACQUIRE_MEMORY_ERROR();
+    ListDefmethods(lname, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setDefmethodWatch */
+static char g_setDefmethodWatch__doc__[] = "\
+setDefmethodWatch(state, index, defgeneric)\n\
+set the specified defgeneric to a particular watch state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defgeneric (defgeneric) - the defgeneric object";
+static PyObject *g_setDefmethodWatch(PyObject *self, PyObject *args) {
+    int i = 0;
+    PyObject *state = NULL;
+    clips_DefgenericObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "OiO!", &state, &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_DEFGENERIC(p);
+    SetDefmethodWatch(PyObject_IsTrue(state), clips_defgeneric_value(p), i);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* undefmethod */
+static char g_undefmethod__doc__[] = "\
+undefmethod([index, defgeneric])\n\
+delete a defmethod object or all defmethod objects\n\
+arguments:\n\
+  index (int) - index of defmethod to delete, all if omitted\n\
+  defgeneric (defgeneric) - referred defgeneric, all if omitted";
+static PyObject *g_undefmethod(PyObject *self, PyObject *args) {
+    int i = 0;
+    clips_DefgenericObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "|iO!", &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i < 0) {
+        ERROR_VALUE("index must be positive or zero");
+        FAIL();
+    }
+    if(i != 0 && !p) {
+        ERROR_VALUE("both arguments must be omitted or specified");
+        FAIL();
+    }
+    if(p)
+        CHECK_DEFGENERIC(p);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Undefmethod(p ? clips_defgeneric_value(p) : NULL, i)) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.12 - Defclass Functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *defclassExists(void *ptr) {
+    void *rv = GetNextDefclass(NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = GetNextDefclass(rv);
+    }
+    return NULL;
+}
+#define PYDEFCLASS_EXISTS(_p) defclassExists(clips_defclass_value(_p))
+#define CHECK_DEFCLASS(_p) do { \
+        if(!PYDEFCLASS_EXISTS(_p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define CHECK_RM_DEFCLASS(_p) do { \
+        if(_p && !PYDEFCLASS_EXISTS(_p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* actual function with documentation */
+
+/* browseClasses */
+static char g_browseClasses__doc__[] = "\
+browseClasses(output, defclass)\n\
+print the classes who inherit from specified one in a graph form\n\
+arguments:\n\
+  output (str) - the name of logical output\n\
+  defclass (defclass) - the defclass to inspect";
+static PyObject *g_browseClasses(PyObject *self, PyObject *args) {
+    char *s = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "sO!", &s, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    BrowseClasses(s, clips_defclass_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* classAbstractP */
+static char g_classAbstractP__doc__[] = "\
+classAbstractP(defclass) -> bool\n\
+tell if class is abstract or concrete\n\
+returns: True if the class is abstract, False if concrete\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect";
+static PyObject *g_classAbstractP(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefclassType, &p))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    i = ClassAbstractP(clips_defclass_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* classReactiveP */
+static char g_classReactiveP__doc__[] = "\
+classReactiveP(defclass) -> bool\n\
+tell if class is reactive (matches object patterns) or not\n\
+returns: True if the class is reactive, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect";
+static PyObject *g_classReactiveP(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefclassType, &p))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    i = ClassReactiveP(clips_defclass_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* classSlots */
+static char g_classSlots__doc__[] = "\
+classSlots(defclass, inherit) -> (MULTIFIELD, list)\n\
+return names of slots of the passed in class\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  inherit (bool) - True to include inherited slots, False otherwise";
+static PyObject *g_classSlots(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O", &clips_DefclassType, &p, &q))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    ClassSlots(clips_defclass_value(p), &o, PyObject_IsTrue(q));
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* classSubclasses */
+static char g_classSubclasses__doc__[] = "\
+classSubclasses(defclass, inherit) -> (MULTIFIELD, list)\n\
+return names of subclasses for the passed in class\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  inherit (bool) - True to include inherited slots, False otherwise";
+static PyObject *g_classSubclasses(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O", &clips_DefclassType, &p, &q))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    ClassSubclasses(clips_defclass_value(p), &o, PyObject_IsTrue(q));
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* classSuperclasses */
+static char g_classSuperclasses__doc__[] = "\
+classSuperclasses(defclass, inherit) -> (MULTIFIELD, list)\n\
+return names of superclasses for the passed in class\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  inherit (bool) - True to include inherited slots, False otherwise";
+static PyObject *g_classSuperclasses(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O", &clips_DefclassType, &p, &q))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    ClassSuperclasses(clips_defclass_value(p), &o, PyObject_IsTrue(q));
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* defclassModule */
+static char g_defclassModule__doc__[] = "\
+defclassModule(defclass) -> str\n\
+retrieve the name of the module where the provided defclass resides\n\
+returns: a string containing a module name\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect";
+static PyObject *g_defclassModule(PyObject *self, PyObject *args) {
+    char *module = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefclassType, &p))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    module = DefclassModule(clips_defclass_value(p));
+    if(!module) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    return Py_BuildValue("s", module);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* describeClass */
+static char g_describeClass__doc__[] = "\
+describeClass(output, defclass)\n\
+print a descriptive summary of class\n\
+arguments:\n\
+  output (str) - logical name of output stream\n\
+  defclass (defclass) - the defclass to inspect";
+static PyObject *g_describeClass(PyObject *self, PyObject *args) {
+    char *lname = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "sO!", &lname, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    DescribeClass(lname, clips_defclass_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* findDefclass */
+static char g_findDefclass__doc__[] = "\
+findDefclass(name) -> defclass\n\
+retrieve defclass object corresponding to the specified name\n\
+returns: the defclass as a new object\n\
+arguments:\n\
+  name (str) - the name of the defclass to look for";
+static PyObject *g_findDefclass(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = FindDefclass(name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_defclass_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defclass_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getClassDefaultsMode */
+FUNC_GET_ONLY(getClassDefaultsMode,
+              g_getClassDefaultsMode,
+              GetClassDefaultsMode,
+              "i")
+
+/* getDefclassList */
+static char g_getDefclassList__doc__[] = "\
+getDefclassList([module]) -> (MULTIFIELD, list)\n\
+retrieve list of defclass objects names in specified defmodule\n\
+returns:  MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_getDefclassList(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    GetDefclassList(&o, module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefclassName */
+static char g_getDefclassName__doc__[] = "\
+getDefclassName(defclass) -> str\n\
+retrieve the name of given defclass object\n\
+returns: a string containing the name\n\
+arguments:\n\
+  defclass (defclass) - the defclass object";
+static PyObject *g_getDefclassName(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefclassType, &p))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    name = GetDefclassName(clips_defclass_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefclassPPForm */
+static char g_getDefclassPPForm__doc__[] = "\
+getDefclassPPForm(defclass) -> str\n\
+retrieve the pretty-print form of given defclass object\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defclass (defclass) - the defclass object";
+static PyObject *g_getDefclassPPForm(PyObject *self, PyObject *args) {
+    char *s = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefclassType, &p))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = GetDefclassPPForm(clips_defclass_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefclassWatchInstances */
+static char g_getDefclassWatchInstances__doc__[] = "\
+getDefclassWatchInstances(defclass) -> bool\n\
+tell if defclass instances are being watched\n\
+returns: True if defclass instances are being watched, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass object";
+static PyObject *g_getDefclassWatchInstances(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefclassType, &p))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    i = GetDefclassWatchInstances(clips_defclass_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefclassWatchSlots */
+static char g_getDefclassWatchSlots__doc__[] = "\
+getDefclassWatchSlots(defclass) -> bool\n\
+tell if defclass slots are being watched\n\
+returns: True if defclass slots are being watched, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass object";
+static PyObject *g_getDefclassWatchSlots(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefclassType, &p))
+        FAIL();
+    i = GetDefclassWatchSlots(clips_defclass_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getNextDefclass */
+static char g_getNextDefclass__doc__[] = "\
+getNextDefclass([defclass]) -> defclass\n\
+find next defclass in the list, first if argument is omitted\n\
+returns: next defclass object, None if already at last defclass\n\
+arguments:\n\
+  defclass (defclass) - the defclass to start from";
+static PyObject *g_getNextDefclass(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefclassType, &p))
+        FAIL();
+    if(p)
+        CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextDefclass(p ? clips_defclass_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_defclass_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defclass_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* isDefclassDeletable */
+static char g_isDefclassDeletable__doc__[] = "\
+isDefclassDeletable(defclass) -> bool\n\
+tell whether or not the defclass can be deleted\n\
+returns: True if the defclass can be deleted, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass object";
+static PyObject *g_isDefclassDeletable(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefclassType, &p)) FAIL();
+    CHECK_DEFCLASS(p);
+    i = IsDefclassDeletable(clips_defclass_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* listDefclasses */
+static char g_listDefclasses__doc__[] = "\
+listDefclasses(logicalname [, module])\n\
+list defclasses to output identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_listDefclasses(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!", &lname, &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ListDefclasses(lname, module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setClassDefaultsMode */
+static char g_setClassDefaultsMode__doc__[] = "\
+setClassDefaultsMode(mode)\n\
+set default mode for classes\n\
+arguments:\n\
+  mode (int) - the new default mode";
+static PyObject *g_setClassDefaultsMode(PyObject *self, PyObject *args) {
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "i", &i))
+        FAIL();
+    if(i != CONVENIENCE_MODE && i != CONSERVATION_MODE) {
+        ERROR_VALUE("invalid mode value");
+        FAIL();
+    }
+    SetClassDefaultsMode((unsigned short)i);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setDefclassWatchInstances */
+static char g_setDefclassWatchInstances__doc__[] = "\
+setDefclassWatchInstances(state, defclass)\n\
+tell to system if defclass instances are to be watched\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defclass (defclass) - the defclass object";
+static PyObject *g_setDefclassWatchInstances(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *state = NULL;
+
+    if(!PyArg_ParseTuple(args, "OO!", &state, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    SetDefclassWatchInstances(
+        PyObject_IsTrue(state), clips_defclass_value(p));
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setDefclassWatchSlots */
+static char g_setDefclassWatchSlots__doc__[] = "\
+setDefclassWatchSlots(state, defclass)\n\
+tell to system if defclass slots are to be watched\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defclass (defclass) - the defclass object";
+static PyObject *g_setDefclassWatchSlots(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *state = NULL;
+
+    if(!PyArg_ParseTuple(args, "OO!", &state, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    SetDefclassWatchSlots(PyObject_IsTrue(state), clips_defclass_value(p));
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* slotAllowedValues */
+static char g_slotAllowedValues__doc__[] = "\
+slotAllowedValues(defclass, name) -> (MULTIFIELD, list)\n\
+retrieve allowed values for specified slot\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *g_slotAllowedValues(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    SlotAllowedValues(clips_defclass_value(p), s, &o);
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* slotCardinality */
+static char g_slotCardinality__doc__[] = "\
+slotCardinality(defclass, name) -> (MULTIFIELD, list)\n\
+retrieve cardinality information for specified slot\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *g_slotCardinality(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    SlotCardinality(clips_defclass_value(p), s, &o);
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+#if CLIPS_MINOR > 23
+
+/* slotAllowedClasses */
+static char g_slotAllowedClasses__doc__[] = "\
+slotAllowedClasses(defclass, name) -> (MULTIFIELD, list)\n\
+retrieve the allowed classes for a slot of given class\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *g_slotAllowedClasses(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &name))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    SlotAllowedClasses(clips_defclass_value(p), name, &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* slotDefaultValue */
+static char g_slotDefaultValue__doc__[] = "\
+slotDefaultValue(defclass, name) -> (MULTIFIELD, list)\n\
+retrieve default value(s) for a slot of given defclass\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *g_slotDefaultValue(PyObject *self, PyObject *args) {
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &name))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    SlotDefaultValue(clips_defclass_value(p), name, &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+#else
+UNIMPLEMENT_VERSION(slotAllowedClasses, g_slotAllowedClasses)
+UNIMPLEMENT_VERSION(slotDefaultValue, g_slotDefaultValue)
+#endif /* CLIPS_MINOR > 23 */
+
+/* slotDirectAccessP */
+static char g_slotDirectAccessP__doc__[] = "\
+slotDirectAccessP(defclass, name) -> bool\n\
+tell if slot is directly accessible\n\
+returns: True if slot is directly accessible, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *g_slotDirectAccessP(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    i = SlotDirectAccessP(clips_defclass_value(p), s);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* slotExistP */
+static char g_slotExistP__doc__[] = "\
+slotExistP(defclass, name, inherit) -> bool\n\
+tell if slot exists\n\
+returns: True if slot exists, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *g_slotExistP(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!sO", &clips_DefclassType, &p, &s, &q))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    i = SlotExistP(clips_defclass_value(p), s, PyObject_IsTrue(q));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* slotFacets */
+static char g_slotFacets__doc__[] = "\
+slotFacets(defclass, name) -> (MULTIFIELD, list)\n\
+retrieve facet values information for specified slot\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *g_slotFacets(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    SlotFacets(clips_defclass_value(p), s, &o);
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* slotInitableP */
+static char g_slotInitableP__doc__[] = "\
+slotInitableP(defclass, name) -> bool\n\
+tell if slot is initializable\n\
+returns: True if slot can be initialized, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *g_slotInitableP(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    i = SlotInitableP(clips_defclass_value(p), s);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* slotPublicP */
+static char g_slotPublicP__doc__[] = "\
+slotPublicP(defclass, name) -> bool\n\
+tell if slot is public\n\
+returns: True if slot is public, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *g_slotPublicP(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    i = SlotPublicP(clips_defclass_value(p), s);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* slotRange */
+static char g_slotRange__doc__[] = "\
+slotRange(defclass, name) -> (MULTIFIELD, list)\n\
+retrieve numeric range information for specified slot\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *g_slotRange(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    SlotRange(clips_defclass_value(p), s, &o);
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* slotSources */
+static char g_slotSources__doc__[] = "\
+slotSources(defclass, name) -> (MULTIFIELD, list)\n\
+retrieve the name of class sources for specified slot\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *g_slotSources(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    SlotSources(clips_defclass_value(p), s, &o);
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* slotTypes */
+static char g_slotTypes__doc__[] = "\
+slotTypes(defclass, name) -> (MULTIFIELD, list)\n\
+retrieve cardinality information for specified slot\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *g_slotTypes(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    SlotTypes(clips_defclass_value(p), s, &o);
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* slotWritableP */
+static char g_slotWritableP__doc__[] = "\
+slotWritableP(defclass, name) -> bool\n\
+tell whether slot can be overwritten or not\n\
+returns: True if slot is writeable, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *g_slotWritableP(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    i = SlotWritableP(clips_defclass_value(p), s);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* subclassP */
+static char g_subclassP__doc__[] = "\
+subclassP(defclass1, defclass2) -> bool\n\
+tell if defclass1 is a subclass of defclass2\n\
+returns: True if relationship is satisfied, False otherwise\n\
+arguments:\n\
+  defclass1, defclass2 (defclass) - test objects";
+static PyObject *g_subclassP(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL, *q = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_DefclassType, &p, &clips_DefclassType, &q))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    CHECK_DEFCLASS(q);
+    i = SubclassP(clips_defclass_value(p), clips_defclass_value(q));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* superclassP */
+static char g_superclassP__doc__[] = "\
+superclassP(defclass1, defclass2) -> bool\n\
+tell if defclass1 is a superclass of defclass2\n\
+returns: True if relationship is satisfied, False otherwise\n\
+arguments:\n\
+  defclass1, defclass2 (defclass) - test objects";
+static PyObject *g_superclassP(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL, *q = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_DefclassType, &p, &clips_DefclassType, &q))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    CHECK_DEFCLASS(q);
+    i = SuperclassP(clips_defclass_value(p), clips_defclass_value(q));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* undefclass */
+static char g_undefclass__doc__[] = "\
+undefclass(defclass)\n\
+remove a class and all its subclasses from system\n\
+arguments:\n\
+  defclass (defclass) - the defclass to remove";
+static PyObject *g_undefclass(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefclassType, &p))
+        FAIL();
+    CHECK_RM_DEFCLASS(p);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Undefclass(clips_defclass_value(p))) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.13 - Instances Functions */
+
+/* binaryLoadInstances */
+static char g_binaryLoadInstances__doc__[] = "\
+binaryLoadInstances(filename) -> int\n\
+binary load a set of instances from named file\n\
+returns: the number of loaded instances\n\
+arguments:\n\
+  filename (str) - the name of binary file to load from";
+static PyObject *g_binaryLoadInstances(PyObject *self, PyObject *args) {
+    char *fn = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "s", &fn))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    i = BinaryLoadInstances(fn);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    else RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* binarySaveInstances */
+static char g_binarySaveInstances__doc__[] = "\
+binarySaveInstances(filename, scope) -> int\n\
+dump instances to file\n\
+returns: the number of saved instances\n\
+arguments:\n\
+  filename (str) - the name of binary file to save to\n\
+  scope (int) - one of LOCAL_SAVE or VISIBLE_SAVE";
+static PyObject *g_binarySaveInstances(PyObject *self, PyObject *args) {
+    char *fn = NULL;
+    long i = 0;
+
+    if(!PyArg_ParseTuple(args, "si", &fn, &i)) FAIL();
+    if(i != LOCAL_SAVE && i != VISIBLE_SAVE) {
+        ERROR_VALUE("invalid scope");
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    i = BinarySaveInstances(fn, i, NULL, TRUE);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_IO();
+        FAIL();
+    } /* do not know */
+    else RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* createRawInstance */
+static char g_createRawInstance__doc__[] = "\
+createRawInstance(defclass, name) -> instance\n\
+create an instance of specified class with given name\n\
+returns: the instance as a new object\n\
+arguments:\n\
+  defclass (defclass) - the defclass to create an instance of\n\
+  name (str) - the name of the instance";
+static PyObject *g_createRawInstance(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    clips_InstanceObject *q = NULL;
+    void *ptr = 0;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_DefclassType, &p, &name))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = CreateRawInstance(clips_defclass_value(p), name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_CREATION();
+        FAIL();
+    }
+    clips_instance_New(GetCurrentEnvironment(), q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_instance_assign(q, ptr);
+    CHECK_VALID_INSTANCE(q);
+    clips_instance_lock(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* decrementInstanceCount */
+UNIMPLEMENT(decrementInstanceCount, g_decrementInstanceCount)
+
+/* deleteInstance */
+static char g_deleteInstance__doc__[] = "\
+deleteInstance([instance])\n\
+delete specified instance\n\
+arguments:\n\
+  instance (instance) - the instance to delete, all if omitted";
+static PyObject *g_deleteInstance(PyObject *self, PyObject *args) {
+    clips_InstanceObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_InstanceType, &p))
+        FAIL();
+    CHECK_VALID_INSTANCE(p);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!DeleteInstance(p ? clips_instance_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* directGetSlot */
+static char g_directGetSlot__doc__[] = "\
+directGetSlot(instance, slotname) -> (type, value)\n\
+get value in specified slot of given instance\n\
+returns: a pair (type, value)\n\
+arguments:\n\
+  instance (instance) - the instance to inspect\n\
+  slotname (str) - the slot to retrieve";
+static PyObject *g_directGetSlot(PyObject *self, PyObject *args) {
+    clips_InstanceObject *p = NULL;
+    PyObject *q = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_InstanceType, &p, &name))
+        FAIL();
+    CHECK_VALID_INSTANCE(p);
+    ACQUIRE_MEMORY_ERROR();
+    DirectGetSlot(clips_instance_value(p), name, &o);
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* directPutSlot */
+static char g_directPutSlot__doc__[] = "\
+directPutSlot(instance, slotname, (type, value))\n\
+put a value in specified slot of given instance\n\
+arguments:\n\
+  instance (instance) - the instance to inspect\n\
+  slotname (str) - the slot to retrieve\n\
+  type (int) - the type of value to assign\n\
+  value (object or list of pairs) - the value to assign";
+static PyObject *g_directPutSlot(PyObject *self, PyObject *args) {
+    clips_InstanceObject *p = NULL;
+    PyObject *q = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!sO", &clips_InstanceType, &p, &name, &q))
+        FAIL();
+    CHECK_VALID_INSTANCE(p);
+    if(!i_py2do(q, &o)) {
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!DirectPutSlot(clips_instance_value(p), name, &o)) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_OTHER("instance slot could not be modified");
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* findInstance */
+static char g_findInstance__doc__[] = "\
+findInstance(name, srchimports [, module]) -> instance\n\
+find the instance with the specified name\n\
+returns: the instance as a new object\n\
+arguments:\n\
+  name (str) - instance name\n\
+  srchimports (bool) - True if imported modules have to be inspected\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_findInstance(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    clips_InstanceObject *q = NULL;
+    char *name = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "sO|O!",
+                         &name, &p, &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = FindInstance(
+        module ? clips_defmodule_value(module) : NULL,
+        name, PyObject_IsTrue(p));
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_instance_New(GetCurrentEnvironment(), q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_instance_assign(q, ptr);
+    CHECK_VALID_INSTANCE(q);
+    clips_instance_lock(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* getInstanceClass */
+static char g_getInstanceClass__doc__[] = "\
+getInstanceClass(instance) -> defclass\n\
+retrieve the class of specified instance\n\
+returns: the instance defclass as a new object\n\
+arguments:\n\
+  instance (instance) - the instance to inspect";
+static PyObject *g_getInstanceClass(PyObject *self, PyObject *args) {
+    clips_InstanceObject *p = NULL;
+    clips_DefclassObject *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_InstanceType, &p))
+        FAIL();
+    CHECK_VALID_INSTANCE(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetInstanceClass(clips_instance_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    clips_defclass_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defclass_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* getInstanceName */
+static char g_getInstanceName__doc__[] = "\
+getInstanceName(instance) -> str\n\
+retrieve the name of specified instance\n\
+returns: the requested name of instance\n\
+arguments:\n\
+  instance (instance) - the instance to inspect";
+static PyObject *g_getInstanceName(PyObject *self, PyObject *args) {
+    clips_InstanceObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_InstanceType, &p))
+        FAIL();
+    CHECK_VALID_INSTANCE(p);
+    ACQUIRE_MEMORY_ERROR();
+    name = GetInstanceName(clips_instance_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getInstancePPForm */
+static char g_getInstancePPForm__doc__[] = "\
+getInstancePPForm(instance) -> str\n\
+retrieve the pretty-print form of specified instance\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  instance (instance) - the instance to inspect";
+static PyObject *g_getInstancePPForm(PyObject *self, PyObject *args) {
+    clips_InstanceObject *p = NULL;
+    char *buffer = NEW_ARRAY(char, ppbuffer_size);
+    PyObject *rv = NULL;
+
+    if(!buffer) {
+        ERROR_MEMORY("cannot allocate buffer");
+        FAIL();
+    }
+    if(!PyArg_ParseTuple(args, "O!", &clips_InstanceType, &p))
+        FAIL();
+    CHECK_VALID_INSTANCE(p);
+    ACQUIRE_MEMORY_ERROR();
+    GetInstancePPForm(buffer, ppbuffer_size-1, clips_instance_value(p));
+    RELEASE_MEMORY_ERROR();
+    rv = Py_BuildValue("s", buffer);
+    DELETE(buffer);
+    return rv;
+
+BEGIN_FAIL
+    if(buffer) DELETE(buffer);
+    SKIP();
+END_FAIL
+}
+
+/* getInstancesChanged */
+STATUS_FUNC_GET_BOOL(getInstancesChanged,
+                     g_getInstancesChanged,
+                     GetInstancesChanged)
+
+/* getNextInstance */
+static char g_getNextInstance__doc__[] = "\
+getNextInstance([instance]) -> instance\n\
+retrieve next instance object in list, first if argument is omitted\n\
+returns: a instance object, None if already at last instance\n\
+arguments:\n\
+  instance (defrule) - the instance to start from";
+static PyObject *g_getNextInstance(PyObject *self, PyObject *args) {
+    clips_InstanceObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_InstanceType, &p))
+        FAIL();
+    if(p)
+        CHECK_VALID_INSTANCE(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextInstance(p ? clips_instance_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) RETURN_NONE();
+    clips_instance_New(GetCurrentEnvironment(), q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_instance_assign(q, ptr);
+    CHECK_VALID_INSTANCE(q);
+    clips_instance_lock(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* getNextInstanceInClass */
+static char g_getNextInstanceInClass__doc__[] = "\
+getNextInstanceInClass(defclass [, instance]) -> instance\n\
+retrieve next instance object in class, first if argument is omitted\n\
+returns: a instance object, None if already at last instance\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  instance (instance) - the instance to start from";
+static PyObject *g_getNextInstanceInClass(PyObject *self, PyObject *args) {
+    clips_InstanceObject *p = NULL, *q = NULL;
+    clips_DefclassObject *c = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_DefclassType, &c, &clips_InstanceType, &p))
+        FAIL();
+    CHECK_DEFCLASS(c);
+    if(p)
+        CHECK_VALID_INSTANCE(p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextInstanceInClass(
+        clips_defclass_value(c), p ? clips_instance_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) RETURN_NONE();
+    clips_instance_New(GetCurrentEnvironment(), q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_instance_assign(q, ptr);
+    CHECK_VALID_INSTANCE(q);
+    clips_instance_lock(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* getNextInstanceInClassAndSubclasses */
+static char g_getNextInstanceInClassAndSubclasses__doc__[] = "\
+getNextInstanceInClassAndSubclasses(defclass [, instance]) -> instance\n\
+retrieve next instance in class/subclasses, first if argument is omitted\n\
+returns: a instance object, None if already at last instance\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  instance (instance) - the instance to start from";
+static PyObject *g_getNextInstanceInClassAndSubclasses(PyObject *self, PyObject *args) {
+    clips_InstanceObject *p = NULL, *q = NULL;
+    clips_DefclassObject *c = NULL;
+    DATA_OBJECT o = { 0 };
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_DefclassType, &c, &clips_InstanceType, &p))
+        FAIL();
+    CHECK_DEFCLASS(c);
+    if(p)
+        CHECK_VALID_INSTANCE(p);
+    /* we should iterate from the start in order to keep the iteration data */
+    ACQUIRE_MEMORY_ERROR();
+    if(p) {
+        ptr = GetNextInstanceInClassAndSubclasses_PY(
+            clips_defclass_value(c), NULL, &o);
+        /* move cursor to the instance we passed in */
+        while(ptr && ptr != clips_instance_value(p))
+            ptr = GetNextInstanceInClassAndSubclasses_PY(
+                clips_defclass_value(c), ptr, &o);
+        /* move cursor one step forward if conditions met (may return NULL) */
+        if(ptr)
+            ptr = GetNextInstanceInClassAndSubclasses_PY(
+                clips_defclass_value(c), ptr, &o);
+    } else
+        ptr = GetNextInstanceInClassAndSubclasses_PY(
+            clips_defclass_value(c), NULL, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_instance_New(GetCurrentEnvironment(), q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_instance_assign(q, ptr);
+    CHECK_VALID_INSTANCE(q);
+    clips_instance_lock(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+
+/* incrementInstanceCount */
+UNIMPLEMENT(incrementInstanceCount, g_incrementInstanceCount)
+
+/* instances */
+static char g_instances__doc__[] = "\
+instances(output [, module] [, class [, subclassflag]]])\n\
+list instances in specified defmodule to logical output\n\
+arguments:\n\
+  output (str) - the name of logical output stream\n\
+  module (defmodule) - the defmodule to inspect, all if omitted\n\
+  class (str) - the class name to inspect, all if omitted\n\
+  subclassflag (bool) - True if all subclasses must be recursed";
+static PyObject *g_instances(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = Py_None;
+    char *name = NULL, *output = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!sO", &output,
+       &clips_DefmoduleType, &module, &name, &p)) {
+        PyErr_Clear();
+        module = NULL;
+        if(!PyArg_ParseTuple(args, "s|sO", &output, &name, &p)) {
+            PyErr_Clear();
+            ERROR_TYPE("invalid argument(s) or invalid argument order");
+            FAIL();
+        }
+    }
+    ACQUIRE_MEMORY_ERROR();
+    Instances(
+        output, module ? clips_defmodule_value(module) : NULL,
+        name, p ? PyObject_IsTrue(p) : FALSE);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* loadInstances */
+static char g_loadInstances__doc__[] = "\
+loadInstances(filename) -> int\n\
+load instance from specified file\n\
+returns: the number of loaded instances\n\
+arguments:\n\
+  filename (str) - the name of file to load instances from";
+static PyObject *g_loadInstances(PyObject *self, PyObject *args) {
+    char *fn = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "s", &fn))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    i = LoadInstances(fn);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* makeInstance */
+static char g_makeInstance__doc__[] = "\
+makeInstance(command) -> instance\n\
+create and initialize an instance using given command\n\
+returns: a new instance\n\
+arguments:\n\
+  command (str) - command used to create instance";
+static PyObject *g_makeInstance(PyObject *self, PyObject *args) {
+    clips_InstanceObject *q = NULL;
+    char *s = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &s))
+        FAIL();
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = MakeInstance(s);
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    if(!ptr) {
+        ERROR_CLIPS_CREATION();
+        FAIL();
+    }
+    clips_instance_New(GetCurrentEnvironment(), q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_instance_assign(q, ptr);
+    CHECK_VALID_INSTANCE(q);
+    clips_instance_lock(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* restoreInstances */
+static char g_restoreInstances__doc__[] = "\
+restoreInstances(filename) -> int\n\
+restore instance from specified file\n\
+returns: number of restored instances\n\
+arguments:\n\
+  filename (str) - the name of file to restore instances from";
+static PyObject *g_restoreInstances(PyObject *self, PyObject *args) {
+    char *fn = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "s", &fn))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    i = RestoreInstances(fn);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* saveInstances */
+static char g_saveInstances__doc__[] = "\
+saveInstances(filename, scope) -> int\n\
+save instances to specified file\n\
+returns: the number of saved instances\n\
+arguments:\n\
+  filename (str) - the name of file to save instances to\n\
+  scope (int) - one of LOCAL_SAVE or VISIBLE_SAVE";
+static PyObject *g_saveInstances(PyObject *self, PyObject *args) {
+    char *fn = NULL;
+    long i = 0;
+
+    if(!PyArg_ParseTuple(args, "si", &fn, &i))
+        FAIL();
+    if(i != LOCAL_SAVE && i != VISIBLE_SAVE) {
+        ERROR_VALUE("invalid scope");
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    i = SaveInstances(fn, i, NULL, TRUE);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_IO();
+        FAIL();
+    } /* do not know */
+    else
+        RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* send */
+static char g_send__doc__[] = "\
+send(instance, message [, arguments])\n\
+send a message to specified object\n\
+returns: the result value for the operation if any\n\
+arguments:\n\
+  instance (instance) - object to send message to\n\
+  message (str) - message to send\n\
+  arguments (str) - blank separated constant arguments";
+static PyObject *g_send(PyObject *self, PyObject *args) {
+    PyObject *p = NULL, *q = NULL;
+    char *msg = NULL, *msa = NULL;
+    DATA_OBJECT o = { 0 }, rv = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!s|s", &clips_InstanceType, &p, &msg, &msa))
+        FAIL();
+    CHECK_VALID_INSTANCE(p);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    SetType(o, INSTANCE_ADDRESS);
+    SetValue(o, clips_instance_value(p));
+    Send(&o, msg, msa, &rv);
+    q = i_do2py(&rv);
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    if(q) {
+        RETURN_PYOBJECT(q);
+    } else RETURN_NONE();
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* setInstancesChanged */
+STATUS_FUNC_SET_BOOL(setInstancesChanged,
+                     g_setInstancesChanged,
+                     SetInstancesChanged)
+
+/* unmakeInstance */
+static char g_unmakeInstance__doc__[] = "\
+unmakeInstance([instance])\n\
+delete specified instance (passing a message)\n\
+arguments:\n\
+  instance (instance) - instance to delete, all if omitted";
+static PyObject *g_unmakeInstance(PyObject *self, PyObject *args) {
+    clips_InstanceObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_InstanceType, &p))
+        FAIL();
+    if(p)
+        CHECK_VALID_INSTANCE(p);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!UnmakeInstance(p ? clips_instance_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* validInstanceAddress */
+static char g_validInstanceAddress__doc__[] = "\
+validInstanceAddress(instance) -> bool\n\
+tell whether the instance still exists or not\n\
+returns: True if instance exists, False otherwise\n\
+arguments:\n\
+  instance (instance) - istance to test";
+static PyObject *g_validInstanceAddress(PyObject *self, PyObject *args) {
+    clips_InstanceObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_InstanceType, &p))
+        FAIL();
+    i = ValidInstanceAddress(clips_instance_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* loadInstancesFromString */
+static char g_loadInstancesFromString__doc__[] = "\
+loadInstancesFromString(string [, maxpos]) -> int\n\
+load instances from a string\n\
+returns: the number of loaded instances\n\
+arguments:\n\
+  string (str) - string to read from\n\
+  maxpos (int) - last char to read, all string if omitted";
+static PyObject *g_loadInstancesFromString(PyObject *self, PyObject *args) {
+    char *s = NULL;
+    int i = -1;
+
+    if(!PyArg_ParseTuple(args, "s|i", &s, &i))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    i = LoadInstancesFromString(s, i);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* restoreInstancesFromString */
+static char g_restoreInstancesFromString__doc__[] = "\
+restoreInstancesFromString(string [, maxpos]) -> int\n\
+restore instances from a string\n\
+returns: number of restored instances\n\
+arguments:\n\
+  string (str) - string to read from\n\
+  maxpos (int) - last char to read, all string if omitted";
+static PyObject *g_restoreInstancesFromString(PyObject *self, PyObject *args) {
+    char *s = NULL;
+    int i = -1;
+
+    if(!PyArg_ParseTuple(args, "s|i", &s, &i))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    i = RestoreInstancesFromString(s, i);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.14 - DefmessageHandler Functions */
+
+/* findDefmessageHandler */
+static char g_findDefmessageHandler__doc__[] = "\
+findDefmessageHandler(defclass, name, type) -> int\n\
+find the matching message handler attached to defclass\n\
+returns: index of message handler\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect object\n\
+  name (str) - message handler name\n\
+  type (str) - one of 'around', 'before', 'primary', 'after'";
+static PyObject *g_findDefmessageHandler(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    char *name = NULL, *type = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!ss", &clips_DefclassType, &p, &name, &type))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    i = (int)FindDefmessageHandler(clips_defclass_value(p), name, type);
+    RELEASE_MEMORY_ERROR();
+    CHECK_DEFCLASS(p);
+    if(i == 0) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefmessageHandlerList */
+static char g_getDefmessageHandlerList__doc__[] = "\
+getDefmessageHandlerList([defclass [, inh]]) -> (MULTIFIELD, list)\n\
+retrieve list of message handlers attached to defclass\n\
+returns: MULTIFIELD and a list of pairs (STRING, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect, all if omitted\n\
+  inh (bool) - True if inherited handlers are to list";
+static PyObject *g_getDefmessageHandlerList(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *p1 = NULL, *q = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "|O!O", &clips_DefclassType, &p, &p1))
+        FAIL();
+    if(p)
+        CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    GetDefmessageHandlerList(
+        p ? clips_defclass_value(p) : NULL,
+        &o, p1 ? PyObject_IsTrue(p1) : FALSE);
+    q = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* getDefmessageHandlerName */
+static char g_getDefmessageHandlerName__doc__[] = "\
+getDefmessageHandlerName(defclass, index) -> str\n\
+retrieve the name of specified message handler\n\
+returns: name as string\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *g_getDefmessageHandlerName(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    char *name = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!i",  &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    name = GetDefmessageHandlerName(clips_defclass_value(p), (unsigned int)i);
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefmessageHandlerPPForm */
+static char g_getDefmessageHandlerPPForm__doc__[] = "\
+getDefmessageHandlerPPForm(defclass, index) -> str\n\
+retrieve the pretty-print form of specified message handler\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *g_getDefmessageHandlerPPForm(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!i",  &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = GetDefmessageHandlerPPForm(clips_defclass_value(p), (unsigned int)i);
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefmessageHandlerType */
+static char g_getDefmessageHandlerType__doc__[] = "\
+getDefmessageHandlerType(defclass, index) -> str\n\
+retrieve type of specified message handler\n\
+returns: type as string\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *g_getDefmessageHandlerType(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!i",  &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = GetDefmessageHandlerType(clips_defclass_value(p), (unsigned int)i);
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefmessageHandlerWatch */
+static char g_getDefmessageHandlerWatch__doc__[] = "\
+getDefmessageHandlerWatch(defclass, index) -> bool\n\
+tell if specified message handler is being watched\n\
+returns: True if the message handler is being watched, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *g_getDefmessageHandlerWatch(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!i",  &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_DEFCLASS(p);
+    i = GetDefmessageHandlerWatch(clips_defclass_value(p), (unsigned int)i);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getNextDefmessageHandler */
+static char g_getNextDefmessageHandler__doc__[] = "\
+getNextDefmessageHandler(defclass [, index]) -> int\n\
+return index of next message handler for specified class\n\
+returns: index as an integer, None if already at last handler\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of current handler, 0 or omitted for first";
+static PyObject *g_getNextDefmessageHandler(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!|i", &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i < 0) {
+        ERROR_VALUE("index must be positive or zero");
+        FAIL();
+    }
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    i = GetNextDefmessageHandler(clips_defclass_value(p), (unsigned int)i);
+    RELEASE_MEMORY_ERROR();
+    if(i == 0)
+        RETURN_NONE();
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* isDefmessageHandlerDeletable */
+static char g_isDefmessageHandlerDeletable__doc__[] = "\
+isDefmessageHandlerDeletable(defclass, index) -> bool\n\
+tell whether or not the specified message handler can be deleted\n\
+returns: True if the message handler can be deleted, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *g_isDefmessageHandlerDeletable(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!i", &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_DEFCLASS(p);
+    i = IsDefmessageHandlerDeletable(clips_defclass_value(p), (unsigned int)i);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* listDefmessageHandlers */
+static char g_listDefmessageHandlers__doc__[] = "\
+listDefmessageHandlers(output [, defclass [, inhflag]])\n\
+list message handlers to logical output\n\
+arguments:\n\
+  output (str) - the name of output stream\n\
+  defclass (defclass) - the defclass to inspect\n\
+  inhflag (bool) - True to list inherited handlers";
+static PyObject *g_listDefmessageHandlers(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    PyObject *p1 = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!O", &s, &clips_DefclassType, &p, &p1))
+        FAIL();
+    if(p)
+        CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    ListDefmessageHandlers(s,
+        p ? clips_defclass_value(p) : NULL, p1 ? PyObject_IsTrue(p1) : FALSE);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* previewSend */
+static char g_previewSend__doc__[] = "\
+previewSend(output, defclass, messagename)\n\
+list message handlers applicable to instances to logical output\n\
+arguments:\n\
+  output (str) - logical output stream name\n\
+  defclass (defclass) - the defclass to inspect\n\
+  messagename (str) - the name of message";
+static PyObject *g_previewSend(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    char *s = NULL, *m = NULL;
+
+    if(!PyArg_ParseTuple(args, "sO!s", &s, &clips_DefclassType, &p, &m))
+        FAIL();
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    PreviewSend(s, clips_defclass_value(p), m);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setDefmessageHandlerWatch */
+static char g_setDefmessageHandlerWatch__doc__[] = "\
+setDefmessageHandlerWatch(state, defclass, index)\n\
+set watch on message handler to specified state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *g_setDefmessageHandlerWatch(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+    PyObject *state = NULL;
+
+    if(!PyArg_ParseTuple(args, "OO!i", &state, &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    SetDefmessageHandlerWatch(
+        PyObject_IsTrue(state), clips_defclass_value(p), (unsigned int)i);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* undefmessageHandler */
+static char g_undefmessageHandler__doc__[] = "\
+undefmessageHandler(defclass, index)\n\
+remove specified message handler from system\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *g_undefmessageHandler(PyObject *self, PyObject *args) {
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!i", &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_DEFCLASS(p);
+    ACQUIRE_MEMORY_ERROR();
+    if(!UndefmessageHandler(clips_defclass_value(p), (unsigned int)i)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.15 - Definstances Functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *definstancesExists(void *ptr) {
+    void *rv = GetNextDefinstances(NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = GetNextDefinstances(rv);
+    }
+    return NULL;
+}
+#define PYDEFINSTANCES_EXISTS(_p) \
+    definstancesExists(clips_definstances_value(_p))
+#define CHECK_DEFINSTANCES(_p) do { \
+        if(!PYDEFINSTANCES_EXISTS(_p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define CHECK_RM_DEFINSTANCES(_p) do { \
+        if(_p && !PYDEFINSTANCES_EXISTS(_p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* actual functions with documentation */
+
+/* definstancesModule */
+static char g_definstancesModule__doc__[] = "\
+definstancesModule(definstances) -> str\n\
+retrieve the module name where specified definstances is defined\n\
+returns: module name as string\n\
+arguments:\n\
+  definstances (definstances) - the definstances to inspect";
+static PyObject *g_definstancesModule(PyObject *self, PyObject *args) {
+    clips_DefinstancesObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefinstancesType, &p))
+        FAIL();
+    CHECK_DEFINSTANCES(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = DefinstancesModule(clips_definstances_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* findDefinstances */
+static char g_findDefinstances__doc__[] = "\
+findDefinstances(name) -> definstances\n\
+return the definstances object associated with name\n\
+returns: the definstances as a new object\n\
+arguments:\n\
+  name (str) - the name to look for";
+static PyObject *g_findDefinstances(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DefinstancesObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name)) FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = FindDefinstances(name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) { ERROR_CLIPS_NOTFOUND(); FAIL(); }
+    clips_definstances_New(p);
+    if(!p) { ERROR_MEMORY_CREATION(); FAIL(); }
+    clips_definstances_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefinstancesList */
+static char g_getDefinstancesList__doc__[] = "\
+getDefinstancesList([module]) -> (MULTIFIELD, list)\n\
+retrieve the list of definstances objects in the specified defmodule\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_getDefinstancesList(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    GetDefinstancesList(&o, module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefinstancesName */
+static char g_getDefinstancesName__doc__[] = "\
+getDefinstancesName(definstances) -> str\n\
+retrieve the name of specified definstances\n\
+returns: name as a string\n\
+arguments:\n\
+  definstances (definstances) - the definstances to inspect";
+static PyObject *g_getDefinstancesName(PyObject *self, PyObject *args) {
+    clips_DefinstancesObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefinstancesType, &p))
+        FAIL();
+    CHECK_DEFINSTANCES(p);
+    ACQUIRE_MEMORY_ERROR();
+    name = GetDefinstancesName(clips_definstances_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefinstancesPPForm */
+static char g_getDefinstancesPPForm__doc__[] = "\
+getDefinstancesPPForm(definstances) -> str\n\
+retrieve the pretty-print form of specified definstances\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  definstances (definstances) - the definstances to inspect";
+static PyObject *g_getDefinstancesPPForm(PyObject *self, PyObject *args) {
+    clips_DefinstancesObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefinstancesType, &p))
+        FAIL();
+    CHECK_DEFINSTANCES(p);
+    ACQUIRE_MEMORY_ERROR();
+    s = GetDefinstancesPPForm(clips_definstances_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getNextDefinstances */
+static char g_getNextDefinstances__doc__[] = "\
+getNextDefinstances([definstances]) -> definstances\n\
+retrieve next definstances object in list, first if argument is omitted\n\
+returns: a definstances object, None if already at last definstances\n\
+arguments:\n\
+  definstances (definstances) - the definstances to start from";
+static PyObject *g_getNextDefinstances(PyObject *self, PyObject *args) {
+    clips_DefinstancesObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefinstancesType, &p))
+        FAIL();
+    if(p) { CHECK_DEFINSTANCES(p); }
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextDefinstances(p ? clips_definstances_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) RETURN_NONE();
+    clips_definstances_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_definstances_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* isDefinstancesDeletable */
+static char g_isDefinstancesDeletable__doc__[] = "\
+isDefinstancesDeletable(definstances) -> bool\n\
+tell whether or not the definstances can be deleted\n\
+returns: True if the definstances can be deleted, False otherwise\n\
+arguments:\n\
+  definstances (definstances) - the definstances to be inspected";
+static PyObject *g_isDefinstancesDeletable(PyObject *self, PyObject *args) {
+    clips_DefinstancesObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefinstancesType, &p))
+        FAIL();
+    CHECK_DEFINSTANCES(p);
+    i = IsDefinstancesDeletable(clips_definstances_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* listDefinstances */
+static char g_listDefinstances__doc__[] = "\
+listDefinstances(logicalname [, module])\n\
+list definstances to output identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *g_listDefinstances(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *module = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O!", &lname, &clips_DefmoduleType, &module))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ListDefinstances(lname, module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* undefinstances */
+static char g_undefinstances__doc__[] = "\
+undefinstances([definstances])\n\
+delete a definstances object or all definstances objects\n\
+arguments:\n\
+  definstances (definstances) - object to be deleted, all if omitted";
+static PyObject *g_undefinstances(PyObject *self, PyObject *args) {
+    clips_DefinstancesObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefinstancesType, &p))
+        FAIL();
+    CHECK_RM_DEFINSTANCES(p);
+    CLIPS_LOCK_GC();
+    ACQUIRE_MEMORY_ERROR();
+    if(!Undefinstances(p ? clips_definstances_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        CLIPS_UNLOCK_GC();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    CLIPS_UNLOCK_GC();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.16 - Defmodule functions */
+
+/* findDefmodule */
+static char g_findDefmodule__doc__[] = "\
+findDefmodule(name) -> defmodule\n\
+return the defmodule object associated with name\n\
+returns: the defmodule as a new object\n\
+arguments:\n\
+  name (str) - the name to look for";
+static PyObject *g_findDefmodule(PyObject *self, PyObject *args) {
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DefmoduleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = FindDefmodule(name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_defmodule_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defmodule_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getCurrentModule */
+static char g_getCurrentModule__doc__[] = "\
+getCurrentModule() -> defmodule\n\
+return current module\n\
+returns: current module as a new object";
+static PyObject *g_getCurrentModule(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *p = NULL;
+    void *ptr = NULL;
+
+    CHECK_NOARGS(args);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetCurrentModule();
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    clips_defmodule_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defmodule_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefmoduleList */
+static char g_getDefmoduleList__doc__[] = "\
+getDefmoduleList() -> (MULTIFIELD, list)\n\
+return the list of modules in system\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)";
+static PyObject *g_getDefmoduleList(PyObject *self, PyObject *args) {
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    CHECK_NOARGS(args);
+    ACQUIRE_MEMORY_ERROR();
+    GetDefmoduleList(&o);
+    p = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getDefmoduleName */
+static char g_getDefmoduleName__doc__[] = "\
+getDefmoduleName(defmodule) -> str\n\
+retrieve the name of specified defmodule\n\
+returns: name as a string\n\
+arguments:\n\
+  defmodule (defmodule) - the defmodule to inspect";
+static PyObject *g_getDefmoduleName(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefmoduleType, &p))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    name = GetDefmoduleName(clips_defmodule_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) { ERROR_CLIPS_RETVAL(); FAIL(); }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getDefmodulePPForm */
+static char g_getDefmodulePPForm__doc__[] = "\
+getDefmodulePPForm(defmodule) -> str\n\
+retrieve the pretty-print form of specified defmodule\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defmodule (defmodule) - the defmodule to inspect";
+static PyObject *g_getDefmodulePPForm(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefmoduleType, &p))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    s = GetDefmodulePPForm(clips_defmodule_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getNextDefmodule */
+static char g_getNextDefmodule__doc__[] = "\
+getNextDefmodule([defmodule]) -> defmodule\n\
+retrieve next defmodule object in list, first if argument is omitted\n\
+returns: a defmodule object, None if already at last defmodule\n\
+arguments:\n\
+  defmodule (defmodule) - the defmodule to start from";
+static PyObject *g_getNextDefmodule(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "|O!", &clips_DefmoduleType, &p))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ptr = GetNextDefmodule(p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_defmodule_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defmodule_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* listDefmodules */
+static char g_listDefmodules__doc__[] = "\
+listDefmodules(output)\n\
+list modules to logical output\n\
+arguments:\n\
+  output (str) - logical name of output stream";
+static PyObject *g_listDefmodules(PyObject *self, PyObject *args) {
+    char *output = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &output))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    ListDefmodules(output);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setCurrentModule */
+static char g_setCurrentModule__doc__[] = "\
+setCurrentModule(defmodule)\n\
+set current module to the one specified\n\
+arguments:\n\
+  defmodule (defmodule) - new current defmodule";
+static PyObject *g_setCurrentModule(PyObject *self, PyObject *args) {
+    clips_DefmoduleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_DefmoduleType, &p))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    SetCurrentModule(clips_defmodule_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* sendCommand [undocumented] */
+static char g_sendCommand__doc__[] = "\
+sendCommand(command [, verbose])\n\
+send a full command to the engine as if it was typed at the prompt\n\
+arguments:\n\
+  command (str) - the complete command to send\n\
+  verbose (bool) - if True command can produce output";
+static PyObject *g_sendCommand(PyObject *self, PyObject *args) {
+    void *env = NULL;
+    char *command = NULL;
+    int res = 0, verbose = FALSE;
+    PyObject *v = NULL;
+
+    if(!PyArg_ParseTuple(args, "s|O", &command, &v))
+        FAIL();
+    env = GetCurrentEnvironment();
+    if(!env) {
+        ERROR_CLIPS_NOENV();
+        FAIL();
+    }
+    verbose = (v && PyObject_IsTrue(v)) ? TRUE : FALSE;
+    ACQUIRE_MEMORY_ERROR();
+    FlushPPBuffer(env);
+    SetPPBufferStatus(env, OFF);
+    RouteCommand(env, command, verbose);
+    res = GetEvaluationError(env);
+    FlushPPBuffer(env);
+    SetHaltExecution(env, FALSE);
+    SetEvaluationError(env, FALSE);
+    FlushBindList(env);
+    RELEASE_MEMORY_ERROR();
+    if(res) {
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* forceCleanup() [undocumented] */
+static char g_forceCleanup__doc__[] = "\
+forceCleanup([alldepths, heuristics])\n\
+attempt to force a garbage collection\n\
+arguments:\n\
+  alldepths (bool) - True to clean up all depths (default)\n\
+  heuristics (bool) - True to use heuristics (default)";
+static PyObject *g_forceCleanup(PyObject *self, PyObject *args) {
+    void *env = GetCurrentEnvironment();
+    PyObject *alldepths = NULL, *heuristics = NULL;
+
+    if(!PyArg_ParseTuple(args, "|OO", &alldepths, &heuristics))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    if(EngineData(env)->ExecutingRule != NULL) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPSSYS_CLEANUP();
+        FAIL();
+    }
+    PeriodicCleanup(env,
+        alldepths ? TRUE : PyObject_IsTrue(alldepths),
+        heuristics ? TRUE : PyObject_IsTrue(heuristics));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* ======================================================================== */
+
+
+
+/* helper to check if an environment is safe to use */
+#define CHECK_VALID_ENVIRONMENT(_e) do { \
+        if(!clips_environment_valid(_e)) { \
+            ERROR_CLIPSSYS_BADENV(); \
+            FAIL(); \
+        } \
+    } while(0)
+
+/* AddClearFunction */
+UNIMPLEMENT(env_addClearFunction, e_addClearFunction)
+/* AddPeriodicFunction */
+UNIMPLEMENT(env_addPeriodicFunction, e_addPeriodicFunction)
+/* AddResetFunction */
+UNIMPLEMENT(env_addResetFunction, e_addResetFunction)
+
+/* env_bload */
+static char e_bload__doc__[] = "\
+env_bload(env, filename)\n\
+load a binary image of environment constructs\n\
+arguments:\n\
+  filename (str) - the name of binary file to load from";
+static PyObject *e_bload(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *fn = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &fn))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvBload(env, fn)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_bsave */
+static char e_bsave__doc__[] = "\
+env_bsave(env, filename)\n\
+save a binary image of environment constructs\n\
+arguments:\n\
+  filename (str) - the name of binary file to save to";
+static PyObject *e_bsave(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *fn = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &fn))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvBsave(env, fn)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_clear */
+static char e_clear__doc__[] = "\
+env_clear(env)\n\
+clear environment";
+static PyObject *e_clear(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_EnvType, &pyenv))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvClear_PY(env)) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPSSYS_ENVNOCLEAR();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+#ifdef USE_CLEAR_RESETGCCOUNTERS
+    ENV_RESET_ASSERTED_FACTS(pyenv);
+#endif /* USE_CLEAR_RESETGCCOUNTERS */
+    ENV_LOSE_HASH_FACTS(pyenv);
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* functionCall */
+static char e_functionCall__doc__[] = "\
+env_functionCall(funcname [, args]) -> (type, value)\n\
+call an internal function\n\
+returns: the function result, as a pair (type, return value)\n\
+arguments:\n\
+  funcname (str) - the internal function or operator name\n\
+  args (str) - string containing a blank separated list of arguments";
+static PyObject *e_functionCall(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *func = NULL, *fargs = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!s|s",
+                         &clips_EnvType, &pyenv, &func, &fargs))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(EnvFunctionCall(env, func, fargs, &o)) {
+        SetEvaluationError(env, FALSE);
+        SetHaltExecution(env, FALSE);
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_FUNCCALL();
+        FAIL();
+    }
+    p = i_do2py_e(env, &o);
+    SetEvaluationError(env, FALSE);
+    SetHaltExecution(env, FALSE);
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getAutoFloatDividend */
+E_STATUS_FUNC_GET_BOOL(env_getAutoFloatDividend,
+                       e_getAutoFloatDividend,
+                       EnvGetAutoFloatDividend)
+
+/* getDynamicConstraintChecking */
+E_STATUS_FUNC_GET_BOOL(env_getDynamicConstraintChecking,
+                       e_getDynamicConstraintChecking,
+                       EnvGetDynamicConstraintChecking)
+
+/* getSequenceOperatorRecognition */
+E_STATUS_FUNC_GET_BOOL(env_getSequenceOperatorRecognition,
+                       e_getSequenceOperatorRecognition,
+                       EnvGetSequenceOperatorRecognition)
+
+/* getStaticConstraintChecking */
+E_STATUS_FUNC_GET_BOOL(env_getStaticConstraintChecking,
+                       e_getStaticConstraintChecking,
+                       EnvGetStaticConstraintChecking)
+
+/* initializeEnvironment: NEVER TO BE IMPLEMENTED */
+/*        the environment is initialized at module load time */
+
+
+/* env_load */
+static char e_load__doc__[] = "\
+env_load(env, filename)\n\
+load constructs into environment\n\
+arguments:\n\
+  filename (str) - the name of file to load constructs from";
+static PyObject *e_load(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *fn = NULL;
+    int rv;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &fn))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    rv = EnvLoad(env, fn);
+    RELEASE_MEMORY_ERROR();
+    if(rv == 0) {
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    if(rv < 0) {
+        ERROR_CLIPS_PARSEF();
+        FAIL();
+    }
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* removeClearFunction */
+UNIMPLEMENT(env_removeClearFunction, e_removeClearFunction)
+
+/* removePeriodicFunction */
+UNIMPLEMENT(env_removePeriodicFunction, e_removePeriodicFunction)
+
+/* removeResetFunction */
+UNIMPLEMENT(env_removeResetFunction, e_removeResetFunction)
+
+
+/* env_reset */
+static char e_reset__doc__[] = "\
+env_reset(env)\n\
+reset environment";
+static PyObject *e_reset(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_EnvType, &pyenv))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvReset(env);
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_save */
+static char e_save__doc__[] = "\
+env_save(env, filename)\n\
+save constructs to a file\n\
+arguments:\n\
+  filename (str) - the name of file to save constructs to";
+static PyObject *e_save(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    char *fn = NULL;
+    void *env = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &fn))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvSave(env, fn)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* setAutoFloatDividend */
+E_STATUS_FUNC_SET_BOOL(env_setAutoFloatDividend,
+                       e_setAutoFloatDividend,
+                       EnvSetAutoFloatDividend)
+
+/* setDynamicConstraintChecking */
+E_STATUS_FUNC_SET_BOOL(env_setDynamicConstraintChecking,
+                       e_setDynamicConstraintChecking,
+                       EnvSetDynamicConstraintChecking)
+
+/* setSequenceOperatorRecognition */
+E_STATUS_FUNC_SET_BOOL(env_setSequenceOperatorRecognition,
+                       e_setSequenceOperatorRecognition,
+                       EnvSetSequenceOperatorRecognition)
+
+/* setStaticConstraintChecking */
+E_STATUS_FUNC_SET_BOOL(env_setStaticConstraintChecking,
+                       e_setStaticConstraintChecking,
+                       EnvSetStaticConstraintChecking)
+
+
+/* env_batchStar */
+static char e_batchStar__doc__[] = "\
+env_batchStar(env, filename)\n\
+batch execute commands stored in specified file\n\
+arguments:\n\
+  filename (str) - the name of file to read commands from";
+static PyObject *e_batchStar(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *fn = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &fn))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvBatchStar(env, fn)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_build */
+static char e_build__doc__[] = "\
+env_build(env, construct)\n\
+define specified construct\n\
+arguments:\n\
+  construct (str) - the construct to be added";
+static PyObject *e_build(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *cons = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &cons))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvBuild(env, cons)) {
+        SetEvaluationError(env, FALSE);
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_PARSEX();
+        FAIL();
+    }
+    SetEvaluationError(env, FALSE);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_eval */
+static char e_eval__doc__[] = "\
+env_eval(env, expression) -> (type, value)\n\
+evaluate the provided expression\n\
+returns: a pair holding the result in the form (type, return value)\n\
+arguments:\n\
+  expression (str) - the expression to evaluate";
+static PyObject *e_eval(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *expr = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &expr))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvEval(env, expr, &o)) {
+        SetEvaluationError(env, FALSE);
+        SetHaltExecution(env, FALSE);
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_EVALX();
+        FAIL();
+    }
+    SetEvaluationError(env, FALSE);
+    SetHaltExecution(env, FALSE);
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!p)
+        RETURN_NONE();
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+
+/* dribbleActive */
+E_STATUS_FUNC_GET_BOOL(env_dribbleActive, e_dribbleActive, EnvDribbleActive)
+
+/* dribbleOff */
+E_FUNC_VOID_BOOL(env_dribbleOff, e_dribbleOff, EnvDribbleOff)
+
+
+
+/* env_dribbleOn */
+static char e_dribbleOn__doc__[] = "\
+env_dribbleOn(env, filename)\n\
+turn the dribble function on\n\
+arguments:\n\
+  filename (str) - the name of file to write dribble information to";
+static PyObject *e_dribbleOn(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *fn = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &fn))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvDribbleOn(env, fn)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getWatchItem */
+static char e_getWatchItem__doc__[] = "\
+env_getWatchItem(env, item) -> bool\n\
+tell whether the specified item is watched or not\n\
+returns: True if specified item is being watched, False otherwise\n\
+arguments:\n\
+  item (str) - the item to monitor the status of, can be one of\n\
+               the following: facts, rules, focus, activations,\n\
+               compilations, statistics, globals, slots, instances,\n\
+               messages, message-handlers, generic-functions,\n\
+               method or deffunctions.";
+static PyObject *e_getWatchItem(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *item = NULL;
+    int rv = 0;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &item))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    rv = EnvGetWatchItem(env, item);
+    if(rv < 0) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    return Py_BuildValue("i", rv ? 1 : 0);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_unwatch */
+static char e_unwatch__doc__[] = "\
+env_unwatch(env, item)\n\
+turn off tracing for specified item\n\
+arguments:\n\
+  item (str) - the item to disable tracing for, can be one of\n\
+               the following: facts, rules, focus, activations,\n\
+               compilations, statistics, globals, slots, instances,\n\
+               messages, message-handlers, generic-functions,\n\
+               method or deffunctions.";
+static PyObject *e_unwatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *item = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &item))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvUnwatch(env, item)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_watch */
+static char e_watch__doc__[] = "\
+env_watch(env, item)\n\
+turn on tracing for specified item\n\
+arguments:\n\
+  item (str) - the item to enable tracing for, can be one of\n\
+               the following: facts, rules, focus, activations,\n\
+               compilations, statistics, globals, slots, instances,\n\
+               messages, message-handlers, generic-functions,\n\
+               method or deffunctions.";
+static PyObject *e_watch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *item = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &item)) FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvWatch(env, item)) {
+         RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.3 [E] - Deftemplate Functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *env_deftemplateExists(void *env, void *ptr) {
+    void *rv = EnvGetNextDeftemplate(env, NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = EnvGetNextDeftemplate(env, rv);
+    }
+    return NULL;
+}
+#define EPYDEFTEMPLATE_EXISTS(_e, _p) \
+    env_deftemplateExists(_e, clips_deftemplate_value(_p))
+#define ECHECK_DEFTEMPLATE(_e, _p) do { \
+        if(!EPYDEFTEMPLATE_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define ECHECK_RM_DEFTEMPLATE(_e, _p) do { \
+        if(_p && !EPYDEFTEMPLATE_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* API functions with documentation */
+
+/* env_deftemplateModule */
+static char e_deftemplateModule__doc__[] = "\
+env_deftemplateModule(env, deftemplate) -> str\n\
+retrieve the name of the module where the provided deftemplate resides\n\
+returns: a string containing a module name\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect";
+static PyObject *e_deftemplateModule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *s = NULL;
+    clips_DeftemplObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvDeftemplateModule(env, clips_deftemplate_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+#if CLIPS_MINOR > 23
+
+/* deftemplateSlotAllowedValues */
+static char e_deftemplateSlotAllowedValues__doc__[] = "\
+env_deftemplateSlotAllowedValues(env, deftemplate, name) -> (MULTIFIELD, list)\n\
+retrieve the allowed values for a slot of the specified deftemplate\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *e_deftemplateSlotAllowedValues(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvDeftemplateSlotAllowedValues(env, clips_deftemplate_value(p), name, &o);
+    rv = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotCardinality */
+static char e_deftemplateSlotCardinality__doc__[] = "\
+env_deftemplateSlotCardinality(env, deftemplate, name) -> (MULTIFIELD, list)\n\
+retrieve the cardinality for a slot of given deftemplate\n\
+returns: MULTIFIELD and a list of pairs of pairs (type, value)\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *e_deftemplateSlotCardinality(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvDeftemplateSlotCardinality(env, clips_deftemplate_value(p), name, &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotDefaultP */
+static char e_deftemplateSlotDefaultP__doc__[] = "\
+env_deftemplateSlotCardinality(env, deftemplate, name) -> int\n\
+tell whether or not a slot of given deftemplate has a default value\n\
+returns: one of NO_DEFAULT, STATIC_DEFAULT or DYNAMIC_DEFAULT\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *e_deftemplateSlotDefaultP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    int rv = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    rv = EnvDeftemplateSlotDefaultP(env, clips_deftemplate_value(p), name);
+    RELEASE_MEMORY_ERROR();
+    RETURN_INT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotDefaultValue */
+static char e_deftemplateSlotDefaultValue__doc__[] = "\
+env_deftemplateSlotDefaultValue(env, deftemplate, name) -> (MULTIFIELD, list)\n\
+retrieve default value(s) for a slot of given deftemplate\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *e_deftemplateSlotDefaultValue(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvDeftemplateSlotDefaultValue(env, clips_deftemplate_value(p), name, &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotExistP */
+static char e_deftemplateSlotExistP__doc__[] = "\
+env_deftemplateSlotExistP(env, deftemplate, name) -> bool\n\
+tell whether or not the given deftemplate has the specified slot\n\
+returns: True if the slot is present, False otherwise\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *e_deftemplateSlotExistP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    int rv = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    rv = EnvDeftemplateSlotExistP(env, clips_deftemplate_value(p), name);
+    RELEASE_MEMORY_ERROR();
+    RETURN_BOOL(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotMultiP */
+static char e_deftemplateSlotMultiP__doc__[] = "\
+env_deftemplateSlotMultiP(env, deftemplate, name) -> bool\n\
+tell whether or not the specified slot of given deftemplate is multifield\n\
+returns: True if it is multifield, False otherwise\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *e_deftemplateSlotMultiP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    int rv = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    rv = EnvDeftemplateSlotMultiP(env, clips_deftemplate_value(p), name);
+    RELEASE_MEMORY_ERROR();
+    RETURN_BOOL(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotNames */
+static char e_deftemplateSlotNames__doc__[] = "\
+env_deftemplateSlotNames(env, deftemplate) -> (MULTIFIELD, list)\n\
+retrieve the names of slots in given deftemplate (special case if implied)\n\
+returns: MULTIFIELD and a list of pairs or a pair (SYMBOL, 'implied')\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect";
+static PyObject *e_deftemplateSlotNames(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvDeftemplateSlotNames(env, clips_deftemplate_value(p), &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotRange */
+static char e_deftemplateSlotRange__doc__[] = "\
+env_deftemplateSlotRange(env, deftemplate, name) -> (MULTIFIELD, list)\n\
+retrieve the numeric range information for a slot of given deftemplate\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *e_deftemplateSlotRange(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvDeftemplateSlotRange(env, clips_deftemplate_value(p), name, &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotSingleP */
+static char e_deftemplateSlotSingleP__doc__[] = "\
+env_deftemplateSlotSingleP(env, deftemplate, name) -> bool\n\
+tell whether or not the specified slot of given deftemplate is single field\n\
+returns: True if it is single field, False otherwise\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *e_deftemplateSlotSingleP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    int rv = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    rv = EnvDeftemplateSlotSingleP(env, clips_deftemplate_value(p), name);
+    RELEASE_MEMORY_ERROR();
+    RETURN_BOOL(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* deftemplateSlotTypes */
+static char e_deftemplateSlotTypes__doc__[] = "\
+env_deftemplateSlotTypes(env, deftemplate, name) -> (MULTIFIELD, list)\n\
+retrieve names of the data types allowed for a slot of given deftemplate\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *e_deftemplateSlotTypes(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p, &name))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvDeftemplateSlotTypes(env, clips_deftemplate_value(p), name, &o);
+    rv = i_do2py(&o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+#else
+UNIMPLEMENT_VERSION(env_deftemplateSlotAllowedValues,
+                    e_deftemplateSlotAllowedValues)
+UNIMPLEMENT_VERSION(env_deftemplateSlotCardinality,
+                    e_deftemplateSlotCardinality)
+UNIMPLEMENT_VERSION(env_deftemplateSlotDefaultP,
+                    e_deftemplateSlotDefaultP)
+UNIMPLEMENT_VERSION(env_deftemplateSlotDefaultValue,
+                    e_deftemplateSlotDefaultValue)
+UNIMPLEMENT_VERSION(env_deftemplateSlotExistP,
+                    e_deftemplateSlotExistP)
+UNIMPLEMENT_VERSION(env_deftemplateSlotMultiP,
+                    e_deftemplateSlotMultiP)
+UNIMPLEMENT_VERSION(env_deftemplateSlotNames,
+                    e_deftemplateSlotNames)
+UNIMPLEMENT_VERSION(env_deftemplateSlotRange,
+                    e_deftemplateSlotRange)
+UNIMPLEMENT_VERSION(env_deftemplateSlotSingleP,
+                    e_deftemplateSlotSingleP)
+UNIMPLEMENT_VERSION(env_deftemplateSlotTypes,
+                    e_deftemplateSlotTypes)
+#endif /* CLIPS_MINOR > 23 */
+
+/* env_findDeftemplate */
+static char e_findDeftemplate__doc__[] = "\
+env_findDeftemplate(env, name) -> deftemplate\n\
+retrieve deftemplate object corresponding to the specified name\n\
+returns: the deftemplate as a new object\n\
+arguments:\n\
+  name (str) - the name of the deftemplate to look for";
+static PyObject *e_findDeftemplate(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DeftemplObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &name))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvFindDeftemplate(env, name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_deftemplate_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deftemplate_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDeftemplateList */
+static char e_getDeftemplateList__doc__[] = "\
+env_getDeftemplateList(env [, module]) -> (MULTIFIELD, list)\n\
+retrieve list of deftemplate names in specified defmodule\n\
+returns: value MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_getDeftemplateList(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDeftemplateList(env,
+        &o, module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDeftemplateName */
+static char e_getDeftemplateName__doc__[] = "\
+env_getDeftemplateName(env, deftemplate) -> str\n\
+retrieve the name of given deftemplate object\n\
+returns: a string containing the name\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate object";
+static PyObject *e_getDeftemplateName(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    clips_DeftemplObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetDeftemplateName(env, clips_deftemplate_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP()
+END_FAIL
+}
+
+/* env_getDeftemplatePPForm */
+static char e_getDeftemplatePPForm__doc__[] = "\
+env_getDeftemplatePPForm(env, deftemplate) -> str\n\
+retrieve the pretty-print form of given deftemplate object\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate object";
+static PyObject *e_getDeftemplatePPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *s = NULL;
+    clips_DeftemplObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvGetDeftemplatePPForm(env, clips_deftemplate_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP()
+END_FAIL
+}
+
+/* env_getDeftemplateWatch */
+static char e_getDeftemplateWatch__doc__[] = "\
+env_getDeftemplateWatch(env, deftemplate) -> bool\n\
+tell if deftemplate is being watched\n\
+returns: True if the deftemplate is being watched, False otherwise\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate object";
+static PyObject *e_getDeftemplateWatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    i = EnvGetDeftemplateWatch(env, clips_deftemplate_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP()
+END_FAIL
+}
+
+/* env_getNextDeftemplate */
+static char e_getNextDeftemplate__doc__[] = "\
+env_getNextDeftemplate(env [, deftemplate]) -> deftemplate\n\
+find next deftemplate in the list, first if argument is omitted\n\
+returns: next deftemplate object, None if already at last deftemplate\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to start from";
+static PyObject *e_getNextDeftemplate(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p)
+        ECHECK_DEFTEMPLATE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextDeftemplate(env, p ? clips_deftemplate_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) RETURN_NONE();
+    clips_deftemplate_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deftemplate_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_isDeftemplateDeletable */
+static char e_isDeftemplateDeletable__doc__[] = "\
+env_isDeftemplateDeletable(env, deftemplate) -> bool\n\
+tell whether or not given deftemplate object can be deleted\n\
+returns: True when deftemplate can be deleted, False otherwise\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate object";
+static PyObject *e_isDeftemplateDeletable(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    i = EnvIsDeftemplateDeletable(env, clips_deftemplate_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP()
+END_FAIL
+}
+
+/* env_listDeftemplates */
+static char e_listDeftemplates__doc__[] = "\
+env_listDeftemplates(env, logicalname [, module])\n\
+list deftemplates to output identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_listDeftemplates(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!",
+                         &clips_EnvType, &pyenv,
+                         &lname, &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvListDeftemplates(env, lname,
+        module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setDeftemplateWatch */
+static char e_setDeftemplateWatch__doc__[] = "\
+env_setDeftemplateWatch(env, state, deftemplate)\n\
+set the specified deftemplate to a new watch state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  deftemplate (deftemplate) - the deftemplate object";
+static PyObject *e_setDeftemplateWatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    PyObject *state = NULL;
+    clips_DeftemplObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!OO!",
+                         &clips_EnvType, &pyenv,
+                         &state, &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, p);
+    EnvSetDeftemplateWatch(env,
+        PyObject_IsTrue(state), clips_deftemplate_value(p));
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP()
+END_FAIL
+}
+
+/* env_undeftemplate */
+static char e_undeftemplate__doc__[] = "\
+env_undeftemplate(env [, deftemplate])\n\
+remove a deftemplate or all deftemplates from the system\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate to remove, all if omitted";
+static PyObject *e_undeftemplate(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_RM_DEFTEMPLATE(env, p);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvUndeftemplate(env, p ? clips_deftemplate_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP()
+END_FAIL
+}
+
+
+/* 4.4 [E] - Fact Functions */
+
+/* env_assertFact */
+static char e_assertFact__doc__[] = "\
+env_assertFact(env, fact) -> fact\n\
+add a fact to the fact list\n\
+returns: the asserted fact as a new object\n\
+arguments:\n\
+  fact (fact) - the fact to assert";
+static PyObject *e_assertFact(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_FactObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_FactType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CHECK_VALID_FACT(env, p);
+    /* if fact is read-only, it was previously asserted and can't be reused */
+    if(clips_fact_readonly(p)) {
+        ERROR_CLIPS_REASSERT();
+        FAIL();
+    }
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvAssert(env, clips_fact_value(p));
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    if(!ptr) {
+        ERROR_CLIPS_ASSERT();
+        FAIL();
+    }
+    /* now the old fact cannot be modified anymore, even on future failure */
+    ENV_REMOVE_JUSTASSERTED_FACT(pyenv);
+    ENV_REMOVE_HASH_FACT(pyenv, p);
+    clips_fact_readonly(p) = TRUE;
+    clips_fact_New(env, q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_fact_readonly(q) = TRUE;
+    clips_fact_assign(q, ptr);
+    clips_fact_lock(q);
+    ENV_CHECK_VALID_FACT(env, q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_assertString */
+static char e_assertString__doc__[] = "\
+env_assertString(env, expr) -> fact\n\
+add a fact to the fact list using a string\n\
+returns: the asserted fact as a new object\n\
+arguments:\n\
+  expr (str) - string containing a list of primitive datatypes";
+static PyObject *e_assertString(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *expr = NULL;
+    clips_FactObject *p = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &expr))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvAssertString(env, expr);
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    if(!ptr) {
+        ERROR_CLIPS_ASSERT();
+        FAIL();
+    }
+    clips_fact_New(env, p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_fact_readonly(p) = TRUE;
+    clips_fact_assign(p, ptr);
+    clips_fact_lock(p);
+    ENV_CHECK_VALID_FACT(env, p);
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_assignFactSlotDefaults */
+static char e_assignFactSlotDefaults__doc__[] = "\
+env_assignFactSlotDefaults(env, fact)\n\
+assign default values to the slots of a fact\n\
+arguments:\n\
+  fact (fact) - the fact whose slots are to reset to default values";
+static PyObject *e_assignFactSlotDefaults(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_FactObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_FactType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CHECK_VALID_FACT(env, p);
+    if(clips_fact_readonly(p)) {
+        ERROR_CLIPS_READONLY();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvAssignFactSlotDefaults(env, clips_fact_value(p))) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_OTHER("could not assign default values to fact");
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_createFact */
+static char e_createFact__doc__[] = "\
+env_createFact(env, deftemplate) -> fact\n\
+create a new fact object using the provided deftemplate\n\
+returns: a new fact object\n\
+arguments:\n\
+  deftemplate (deftemplate) - the deftemplate defining the fact type";
+static PyObject *e_createFact(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_FactObject *p = NULL;
+    clips_DeftemplObject *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeftemplType, &q))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvCreateFact(env, clips_deftemplate_value(q));
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_CREATION();
+        FAIL();
+    }
+    clips_fact_New(env, p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_fact_assign(p, ptr);
+    ENV_CHECK_VALID_FACT(env, p);
+    ENV_ADD_NONASSERTED_FACT(pyenv);
+    ENV_APPEND_HASH_FACT(pyenv, p);
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_decrementFactCount */
+UNIMPLEMENT(env_decrementFactCount, e_decrementFactCount)
+
+/* env_factIndex */
+static char e_factIndex__doc__[] = "\
+env_factIndex(env, fact) -> int\n\
+retrieve the index of specified fact in fact list\n\
+arguments:\n\
+  fact (fact) - the fact to look for";
+static PyObject *e_factIndex(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_FactObject *p = NULL;
+    long int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_FactType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CHECK_VALID_FACT(env, p);
+    ACQUIRE_MEMORY_ERROR();     /* needed? */
+    i = EnvFactIndex(env, clips_fact_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    if(p) DELETE(p);
+    SKIP();
+END_FAIL
+}
+
+/* env_facts */
+static char e_facts__doc__[] = "\
+env_facts(env, logicalname [, module [, start [, end [, max]]]])\n\
+list facts to the output stream identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule, None for all modules\n\
+  start (int) - first fact, -1 for no restriction\n\
+  end (int) - last fact, -1 for no restriction\n\
+  max (int) - maximum number of facts, -1 for no restriction";
+static PyObject *e_facts(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    PyObject *module = NULL;
+    char *lname = NULL;
+    int start = -1, end = -1, max = -1;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!iii",
+                         &clips_EnvType, &pyenv, &lname,
+                         &clips_DefmoduleType, &module,
+                         &start, &end, &max))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvFacts(
+        env, lname,
+        module && module != Py_None ? clips_defmodule_value(module) : NULL,
+        start, end, max);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* getFactDuplication */
+E_STATUS_FUNC_GET_BOOL(env_getFactDuplication,
+                       e_getFactDuplication,
+                       EnvGetFactDuplication)
+
+/* getFactListChanged */
+E_STATUS_FUNC_GET_BOOL(env_getFactListChanged,
+                       e_getFactListChanged,
+                       EnvGetFactListChanged)
+
+
+/* env_getFactPPForm */
+static char e_getFactPPForm__doc__[] = "\
+env_getFactPPForm(env, fact) -> str\n\
+retrieve the pretty-print form of given fact\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  fact (fact) - the fact object to inspect";
+static PyObject *e_getFactPPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *buffer = NEW_ARRAY(char, ppbuffer_size);
+    PyObject *rv = NULL;
+    clips_FactObject *p = NULL;
+
+    if(!buffer) {
+        ERROR_MEMORY("cannot allocate buffer");
+        FAIL();
+    }
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_FactType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CHECK_VALID_FACT(env, p);
+    ENV_CHECK_LOST_FACT(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetFactPPForm(env, buffer, ppbuffer_size-1, clips_fact_value(p));
+    RELEASE_MEMORY_ERROR();
+    rv = Py_BuildValue("s", buffer);
+    DELETE(buffer);
+    return rv;
+
+BEGIN_FAIL
+    if(buffer) DELETE(buffer);
+    SKIP();
+END_FAIL
+}
+
+/* env_getFactSlot */
+static char e_getFactSlot__doc__[] = "\
+env_getFactSlot(env, fact [, slotname]) -> (type, value)\n\
+get the slot value for the specified fact given the slot name\n\
+returns: a value or a multifield in the form (type, return value)\n\
+arguments:\n\
+  fact (fact) - the fact to inspect\n\
+  slotname (str) - the name of the slot to retrieve, should be omitted\n\
+                   for the implied multifield slot of an implied\n\
+                   deftemplate";
+static PyObject *e_getFactSlot(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_FactObject *p = NULL;
+    char *slotname = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!|s",
+                         &clips_EnvType, &pyenv,
+                         &clips_FactType, &p, &slotname))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CHECK_VALID_FACT(env, p);
+    ENV_CHECK_LOST_FACT(env, p);
+    /* we make some considerations about this call, to avoid nasty errors */
+    /* check that the slot name can be really omitted (see docstring) */
+    if(!slotname && !
+       ((struct deftemplate *)
+           ((struct fact *)clips_fact_value(p))->whichDeftemplate
+       )->implied) {
+        ERROR_VALUE("cannot omit slot name using this fact");
+        FAIL();
+    }
+    /* end of considerations */
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvGetFactSlot(env, clips_fact_value(p), slotname, &o)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    rv = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    Py_XDECREF(rv);
+END_FAIL
+}
+
+/* env_getNextFact */
+static char e_getNextFact__doc__[] = "\
+env_getNextFact(env [, fact]) -> fact\n\
+retrieve next fact object, first if argument is omitted\n\
+returns: a fact object, None if already at last fact\n\
+arguments:\n\
+  fact (fact) - the fact to start from";
+static PyObject *e_getNextFact(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_FactObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_FactType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p)
+        ENV_CHECK_VALID_FACT(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextFact(env, p ? clips_fact_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_fact_New(env, q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_fact_readonly(q) = TRUE;
+    clips_fact_assign(q, ptr);
+    clips_fact_lock(q);
+    ENV_CHECK_VALID_FACT(env, q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* 4.4.12a [E] - getNextFactInTemplate */
+static char e_getNextFactInTemplate__doc__[] = "\
+env_getNextFactInTemplate(env, deftemplate [, fact]) -> fact\n\
+retrieve next fact object for a deftemplate, first if fact is omitted\n\
+returns: a fact object, None if already at last fact\n\
+arguments:\n\
+  deftemplate (deftemplate) - the template to find facts of\n\
+  fact (fact) - the fact to start from";
+static PyObject *e_getNextFactInTemplate(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_FactObject *p = NULL, *q = NULL;
+    clips_DeftemplObject *t = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DeftemplType, &t, &clips_FactType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFTEMPLATE(env, t);
+    if(p)
+        ENV_CHECK_VALID_FACT(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextFactInTemplate(env,
+        clips_deftemplate_value(t), p ? clips_fact_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_fact_New(env, q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_fact_readonly(q) = TRUE;
+    clips_fact_assign(q, ptr);
+    clips_fact_lock(q);
+    ENV_CHECK_VALID_FACT(env, q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_incrementFactCount */
+UNIMPLEMENT(env_incrementFactCount, e_incrementFactCount)
+
+/* env_loadFacts */
+static char e_loadFacts__doc__[] = "\
+env_loadFacts(env, filename)\n\
+load facts from specified file\n\
+arguments:\n\
+  filename (str) - the name of file to load facts from";
+static PyObject *e_loadFacts(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *fn = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &fn))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvLoadFacts(env, fn)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+#if CLIPS_MINOR > 23
+
+/* ppFact */
+static char e_ppFact__doc__[] = "\
+env_ppFact(env, fact, output [, ignoredefault])\n\
+write the pretty-print form of given fact to logical output\n\
+arguments:\n\
+  fact (fact) - the fact to write\n\
+  output (str) - logical name of stream to output to\n\
+  ignoredefault (bool) - True to skip slots whose values equal defaults";
+static PyObject *e_ppFact(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_FactObject *p = NULL;
+    char *s = NULL;
+    PyObject *o = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!s|O",
+                         &clips_EnvType, &pyenv, &clips_FactType, &p, &s, &o))
+        FAIL();
+    ENV_CHECK_VALID_FACT(env, p);
+    ENV_CHECK_LOST_FACT(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvPPFact(env, clips_fact_value(p), s, o ? PyObject_IsTrue(o) : FALSE);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+#else
+UNIMPLEMENT_VERSION(env_ppFact, e_ppFact)
+#endif /* CLIPS_MINOR > 23 */
+
+/* env_putFactSlot */
+static char e_putFactSlot__doc__[] = "\
+env_putFactSlot(env, fact, name, value)\n\
+changes the value of specified slot in given fact\n\
+arguments:\n\
+  fact (fact) - the fact to change: must have been created with createFact\n\
+  name (str) - the name of the slot to change\n\
+  value (pair) - a pair (type, value) containing the value to assign";
+static PyObject *e_putFactSlot(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    DATA_OBJECT o = { 0 };
+    clips_FactObject *f = NULL;
+    PyObject *p = NULL;
+    char *s;
+
+    /* note that function i_py2do checks for last argument validity */
+    if(!PyArg_ParseTuple(args, "O!O!sO",
+                         &clips_EnvType, &pyenv,
+                         &clips_FactType, &f, &s, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CHECK_VALID_FACT(env, f);
+    ENV_CHECK_LOST_FACT(env, f);
+    if(clips_fact_readonly(f)) {
+        ERROR_CLIPS_READONLY();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    if(!i_py2do_e(env, p, &o)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    if(!EnvPutFactSlot(env, clips_fact_value(f), s, &o)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_OTHER("fact slot could not be modified");
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_retract */
+static char e_retract__doc__[] = "\
+env_retract(env, fact)\n\
+retract provided fact\n\
+arguments:\n\
+  fact (fact) - the fact to retract";
+static PyObject *e_retract(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_FactObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_FactType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CHECK_VALID_FACT(env, p);
+    ENV_CHECK_LOST_FACT(env, p);
+    clips_fact_lock(p);
+    /* if the fact was actually asserted it must now be read-only */
+    if(!clips_fact_readonly(p)) {
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvRetract(env, clips_fact_value(p))) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_saveFacts */
+static char e_saveFacts__doc__[] = "\
+env_saveFacts(env, filename, scope)\n\
+save the facts in the specified scope\n\
+arguments:\n\
+  filename (str) - the name of the file to save to\n\
+  scope (int) - can be one of LOCAL_SAVE or VISIBLE_SAVE";
+static PyObject *e_saveFacts(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    int scope = 0;
+    char *fn = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!si",
+                         &clips_EnvType, &pyenv, &fn, &scope))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(scope != LOCAL_SAVE && scope != VISIBLE_SAVE) {
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvSaveFacts(env, fn, scope, NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* setFactDuplication */
+E_STATUS_FUNC_SET_BOOL(env_setFactDuplication,
+                       e_setFactDuplication,
+                       EnvSetFactDuplication)
+
+/* setFactListChanged */
+E_STATUS_FUNC_SET_BOOL(env_setFactListChanged,
+                       e_setFactListChanged,
+                       EnvSetFactListChanged)
+
+/* env_factDeftemplate */
+static char e_factDeftemplate__doc__[] = "\
+env_factDeftemplate(env, fact) -> deftemplate\n\
+return the deftemplate associated with a particular fact\n\
+returns: a deftemplate object, None if no deftemplate associated\n\
+arguments:\n\
+  fact (fact) - the fact to examine";
+static PyObject *e_factDeftemplate(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_FactObject *p = NULL;
+    clips_DeftemplObject *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_FactType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CHECK_VALID_FACT(env, p);
+    ENV_CHECK_LOST_FACT(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvFactDeftemplate(env, clips_fact_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!ptr || !env_deftemplateExists(env, ptr))
+        RETURN_NONE();
+    clips_deftemplate_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deftemplate_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_factExistp */
+static char e_factExistp__doc__[] = "\
+env_factExistp(env, fact) -> bool\n\
+tell whether a fact is in the list or has been retracted\n\
+returns: True if the fact exixts, False if it was retracted\n\
+arguments:\n\
+  fact (fact) - the fact to check";
+static PyObject *e_factExistp(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    clips_FactObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_FactType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    i = FactExistp(clips_fact_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_factSlotNames */
+static char e_factSlotNames__doc__[] = "\
+env_factSlotNames(env, fact) -> (MULTIFIELD, list)\n\
+get the slot names for the specified fact\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  fact (fact) - the fact to inspect";
+static PyObject *e_factSlotNames(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_FactObject *p = NULL;
+    PyObject *q = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_FactType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CHECK_VALID_FACT(env, p);
+    ENV_CHECK_LOST_FACT(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvFactSlotNames(env, clips_fact_value(p), &o);
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    return q;
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getFactList */
+static char e_getFactList__doc__[] = "\
+env_getFactList(env [, module]) -> (type, list)\n\
+retrieve list of fact identifiers in specified defmodule\n\
+returns:  MULTIFIELD and a list of pairs (STRING, identifier)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_getFactList(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    PyObject *q = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetFactList(env, &o, module ? clips_defmodule_value(module) : NULL);
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    return q;
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_loadFactsFromString */
+static char e_loadFactsFromString__doc__[] = "\
+env_loadFactsFromString(env, string)\n\
+load facts from specified string into the fact list\n\
+arguments:\n\
+  string (str) - string to load facts from";
+static PyObject *e_loadFactsFromString(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &s)) FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvLoadFactsFromString(env, s, -1)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_PARSEX();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.5 [E] - Deffacts Functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *env_deffactsExists(void *env, void *ptr) {
+    void *rv = EnvGetNextDeffacts(env, NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = EnvGetNextDeffacts(env, rv);
+    }
+    return NULL;
+}
+#define EPYDEFFACTS_EXISTS(_e, _p) \
+    env_deffactsExists(_e, clips_deffacts_value(_p))
+#define ECHECK_DEFFACTS(_e, _p) do { \
+        if(!EPYDEFFACTS_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define ECHECK_RM_DEFFACTS(_e, _p) do { \
+        if(_p && !EPYDEFFACTS_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* API functions with documentation */
+
+/* env_deffactsModule */
+static char e_deffactsModule__doc__[] = "\
+env_deffactsModule(env, deffacts) -> str\n\
+retrieve the module where the specified deffacts object is defined\n\
+returns: the module name\n\
+arguments:\n\
+  deffacts (deffacts) - the deffacts object to inspect";
+static PyObject *e_deffactsModule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffactsObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeffactsType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFFACTS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvDeffactsModule(env, clips_deffacts_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_findDeffacts */
+static char e_findDeffacts__doc__[] = "\
+env_findDeffacts(env, name) -> deffacts\n\
+find the deffacts object whose name is specified\n\
+returns: the deffacts as a new object\n\
+arguments:\n\
+  name (str) - the name of the deffacts to look for";
+static PyObject *e_findDeffacts(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DeffactsObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &name))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvFindDeffacts(env, name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_deffacts_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deffacts_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDeffactsList */
+static char e_getDeffactsList__doc__[] = "\
+env_getDeffactsList(env [, module]) -> (MULTIFIELD, list)\n\
+retrieve the list of deffacts in specified defmodule\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_getDeffactsList(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDeffactsList(env, &o, module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDeffactsName */
+static char e_getDeffactsName__doc__[] = "\
+env_getDeffactsName(env, deffacts) -> str\n\
+retrieve the name of deffacts object\n\
+returns: the deffacts name\n\
+arguments:\n\
+  deffacts (deffacts) - the deffacts to inspect";
+static PyObject *e_getDeffactsName(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffactsObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeffactsType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFFACTS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetDeffactsName(env, clips_deffacts_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDeffactsPPForm */
+static char e_getDeffactsPPForm__doc__[] = "\
+env_getDeffactsPPForm(env, deffacts) -> str\n\
+retrieve the pretty-print form of deffacts object\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  deffacts (deffacts) - the deffacts to inspect";
+static PyObject *e_getDeffactsPPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffactsObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeffactsType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFFACTS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvGetDeffactsPPForm(env, clips_deffacts_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getNextDeffacts */
+static char e_getNextDeffacts__doc__[] = "\
+env_getNextDeffacts(env [, deffacts]) -> deffacts\n\
+retrieve next deffacts object in list, first if argument is omitted\n\
+returns: a deffacts object, None if already at last deffacts\n\
+arguments:\n\
+  deffacts (deffacts) - the deffacts to start from";
+static PyObject *e_getNextDeffacts(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffactsObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_DeffactsType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p)
+        ECHECK_DEFFACTS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextDeffacts(env, p ? clips_deffacts_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_deffacts_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deffacts_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_isDeffactsDeletable */
+static char e_isDeffactsDeletable__doc__[] = "\
+env_isDeffactsDeletable(env, deffacts) -> bool\n\
+tell whether or not given deffacts object can be deleted\n\
+returns: True when deffacts can be deleted, False otherwise\n\
+arguments:\n\
+  deffacts (deffacts) - the deffacts object";
+static PyObject *e_isDeffactsDeletable(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffactsObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeffactsType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFFACTS(env, p);
+    i = EnvIsDeffactsDeletable(env, clips_deffacts_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_listDeffacts */
+static char e_listDeffacts__doc__[] = "\
+env_listDeffacts(env, output [, module])\n\
+list deffacts objects in specified defmodule to logical output\n\
+arguments:\n\
+  output (str) - logical name of stream to output to\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_listDeffacts(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!",
+                         &clips_EnvType, &pyenv,
+                         &s, &clips_DefmoduleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvListDeffacts(env, s, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_undeffacts */
+static char e_undeffacts__doc__[] = "\
+env_undeffacts(env [, deffacts])\n\
+delete a deffacts object or all deffacts objects\n\
+arguments:\n\
+  deffacts (deffacts) - the deffacts to be deleted, all if omitted";
+static PyObject *e_undeffacts(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffactsObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeffactsType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_RM_DEFFACTS(env, p);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvUndeffacts(env, p ? clips_deffacts_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.6 [E] - Defrule Functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *env_defruleExists(void *env, void *ptr) {
+    void *rv = EnvGetNextDefrule(env, NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = EnvGetNextDefrule(env, rv);
+    }
+    return NULL;
+}
+#define EPYDEFRULE_EXISTS(_e, _p) \
+    env_defruleExists(_e, clips_defrule_value(_p))
+#define ECHECK_DEFRULE(_e, _p) do { \
+        if(!EPYDEFRULE_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define ECHECK_RM_DEFRULE(_e, _p) do { \
+        if(_p && !EPYDEFRULE_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* API functions with documentation */
+
+/* env_defruleHasBreakpoint */
+static char e_defruleHasBreakpoint__doc__[] = "\
+env_defruleHasBreakpoint(env, defrule) -> bool\n\
+test whether or not the given defrule has a breakpoint\n\
+returns: True if the defrule has a breakpoint, False otherwise\n\
+arguments:\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *e_defruleHasBreakpoint(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    i = EnvDefruleHasBreakpoint(env, clips_defrule_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_defruleModule */
+static char e_defruleModule__doc__[] = "\
+env_defruleModule(env, defrule) -> str\n\
+retrieve the module where the defrule is defined\n\
+returns: the requested name of module\n\
+arguments:\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *e_defruleModule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvDefruleModule(env, clips_defrule_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_findDefrule */
+static char e_findDefrule__doc__[] = "\
+env_findDefrule(env, name) -> defrule\n\
+find the defrule with the specified name\n\
+returns: the defrule as a new object\n\
+arguments:\n\
+  name (str) - the name of defrule to look for";
+static PyObject *e_findDefrule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    clips_DefruleObject *p = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &name))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvFindDefrule(env, name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    clips_defrule_New(p);
+    clips_defrule_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefruleList */
+static char e_getDefruleList__doc__[] = "\
+env_getDefruleList(env [, module]) -> (MULTIFIELD, list)\n\
+retrieve the list of defrule objects in the specified defmodule\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_getDefruleList(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDefruleList(env, &o, module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefruleName */
+static char e_getDefruleName__doc__[] = "\
+env_getDefruleName(env, defrule) -> str\n\
+retrieve the name of specified defrule\n\
+returns: a string containing the defrule name\n\
+arguments:\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *e_getDefruleName(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetDefruleName(env, clips_defrule_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefrulePPForm */
+static char e_getDefrulePPForm__doc__[] = "\
+env_getDefrulePPForm(env, defrule) -> str\n\
+retrieve the pretty-print form of specified defrule\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *e_getDefrulePPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    s = EnvGetDefrulePPForm(env, clips_defrule_value(p));
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefruleWatchActivations */
+static char e_getDefruleWatchActivations__doc__[] = "\
+env_getDefruleWatchActivations(env, defrule) -> bool\n\
+tell whether the specified defrule is watched for activations\n\
+returns: True if activations are watched, False otherwise\n\
+arguments:\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *e_getDefruleWatchActivations(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    i = EnvGetDefruleWatchActivations(env, clips_defrule_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefruleWatchFirings */
+static char e_getDefruleWatchFirings__doc__[] = "\
+env_getDefruleWatchFirings(env, defrule) -> bool\n\
+tell whether the specified defrule is watched for firings\n\
+returns: True if rule firings are watched, False otherwise\n\
+arguments:\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *e_getDefruleWatchFirings(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    i = EnvGetDefruleWatchFirings(env, clips_defrule_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* getIncrementalReset */
+E_STATUS_FUNC_GET_BOOL(env_getIncrementalReset,
+                       e_getIncrementalReset,
+                       EnvGetIncrementalReset)
+
+
+/* env_getNextDefrule */
+static char e_getNextDefrule__doc__[] = "\
+env_getNextDefrule(env [, defrule]) -> defrule\n\
+retrieve next defrule object in list, first if argument is omitted\n\
+returns: a defrule object, None if already at last defrule\n\
+arguments:\n\
+  defrule (defrule) - the defrule to start from";
+static PyObject *e_getNextDefrule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p)
+        ECHECK_DEFRULE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextDefrule(env, p ? clips_defrule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) RETURN_NONE();
+    clips_defrule_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defrule_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_isDefruleDeletable */
+static char e_isDefruleDeletable__doc__[] = "\
+env_isDefruleDeletable(env, defrule) -> bool\n\
+tell whether or not given defrule object can be deleted\n\
+returns: True when defrule can be deleted, False otherwise\n\
+arguments:\n\
+  defrule (defrule) - the defrule object";
+static PyObject *e_isDefruleDeletable(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    i = EnvIsDefruleDeletable(env, clips_defrule_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_listDefrules */
+static char e_listDefrules__doc__[] = "\
+env_listDefrules(env, output [, module])\n\
+list defrule objects in specified defmodule to logical output\n\
+arguments:\n\
+  output (str) - logical name of stream to output to\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_listDefrules(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!",
+                         &clips_EnvType, &pyenv, &s, &clips_DefmoduleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvListDefrules(env, s, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_matches */
+static char e_matches__doc__[] = "\
+env_matches(env, output, defrule)\n\
+list defrule partial matches\n\
+arguments:\n\
+  output (str) - logical name of stream to output to\n\
+  defrule (defrule) - the defrule to inspect";
+static PyObject *e_matches(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!sO!",
+                         &clips_EnvType, &pyenv,
+                         &s, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvMatches_PY(env, s, clips_defrule_value(p))) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_refresh */
+static char e_refresh__doc__[] = "\
+env_refresh(env, defrule)\n\
+refresh a defrule\n\
+arguments:\n\
+  defrule (defrule) - the defrule to refresh";
+static PyObject *e_refresh(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvRefresh(env, clips_defrule_value(p))) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_removeBreak */
+static char e_removeBreak__doc__[] = "\
+env_removeBreak(env, defrule)\n\
+remove the breakpoint from a defrule\n\
+arguments:\n\
+  defrule (defrule) - the defrule to access";
+static PyObject *e_removeBreak(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvRemoveBreak(env, clips_defrule_value(p))) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setBreak */
+static char e_setBreak__doc__[] = "\
+env_setBreak(env, defrule)\n\
+set a breakpoint to a defrule\n\
+arguments:\n\
+  defrule (defrule) - the defrule to access";
+static PyObject *e_setBreak(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSetBreak(env, clips_defrule_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setDefruleWatchActivations */
+static char e_setDefruleWatchActivations__doc__[] = "\
+env_setDefruleWatchActivations(env, state, defrule)\n\
+set activations watch of a defrule to a new state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defrule (defrule) - the defrule to access";
+static PyObject *e_setDefruleWatchActivations(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+    PyObject *state = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!OO!",
+                         &clips_EnvType, &pyenv,
+                         &state, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    EnvSetDefruleWatchActivations(env,
+        PyObject_IsTrue(state), clips_defrule_value(p));
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setDefruleWatchFirings */
+static char e_setDefruleWatchFirings__doc__[] = "\
+env_setDefruleWatchFirings(env, state, defrule)\n\
+set firings watch of a defrule to a new state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defrule (defrule) - the defrule to access";
+static PyObject *e_setDefruleWatchFirings(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+    PyObject *state = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!OO!",
+                         &clips_EnvType, &pyenv,
+                         &state, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFRULE(env, p);
+    EnvSetDefruleWatchFirings(env,
+        PyObject_IsTrue(state), clips_defrule_value(p));
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setIncrementalReset */
+E_STATUS_FUNC_SET_BOOL(env_setIncrementalReset,
+                       e_setIncrementalReset,
+                       EnvSetIncrementalReset)
+
+/* env_showBreaks */
+static char e_showBreaks__doc__[] = "\
+env_showBreaks(env, output [, module])\n\
+list breakpoints in specified defmodule to logical output\n\
+arguments:\n\
+  output (str) - logical name of stream to output to\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_showBreaks(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!",
+                         &clips_EnvType, &pyenv,
+                         &s, &clips_DefmoduleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvShowBreaks(env, s, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_undefrule */
+static char e_undefrule__doc__[] = "\
+env_undefrule(env [, defrule])\n\
+delete a defrule object or all defrule objects\n\
+arguments:\n\
+  defrule (defrule) - the defrule to be deleted, all if omitted";
+static PyObject *e_undefrule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefruleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefruleType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p && !env_defruleExists(env, clips_defrule_value(p))) {
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvUndefrule(env, p ? clips_defrule_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.7 [E] - Agenda functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *env_activationExists(void *env, void *ptr) {
+    void *rv = EnvGetNextActivation(env, NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = EnvGetNextActivation(env, rv);
+    }
+    return NULL;
+}
+#define EPYACTIVATION_EXISTS(_e, _p) \
+    env_activationExists(_e, clips_activation_value(_p))
+#define ECHECK_ACTIVATION(_e, _p) do { \
+        if(!EPYACTIVATION_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define ECHECK_RM_ACTIVATION(_e, _p) do { \
+        if(_p && !EPYACTIVATION_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* API functions with documentation */
+
+/* addRunFunction */
+UNIMPLEMENT(env_addRunFunction, e_addRunFunction)
+
+/* env_agenda */
+static char e_agenda__doc__[] = "\
+env_agenda(env, output [, module])\n\
+list agenda rules in specified defmodule to logical output\n\
+arguments:\n\
+  output (str) - logical name of stream to output to\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_agenda(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!",
+                         &clips_EnvType, &pyenv,
+                         &s, &clips_DefmoduleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvAgenda(env, s, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* clearFocusStack */
+E_FUNC_VOID_ONLY(env_clearFocusStack, e_clearFocusStack, EnvClearFocusStack)
+
+/* env_deleteActivation */
+static char e_deleteActivation__doc__[] = "\
+env_deleteActivation(env, activation)\n\
+remove activation from agenda\n\
+arguments:\n\
+  activation (activation) - the activation to delete";
+static PyObject *e_deleteActivation(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_ActivationObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_ActivationType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_RM_ACTIVATION(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvDeleteActivation(env, p ? clips_activation_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_focus */
+static char e_focus__doc__[] = "\
+env_focus(env, module)\n\
+set current focus\n\
+arguments:\n\
+  module (defmodule) - the defmodule to set focus to";
+static PyObject *e_focus(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefmoduleType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvFocus(env, clips_defmodule_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getActivationName */
+static char e_getActivationName__doc__[] = "\
+env_getActivationName(env, activation) -> str\n\
+retrieve the name of specified activation\n\
+returns: name as a string\n\
+arguments:\n\
+  activation (activation) - the activation to inspect";
+static PyObject *e_getActivationName(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_ActivationObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_ActivationType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_ACTIVATION(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetActivationName(env, clips_defrule_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getActivationPPForm */
+static char e_getActivationPPForm__doc__[] = "\
+env_getActivationPPForm(env, activation) -> str\n\
+retrieve the pretty-print form of specified activation\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  activation (activation) - the activation to inspect";
+static PyObject *e_getActivationPPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_ActivationObject *p = NULL;
+    char *buffer = NEW_ARRAY(char, ppbuffer_size);
+    PyObject *rv = NULL;
+
+    if(!buffer) {
+        ERROR_MEMORY("cannot allocate buffer");
+        FAIL();
+    }
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_ActivationType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_ACTIVATION(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetActivationPPForm(env, buffer,
+        ppbuffer_size-1, clips_activation_value(p));
+    RELEASE_MEMORY_ERROR();
+    rv = Py_BuildValue("s", buffer);
+    DELETE(buffer);
+    return rv;
+
+BEGIN_FAIL
+    if(buffer) DELETE(buffer);
+    SKIP();
+END_FAIL
+}
+
+/* env_getActivationSalience */
+static char e_getActivationSalience__doc__[] = "\
+env_getActivationSalience(env, activation) -> int\n\
+retrieve the salience value of specified activation\n\
+returns: salience as integer\n\
+arguments:\n\
+  activation (activation) - the activation to inspect";
+static PyObject *e_getActivationSalience(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_ActivationObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_ActivationType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_ACTIVATION(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    i = EnvGetActivationSalience(env, clips_defrule_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getAgendaChanged */
+E_STATUS_FUNC_GET_BOOL(env_getAgendaChanged,
+                       e_getAgendaChanged,
+                       EnvGetAgendaChanged)
+
+/* env_getFocus */
+static char e_getFocus__doc__[] = "\
+env_getFocus(env) -> defmodule\n\
+retrieve the module with associated focus\n\
+returns: the defmodule with focus as a new object";
+static PyObject *e_getFocus(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *p = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_EnvType, &pyenv))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetFocus(env);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    clips_defmodule_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getFocusStack */
+static char e_getFocusStack__doc__[] = "\
+env_getFocusStack(env) -> (MULTIFIELD, list)\n\
+retrieve the module names in the focus stack\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)";
+static PyObject *e_getFocusStack(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_EnvType, &pyenv))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetFocusStack(env, &o);
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getNextActivation */
+static char e_getNextActivation__doc__[] = "\
+env_getNextActivation(env [, activation]) -> activation\n\
+retrieve next activation object in list, first if argument is omitted\n\
+returns: an activation object, None if already at last activation\n\
+arguments:\n\
+  activation (activation) - the activation to start from";
+static PyObject *e_getNextActivation(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_ActivationObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_ActivationType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p)
+        ECHECK_ACTIVATION(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextActivation(env, p ? clips_activation_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) RETURN_NONE();
+    clips_activation_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_activation_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* getSalienceEvaluation */
+E_STATUS_FUNC_GET(env_getSalienceEvaluation,
+                  e_getSalienceEvaluation,
+                  EnvGetSalienceEvaluation,
+                  "i")
+
+/* getStrategy */
+E_FUNC_GET_ONLY(env_getStrategy, e_getStrategy, EnvGetStrategy, "i")
+
+/* env_listFocusStack */
+static char e_listFocusStack__doc__[] = "\
+env_listFocusStack(env, output)\n\
+print current focus stack\n\
+arguments:\n\
+  output (str) - logical name of output stream";
+static PyObject *e_listFocusStack(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *output = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &output))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvListFocusStack(env, output);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* popFocus */
+E_FUNC_VOID_ONLY(env_popFocus, e_popFocus, EnvPopFocus)
+
+/* env_refreshAgenda */
+static char e_refreshAgenda__doc__[] = "\
+env_refreshAgenda(env [, module])\n\
+refresh agenda for specified defmodule\n\
+arguments:\n\
+  module (defmodule) - the defmodule to process, all if omitted";
+static PyObject *e_refreshAgenda(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvRefreshAgenda(env, module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* removeRunFunction */
+UNIMPLEMENT(env_removeRunFunction, e_removeRunFunction)
+
+/* env_reorderAgenda */
+static char e_reorderAgenda__doc__[] = "\
+env_reorderAgenda(env [, module])\n\
+reorder agenda for specified defmodule\n\
+arguments:\n\
+  module (defmodule) - the defmodule to process, all if omitted";
+static PyObject *e_reorderAgenda(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvReorderAgenda(env, module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_run */
+static char e_run__doc__[] = "\
+env_run(env [, limit]) -> fired\n\
+execute rules\n\
+returns: the number of fired rules\n\
+arguments:\n\
+  limit (int) - number of rules to fire, all if omitted";
+static PyObject *e_run(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    long runlimit = -1;
+
+    if(!PyArg_ParseTuple(args, "O!|i", &clips_EnvType, &pyenv, &runlimit))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    runlimit = EnvRun(env, runlimit);
+    RELEASE_MEMORY_ERROR();
+    RETURN_INT(runlimit);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setActivationSalience */
+static char e_setActivationSalience__doc__[] = "\
+env_setActivationSalience(env, activation, salience) -> int\n\
+set the new activation salience\n\
+returns: the old value\n\
+arguments:\n\
+  activation (activation) - an activation object\n\
+  salience (int) - the new activation salience";
+static PyObject *e_setActivationSalience(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_ActivationObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!i",
+                         &clips_EnvType, &pyenv,
+                         &clips_ActivationType, &p, &i))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_ACTIVATION(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    i = EnvSetActivationSalience(env, clips_activation_value(p), i);
+    RELEASE_MEMORY_ERROR();
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setAgendaChanged */
+E_STATUS_FUNC_SET_BOOL(env_setAgendaChanged,
+                       e_setAgendaChanged,
+                       EnvSetAgendaChanged)
+
+/* env_setSalienceEvaluation */
+static char e_setSalienceEvaluation__doc__[] = "\
+env_setSalienceEvaluation(env, mode)\n\
+set the new salience evaluation mode\n\
+arguments:\n\
+  mode (int) - the new evaluation mode";
+static PyObject *e_setSalienceEvaluation(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!i", &clips_EnvType, &pyenv, &i))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(i != WHEN_DEFINED && i != WHEN_ACTIVATED && i != EVERY_CYCLE) {
+        ERROR_VALUE("invalid evaluation mode");
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    EnvSetSalienceEvaluation(env, i);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setStrategy */
+static char e_setStrategy__doc__[] = "\
+env_setStrategy(env, mode)\n\
+set the new strategy\n\
+arguments:\n\
+  strategy (int) - the new strategy";
+static PyObject *e_setStrategy(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!i", &clips_EnvType, &pyenv, &i))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(i != DEPTH_STRATEGY && i != BREADTH_STRATEGY && i != LEX_STRATEGY &&
+       i != MEA_STRATEGY && i != COMPLEXITY_STRATEGY &&
+       i != SIMPLICITY_STRATEGY && i != RANDOM_STRATEGY) {
+        ERROR_VALUE("invalid strategy");
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    EnvSetStrategy(env, i);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.8 [E] - Defglobal Functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *env_defglobalExists(void *env, void *ptr) {
+    void *rv = EnvGetNextDefglobal(env, NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = EnvGetNextDefglobal(env, rv);
+    }
+    return NULL;
+}
+#define EPYDEFGLOBAL_EXISTS(_e, _p) \
+    env_defglobalExists(_e, clips_defglobal_value(_p))
+#define ECHECK_DEFGLOBAL(_e, _p) do { \
+        if(!EPYDEFGLOBAL_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define ECHECK_RM_DEFGLOBAL(_e, _p) do { \
+        if(_p && !EPYDEFGLOBAL_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* API functions with documentation */
+
+/* env_defglobalModule */
+static char e_defglobalModule__doc__[] = "\
+env_defglobalModule(env, defglobal) -> str\n\
+retrieve the module name where specified defglobal is defined\n\
+returns: module name as string\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to inspect";
+static PyObject *e_defglobalModule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefglobalObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvDefglobalModule(env, clips_defglobal_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_findDefglobal */
+static char e_findDefglobal__doc__[] = "\
+env_findDefglobal(env, name) -> defglobal\n\
+return the defglobal object associated with name\n\
+returns: the defglobal as a new object\n\
+arguments:\n\
+  name (str) - the name to look for";
+static PyObject *e_findDefglobal(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DefglobalObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &name))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvFindDefglobal(env, name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_defglobal_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defglobal_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefglobalList */
+static char e_getDefglobalList__doc__[] = "\
+env_getDefglobalList(env [, module]) -> (MULTIFIELD, list)\n\
+retrieve the list of defglobal objects in the specified defmodule\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_getDefglobalList(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDefglobalList(env, &o,
+        module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefglobalName */
+static char e_getDefglobalName__doc__[] = "\
+env_getDefglobalName(env, defglobal) -> str\n\
+retrieve the name of specified defglobal\n\
+returns: name as a string\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to inspect";
+static PyObject *e_getDefglobalName(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefglobalObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGLOBAL(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetDefglobalName(env, clips_defglobal_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefglobalPPForm */
+static char e_getDefglobalPPForm__doc__[] = "\
+env_getDefglobalPPForm(env, defglobal) -> str\n\
+retrieve the pretty-print form of specified defglobal\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to inspect";
+static PyObject *e_getDefglobalPPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefglobalObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGLOBAL(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvGetDefglobalPPForm(env, clips_defglobal_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefglobalValue */
+static char e_getDefglobalValue__doc__[] = "\
+env_getDefglobalValue(env, name) -> (type, value)\n\
+retrieve the value of specified defglobal\n\
+returns: value as a pair (type, value)\n\
+arguments:\n\
+  name (str) - the name of the defglobal";
+static PyObject *e_getDefglobalValue(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &name))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvGetDefglobalValue(env, name, &o)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefglobalValueForm */
+static char e_getDefglobalValueForm__doc__[] = "\
+env_getDefglobalValueForm(env, defglobal) -> str\n\
+retrieve the pretty-print form of specified defglobal\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to inspect";
+static PyObject *e_getDefglobalValueForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefglobalObject *p = NULL;
+    char *buffer = NEW_ARRAY(char, ppbuffer_size);
+    PyObject *rv = NULL;
+
+    if(!buffer) {
+        ERROR_MEMORY("cannot allocate buffer");
+        FAIL();
+    }
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGLOBAL(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDefglobalValueForm(
+        env, buffer, ppbuffer_size-1, clips_defglobal_value(p));
+    RELEASE_MEMORY_ERROR();
+    rv = Py_BuildValue("s", buffer);
+    DELETE(buffer);
+    return rv;
+
+BEGIN_FAIL
+    if(buffer) DELETE(buffer);
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefglobalWatch */
+static char e_getDefglobalWatch__doc__[] = "\
+env_getDefglobalWatch(env, defglobal) -> bool\n\
+tell whether or not the defglobal is being watched\n\
+returns: True if the defglobal is being watched, False otherwise\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to inspect";
+static PyObject *e_getDefglobalWatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefglobalObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGLOBAL(env, p);
+    i = EnvGetDefglobalWatch(env, clips_defglobal_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* getGlobalsChanged */
+E_STATUS_FUNC_GET_BOOL(env_getGlobalsChanged,
+                       e_getGlobalsChanged,
+                       EnvGetGlobalsChanged)
+
+/* env_getNextDefglobal */
+static char e_getNextDefglobal__doc__[] = "\
+env_getNextDefglobal(env [, defglobal]) -> defglobal\n\
+retrieve next defglobal object in list, first if argument is omitted\n\
+returns: a defglobal object, None if already at last defglobal\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to start from";
+static PyObject *e_getNextDefglobal(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefglobalObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p)
+        ECHECK_DEFGLOBAL(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextDefglobal(env, p ? clips_defglobal_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_defglobal_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defglobal_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* getResetGlobals */
+E_STATUS_FUNC_GET_BOOL(env_getResetGlobals,
+                       e_getResetGlobals,
+                       EnvGetResetGlobals)
+
+/* env_isDefglobalDeletable */
+static char e_isDefglobalDeletable__doc__[] = "\
+env_isDefglobalDeletable(env, defglobal) -> bool\n\
+tell whether or not the defglobal is deletable\n\
+returns: True if the defglobal can be deleted, False otherwise\n\
+arguments:\n\
+  defglobal (defglobal) - the defglobal to be inspected";
+static PyObject *e_isDefglobalDeletable(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefglobalObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGLOBAL(env, p);
+    i = EnvIsDefglobalDeletable(env, clips_defglobal_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_listDefglobals */
+static char e_listDefglobals__doc__[] = "\
+env_listDefglobals(env, logicalname [, module])\n\
+list defglobals to output identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_listDefglobals(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!",
+                         &clips_EnvType, &pyenv,
+                         &lname, &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvListDefglobals(env, lname,
+        module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setDefglobalValue */
+static char e_setDefglobalValue__doc__[] = "\
+env_setDefglobalValue(env, name, value)\n\
+set the value of passed in defglobal\n\
+arguments:\n\
+  name (str) - the name of defglobal to change\n\
+  value (pair) - a pair (type, value)";
+static PyObject *e_setDefglobalValue(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!sO", &clips_EnvType, &pyenv, &name, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(!i_py2do_e(env, p, &o)) {
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvSetDefglobalValue(env, name, &o)) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    Py_XDECREF(p);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_setDefglobalWatch */
+static char e_setDefglobalWatch__doc__[] = "\
+env_setDefglobalWatch(env, state, defglobal)\n\
+set the specified defglobal to a particular watch state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defglobal (defglobal) - the defglobal object";
+static PyObject *e_setDefglobalWatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    PyObject *state = NULL;
+    clips_DefglobalObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!OO!",
+                         &clips_EnvType, &pyenv,
+                         &state, &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGLOBAL(env, p);
+    EnvSetDefglobalWatch(env,
+        PyObject_IsTrue(state), clips_defglobal_value(p));
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setGlobalsChanged */
+E_STATUS_FUNC_SET_BOOL(env_setGlobalsChanged,
+                       e_setGlobalsChanged,
+                       EnvSetGlobalsChanged)
+
+/* setResetGlobals */
+E_STATUS_FUNC_SET_BOOL(env_setResetGlobals,
+                       e_setResetGlobals,
+                       EnvSetResetGlobals)
+
+/* env_showDefglobals */
+static char e_showDefglobals__doc__[] = "\
+env_showDefglobals(env, output [, module])\n\
+list defglobals in specified defmodule to logical output\n\
+arguments:\n\
+  output (str) - logical name of stream to output to\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_showDefglobals(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!",
+                         &clips_EnvType, &pyenv,
+                         &s, &clips_DefmoduleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvShowDefglobals(env, s, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_undefglobal */
+static char e_undefglobal__doc__[] = "\
+env_undefglobal(env [, defglobal])\n\
+delete a defglobal object or all defglobal objects\n\
+arguments:\n\
+  defglobal (defglobal) - object to be deleted, all if omitted";
+static PyObject *e_undefglobal(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefglobalObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefglobalType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_RM_DEFGLOBAL(env, p);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvUndefglobal(env, p ? clips_defglobal_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.9 [E] - Deffunction functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *env_deffunctionExists(void *env, void *ptr) {
+    void *rv = EnvGetNextDeffunction(env, NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = EnvGetNextDeffunction(env, rv);
+    }
+    return NULL;
+}
+#define EPYDEFFUNCTION_EXISTS(_e, _p) \
+    env_deffunctionExists(_e, clips_deffunction_value(_p))
+#define ECHECK_DEFFUNCTION(_e, _p) do { \
+        if(!EPYDEFFUNCTION_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define ECHECK_RM_DEFFUNCTION(_e, _p) do { \
+        if(_p && !EPYDEFFUNCTION_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* API functions with documentation */
+
+/* env_deffunctionModule */
+static char e_deffunctionModule__doc__[] = "\
+env_deffunctionModule(env, deffunction) -> str\n\
+retrieve the module name where specified deffunction is defined\n\
+returns: module name as string\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to inspect";
+static PyObject *e_deffunctionModule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffunctionObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFFUNCTION(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvDeffunctionModule(env, clips_deffunction_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_findDeffunction */
+static char e_findDeffunction__doc__[] = "\
+env_findDeffunction(env, name) -> deffunction\n\
+return the deffunction object associated with name\n\
+returns: the deffunction as a new object\n\
+arguments:\n\
+  name (str) - the name to look for";
+static PyObject *e_findDeffunction(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DeffunctionObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &name))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvFindDeffunction(env, name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_deffunction_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deffunction_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDeffunctionList */
+static char e_getDeffunctionList__doc__[] = "\
+env_getDeffunctionList(env [, module]) -> (MULTIFIELD, list)\n\
+retrieve the list of deffunction objects in the specified defmodule\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_getDeffunctionList(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDeffunctionList(env, &o,
+        module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDeffunctionName */
+static char e_getDeffunctionName__doc__[] = "\
+env_getDeffunctionName(env, deffunction) -> str\n\
+retrieve the name of specified deffunction\n\
+returns: name as a string\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to inspect";
+static PyObject *e_getDeffunctionName(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffunctionObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFFUNCTION(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetDeffunctionName(env, clips_deffunction_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDeffunctionPPForm */
+static char e_getDeffunctionPPForm__doc__[] = "\
+env_getDeffunctionPPForm(env, deffunction) -> str\n\
+retrieve the pretty-print form of specified deffunction\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to inspect";
+static PyObject *e_getDeffunctionPPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffunctionObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFFUNCTION(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvGetDeffunctionPPForm(env, clips_deffunction_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDeffunctionWatch */
+static char e_getDeffunctionWatch__doc__[] = "\
+env_getDeffunctionWatch(env, deffunction) -> bool\n\
+tell whether or not the deffunction is being watched\n\
+returns: True if the deffunction is being watched, False otherwise\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to inspect";
+static PyObject *e_getDeffunctionWatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffunctionObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFFUNCTION(env, p);
+    i = EnvGetDeffunctionWatch(env, clips_deffunction_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getNextDeffunction */
+static char e_getNextDeffunction__doc__[] = "\
+env_getNextDeffunction(env [, deffunction]) -> deffunction\n\
+retrieve next deffunction object in list, first if argument is omitted\n\
+returns: a deffunction object, None if already at last deffunction\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to start from";
+static PyObject *e_getNextDeffunction(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffunctionObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p)
+        ECHECK_DEFFUNCTION(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextDeffunction(env, p ? clips_deffunction_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_deffunction_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_deffunction_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_isDeffunctionDeletable */
+static char e_isDeffunctionDeletable__doc__[] = "\
+env_isDeffunctionDeletable(env, deffunction) -> bool\n\
+tell whether or not the deffunction is deletable\n\
+returns: True if the deffunction can be deleted, False otherwise\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to be inspected";
+static PyObject *e_isDeffunctionDeletable(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffunctionObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFFUNCTION(env, p);
+    i = EnvIsDeffunctionDeletable(env, clips_deffunction_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_listDeffunctions */
+static char e_listDeffunctions__doc__[] = "\
+env_listDeffunctions(env, logicalname [, module])\n\
+list deffunctions to output identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_listDeffunctions(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!",
+                         &clips_EnvType, &pyenv,
+                         &lname, &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvListDeffunctions(env, lname,
+        module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setDeffunctionWatch */
+static char e_setDeffunctionWatch__doc__[] = "\
+env_setDeffunctionWatch(env, state, deffunction)\n\
+set the specified deffunction to a particular watch state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  deffunction (deffunction) - the deffunction object";
+static PyObject *e_setDeffunctionWatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    PyObject *state = NULL;
+    clips_DeffunctionObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!OO!",
+                         &clips_EnvType, &pyenv,
+                         &state, &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFFUNCTION(env, p);
+    EnvSetDeffunctionWatch(env,
+        PyObject_IsTrue(state), clips_deffunction_value(p));
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_undeffunction */
+static char e_undeffunction__doc__[] = "\
+env_undeffunction(env [, deffunction])\n\
+delete a deffunction object or all deffunction objects\n\
+arguments:\n\
+  deffunction (deffunction) - the deffunction to delete, all if omitted";
+static PyObject *e_undeffunction(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeffunctionObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DeffunctionType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_RM_DEFFUNCTION(env, p);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvUndeffunction(env, p ? clips_deffunction_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.10 [E] - Defgeneric Functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *env_defgenericExists(void *env, void *ptr) {
+    void *rv = EnvGetNextDefgeneric(env, NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = EnvGetNextDefgeneric(env, rv);
+    }
+    return NULL;
+}
+#define EPYDEFGENERIC_EXISTS(_e, _p) \
+    env_defgenericExists(_e, clips_defgeneric_value(_p))
+#define ECHECK_DEFGENERIC(_e, _p) do { \
+        if(!EPYDEFGENERIC_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define ECHECK_RM_DEFGENERIC(_e, _p) do { \
+        if(_p && !EPYDEFGENERIC_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* API functions with documentation */
+
+/* env_defgenericModule */
+static char e_defgenericModule__doc__[] = "\
+env_defgenericModule(env, defgeneric) -> str\n\
+retrieve the module name where specified defgeneric is defined\n\
+returns: module name as string\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *e_defgenericModule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvDefgenericModule(env, clips_defgeneric_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_findDefgeneric */
+static char e_findDefgeneric__doc__[] = "\
+env_findDefgeneric(env, name) -> defgeneric\n\
+return the defgeneric object associated with name\n\
+returns: the defgeneric as a new object\n\
+arguments:\n\
+  name (str) - the name to look for";
+static PyObject *e_findDefgeneric(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DefgenericObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &name))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvFindDefgeneric(env, name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_defgeneric_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defgeneric_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefgenericList */
+static char e_getDefgenericList__doc__[] = "\
+env_getDefgenericList(env [, module]) -> (MULTIFIELD, list)\n\
+retrieve the list of defgeneric objects in the specified defmodule\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_getDefgenericList(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDefgenericList(env, &o,
+        module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefgenericName */
+static char e_getDefgenericName__doc__[] = "\
+env_getDefgenericName(env, defgeneric) -> str\n\
+retrieve the name of specified defgeneric\n\
+returns: name as a string\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *e_getDefgenericName(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetDefgenericName(env, clips_deffunction_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefgenericPPForm */
+static char e_getDefgenericPPForm__doc__[] = "\
+env_getDefgenericPPForm(env, defgeneric) -> str\n\
+retrieve the pretty-print form of specified defgeneric\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *e_getDefgenericPPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvGetDefgenericPPForm(env, clips_defgeneric_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefgenericWatch */
+static char e_getDefgenericWatch__doc__[] = "\
+env_getDefgenericWatch(env, defgeneric) -> bool\n\
+tell whether or not the defgeneric is being watched\n\
+returns: True if the defgeneric is being watched, False otherwise\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *e_getDefgenericWatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    i = EnvGetDefgenericWatch(env, clips_deffunction_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getNextDefgeneric */
+static char e_getNextDefgeneric__doc__[] = "\
+env_getNextDefgeneric(env [, defgeneric]) -> defgeneric\n\
+retrieve next defgeneric object in list, first if argument is omitted\n\
+returns: a defgeneric object, None if already at last defgeneric\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to start from";
+static PyObject *e_getNextDefgeneric(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p)
+        ECHECK_DEFGENERIC(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextDefgeneric(env, p ? clips_defgeneric_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_defgeneric_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defgeneric_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_isDefgenericDeletable */
+static char e_isDefgenericDeletable__doc__[] = "\
+env_isDefgenericDeletable(env, defgeneric) -> bool\n\
+tell whether or not the defgeneric is deletable\n\
+returns: True if the defgeneric can be deleted, False otherwise\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to be inspected";
+static PyObject *e_isDefgenericDeletable(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    i = IsDefgenericDeletable(clips_defgeneric_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_listDefgenerics */
+static char e_listDefgenerics__doc__[] = "\
+env_listDefgenerics(env, logicalname [, module])\n\
+list defgeneric objects to output identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_listDefgenerics(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!",
+                         &clips_EnvType, &pyenv,
+                         &lname, &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvListDefgenerics(env, lname,
+        module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setDefgenericWatch */
+static char e_setDefgenericWatch__doc__[] = "\
+env_setDefgenericWatch(env, state, defgeneric)\n\
+set the specified defgeneric to a particular watch state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defgeneric (defgeneric) - the defgeneric object";
+static PyObject *e_setDefgenericWatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    PyObject *state = NULL;
+    clips_DefgenericObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!OO!",
+                         &clips_EnvType, &pyenv,
+                         &state, &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSetDefgenericWatch(env,
+        PyObject_IsTrue(state), clips_defgeneric_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_undefgeneric */
+static char e_undefgeneric__doc__[] = "\
+env_undefgeneric(env [, defgeneric])\n\
+delete a defgeneric object or all defgeneric objects\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to delete, all if omitted";
+static PyObject *e_undefgeneric(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_RM_DEFGENERIC(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvUndefgeneric(env, p ? clips_defgeneric_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.11 [E] - Defmethod function */
+
+/* env_getDefmethodDescription */
+static char e_getDefmethodDescription__doc__[] = "\
+env_getDefmethodDescription(env, index, defgeneric) -> str\n\
+describe method parameter restrictions\n\
+returns: the description as a string\n\
+arguments:\n\
+  index (int) - index of method\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *e_getDefmethodDescription(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *buffer = NEW_ARRAY(char, ppbuffer_size);
+    PyObject *rv = NULL;
+    int i = 0;
+    clips_DefgenericObject *p = NULL;
+
+    if(!buffer) {
+        ERROR_MEMORY("cannot allocate buffer");
+        FAIL();
+    }
+    if(!PyArg_ParseTuple(args, "O!iO!",
+                         &clips_EnvType, &pyenv,
+                         &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDefmethodDescription(env, buffer,
+        ppbuffer_size-1, clips_defgeneric_value(p), i);
+    RELEASE_MEMORY_ERROR();
+    rv = Py_BuildValue("s", buffer);
+    DELETE(buffer);
+    return rv;
+
+BEGIN_FAIL
+    if(buffer) DELETE(buffer);
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefmethodList */
+static char e_getDefmethodList__doc__[] = "\
+env_getDefmethodList(env [, defgeneric]) -> (MULTIFIELD, list)\n\
+retrieve the list of defmethods in the specified defgeneric\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  defgeneric (defgeneric) - the defgeneric to inspect, all if omitted";
+static PyObject *e_getDefmethodList(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *g = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_DefgenericType, &g))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(g)
+        ECHECK_DEFGENERIC(env, g);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDefmethodList(env, g ? clips_defgeneric_value(g) : NULL, &o);
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefmethodPPForm */
+static char e_getDefmethodPPForm__doc__[] = "\
+env_getDefmethodPPForm(env, index, defgeneric) -> str\n\
+retrieve the pretty-print form of specified defmethod\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  index (int) - index of method\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *e_getDefmethodPPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!iO!",
+                         &clips_EnvType, &pyenv,
+                         &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvGetDefmethodPPForm(env, clips_defgeneric_value(p), i);
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefmethodWatch */
+static char e_getDefmethodWatch__doc__[] = "\
+env_getDefmethodWatch(env, index, defgeneric) -> bool\n\
+tell whether or not a defgeneric method is being watched\n\
+returns: True if the method is being watched, False otherwise\n\
+arguments:\n\
+  index (int) - index of method\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *e_getDefmethodWatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!iO!",
+                         &clips_EnvType, &pyenv,
+                         &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    i = EnvGetDefmethodWatch(env, clips_defgeneric_value(p), i);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getMethodRestrictions */
+static char e_getMethodRestrictions__doc__[] = "\
+env_getMethodRestrictions(env, index, defgeneric) -> (MULTIFIELD, list)\n\
+retrieve restriction for specified defmethod\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  index (int) - index of method\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *e_getMethodRestrictions(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL;
+    PyObject *q = NULL;
+    int i = 0;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!i|O!",
+                         &clips_EnvType, &pyenv,
+                         &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetMethodRestrictions(env, p ? clips_defgeneric_value(p) : NULL, i, &o);
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_getNextDefmethod */
+static char e_getNextDefmethod__doc__[] = "\
+env_getNextDefmethod(env, index, defgeneric) -> int\n\
+return index of next defmethod in defgeneric object\n\
+returns: an integer value\n\
+arguments:\n\
+  index (int) - index of method, zero for first method\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *e_getNextDefmethod(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!iO!",
+                         &clips_EnvType, &pyenv,
+                         &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i < 0) {
+        ERROR_VALUE("index must be positive or zero");
+        FAIL();
+    }
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    i = EnvGetNextDefmethod(env, p ? clips_defgeneric_value(p) : NULL, i);
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_isDefmethodDeletable */
+static char e_isDefmethodDeletable__doc__[] = "\
+env_isDefmethodDeletable(env, index, defgeneric) -> bool\n\
+tell whether the specified method is deletable or not\n\
+returns: True if the method can be deleted, False otherwise\n\
+arguments:\n\
+  index (int) - index of method, zero for first method\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *e_isDefmethodDeletable(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!iO!",
+                         &clips_EnvType, &pyenv,
+                         &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i < 0) {
+        ERROR_VALUE("index must be positive or zero");
+        FAIL();
+    }
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    i = EnvIsDefmethodDeletable(
+        env, p ? clips_defgeneric_value(p) : NULL, i);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_listDefmethods */
+static char e_listDefmethods__doc__[] = "\
+env_listDefmethods(env, output, defgeneric)\n\
+list the defmethod in the defgeneric object\n\
+arguments:\n\
+  output (str) - logical name of output stream\n\
+  defgeneric (defgeneric) - the defgeneric to inspect";
+static PyObject *e_listDefmethods(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefgenericObject *p = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!",
+                         &clips_EnvType, &pyenv,
+                         &lname, &clips_DefgenericType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvListDefmethods(env, lname, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setDefmethodWatch */
+static char e_setDefmethodWatch__doc__[] = "\
+env_setDefmethodWatch(env, state, index, defgeneric)\n\
+set the specified defgeneric to a particular watch state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defgeneric (defgeneric) - the defgeneric object";
+static PyObject *e_setDefmethodWatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    PyObject *state = NULL;
+    int i = 0;
+    clips_DefgenericObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!OiO!",
+                         &clips_EnvType, &pyenv,
+                         &state, &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFGENERIC(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSetDefmethodWatch(env,
+        PyObject_IsTrue(state), clips_defgeneric_value(p), i);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_undefmethod */
+static char e_undefmethod__doc__[] = "\
+env_undefmethod(env [, index, defgeneric])\n\
+delete a defmethod object or all defmethod objects\n\
+arguments:\n\
+  index (int) - index of defmethod to delete, all if omitted\n\
+  defgeneric (defgeneric) - referred defgeneric, all if omitted";
+static PyObject *e_undefmethod(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    int i = 0;
+    clips_DefgenericObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|iO!",
+                         &clips_EnvType, &pyenv,
+                         &i, &clips_DefgenericType, &p))
+        FAIL();
+    if(i < 0) {
+        ERROR_VALUE("index must be positive or zero");
+        FAIL();
+    }
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(i != 0 && !p) {
+        ERROR_VALUE("both arguments must be omitted or specified");
+        FAIL();
+    }
+    if(p)
+        ECHECK_DEFGENERIC(env, p);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvUndefmethod(env, p ? clips_defgeneric_value(p) : NULL, i)) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.12 [E] - Defclass functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *env_defclassExists(void *env, void *ptr) {
+    void *rv = EnvGetNextDefclass(env, NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = EnvGetNextDefclass(env, rv);
+    }
+    return NULL;
+}
+#define EPYDEFCLASS_EXISTS(_e, _p) \
+    env_defclassExists(_e, clips_defclass_value(_p))
+#define ECHECK_DEFCLASS(_e, _p) do { \
+        if(!EPYDEFCLASS_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define ECHECK_RM_DEFCLASS(_e, _p) do { \
+        if(_p && !EPYDEFCLASS_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* API functions with documentation */
+
+/* env_browseClasses */
+static char e_browseClasses__doc__[] = "\
+env_browseClasses(env, output, defclass)\n\
+print the classes who inherit from specified one in a graph form\n\
+arguments:\n\
+  output (str) - the name of logical output\n\
+  defclass (defclass) - the defclass to inspect";
+static PyObject *e_browseClasses(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *s = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!sO!",
+                         &clips_EnvType, &pyenv,
+                         &s, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvBrowseClasses(env, s, clips_defclass_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_classAbstractP */
+static char e_classAbstractP__doc__[] = "\
+env_classAbstractP(env, defclass) -> bool\n\
+tell if class is abstract or concrete\n\
+returns: True if the class is abstract, False if concrete\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect";
+static PyObject *e_classAbstractP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    i = EnvClassAbstractP(env, clips_defclass_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_classReactiveP */
+static char e_classReactiveP__doc__[] = "\
+env_classReactiveP(env, defclass) -> bool\n\
+tell if class is reactive (matches object patterns) or not\n\
+returns: True if the class is reactive, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect";
+static PyObject *e_classReactiveP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    i = EnvClassReactiveP(env, clips_defclass_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_classSlots */
+static char e_classSlots__doc__[] = "\
+env_classSlots(env, defclass, inherit) -> (MULTIFIELD, list)\n\
+return names of slots of the passed in class\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  inherit (bool) - True to include inherited slots, False otherwise";
+static PyObject *e_classSlots(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!O",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &q))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvClassSlots(env, clips_defclass_value(p), &o, PyObject_IsTrue(q));
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_classSubclasses */
+static char e_classSubclasses__doc__[] = "\
+env_classSubclasses(env, defclass, inherit) -> (MULTIFIELD, list)\n\
+return names of subclasses for the passed in class\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  inherit (bool) - True to include inherited slots, False otherwise";
+static PyObject *e_classSubclasses(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!O",
+                         &clips_EnvType, &pyenv, &clips_DefclassType, &p, &q))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvClassSubclasses(env, clips_defclass_value(p), &o, PyObject_IsTrue(q));
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_classSuperclasses */
+static char e_classSuperclasses__doc__[] = "\
+env_classSuperclasses(env, defclass, inherit) -> (MULTIFIELD, list)\n\
+return names of superclasses for the passed in class\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  inherit (bool) - True to include inherited slots, False otherwise";
+static PyObject *e_classSuperclasses(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!O",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &q))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvClassSuperclasses(env, clips_defclass_value(p), &o, PyObject_IsTrue(q));
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_defclassModule */
+static char e_defclassModule__doc__[] = "\
+env_defclassModule(env, defclass) -> str\n\
+retrieve the name of the module where the provided defclass resides\n\
+returns: a string containing a module name\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect";
+static PyObject *e_defclassModule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *s = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvDefclassModule(env, clips_defclass_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_describeClass */
+static char e_describeClass__doc__[] = "\
+env_describeClass(env, output, defclass)\n\
+print a descriptive summary of class\n\
+arguments:\n\
+  output (str) - logical name of output stream\n\
+  defclass (defclass) - the defclass to inspect";
+static PyObject *e_describeClass(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *lname = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!sO!",
+                         &clips_EnvType, &pyenv,
+                         &lname, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvDescribeClass(env, lname, clips_defclass_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_findDefclass */
+static char e_findDefclass__doc__[] = "\
+env_findDefclass(env, name) -> defclass\n\
+retrieve defclass object corresponding to the specified name\n\
+returns: the defclass as a new object\n\
+arguments:\n\
+  name (str) - the name of the defclass to look for";
+static PyObject *e_findDefclass(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &name))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvFindDefclass(env, name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_defclass_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defclass_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* getClassDefaultsMode */
+E_FUNC_GET_ONLY(env_getClassDefaultsMode,
+                e_getClassDefaultsMode,
+                EnvGetClassDefaultsMode,
+                "i")
+
+/* env_getDefclassList */
+static char e_getDefclassList__doc__[] = "\
+env_getDefclassList(env [, module]) -> (MULTIFIELD, list)\n\
+retrieve list of defclass objects names in specified defmodule\n\
+returns:  MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_getDefclassList(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDefclassList(env, &o,
+        module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefclassName */
+static char e_getDefclassName__doc__[] = "\
+env_getDefclassName(env, defclass) -> str\n\
+retrieve the name of given defclass object\n\
+returns: a string containing the name\n\
+arguments:\n\
+  defclass (defclass) - the defclass object";
+static PyObject *e_getDefclassName(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetDefclassName(env, clips_defclass_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefclassPPForm */
+static char e_getDefclassPPForm__doc__[] = "\
+env_getDefclassPPForm(env, defclass) -> str\n\
+retrieve the pretty-print form of given defclass object\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defclass (defclass) - the defclass object";
+static PyObject *e_getDefclassPPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *s = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvGetDefclassPPForm(env, clips_defclass_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefclassWatchInstances */
+static char e_getDefclassWatchInstances__doc__[] = "\
+env_getDefclassWatchInstances(env, defclass) -> bool\n\
+tell if defclass instances are being watched\n\
+returns: True if defclass instances are being watched, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass object";
+static PyObject *e_getDefclassWatchInstances(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    i = EnvGetDefclassWatchInstances(env, clips_defclass_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefclassWatchSlots */
+static char e_getDefclassWatchSlots__doc__[] = "\
+env_getDefclassWatchSlots(env, defclass) -> bool\n\
+tell if defclass slots are being watched\n\
+returns: True if defclass slots are being watched, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass object";
+static PyObject *e_getDefclassWatchSlots(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    i = EnvGetDefclassWatchSlots(env, clips_defclass_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getNextDefclass */
+static char e_getNextDefclass__doc__[] = "\
+env_getNextDefclass(env [, defclass]) -> defclass\n\
+find next defclass in the list, first if argument is omitted\n\
+returns: next defclass object, None if already at last defclass\n\
+arguments:\n\
+  defclass (defclass) - the defclass to start from";
+static PyObject *e_getNextDefclass(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p)
+        ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextDefclass(env, p ? clips_defclass_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_defclass_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defclass_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_isDefclassDeletable */
+static char e_isDefclassDeletable__doc__[] = "\
+env_isDefclassDeletable(env, defclass) -> bool\n\
+tell whether or not the defclass can be deleted\n\
+returns: True if the defclass can be deleted, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass object";
+static PyObject *e_isDefclassDeletable(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    i = EnvIsDefclassDeletable(env, clips_defclass_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_listDefclasses */
+static char e_listDefclasses__doc__[] = "\
+env_listDefclasses(env, logicalname [, module])\n\
+list defclasses to output identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_listDefclasses(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!",
+                         &clips_EnvType, &pyenv,
+                         &lname, &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvListDefclasses(env, lname,
+        module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setClassDefaultsMode */
+static char e_setClassDefaultsMode__doc__[] = "\
+env_setClassDefaultsMode(env, mode)\n\
+set default mode for classes\n\
+arguments:\n\
+  mode (int) - the new default mode";
+static PyObject *e_setClassDefaultsMode(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    int i = 0;
+    void *env = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!i", &clips_EnvType, &pyenv, &i))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(i != CONVENIENCE_MODE && i != CONSERVATION_MODE) {
+        ERROR_VALUE("invalid mode value");
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    EnvSetClassDefaultsMode(env, (unsigned short)i);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setDefclassWatchInstances */
+static char e_setDefclassWatchInstances__doc__[] = "\
+env_setDefclassWatchInstances(env, state, defclass)\n\
+tell to system if defclass instances are to be watched\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defclass (defclass) - the defclass object";
+static PyObject *e_setDefclassWatchInstances(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *state = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!OO!",
+                         &clips_EnvType, &pyenv,
+                         &state, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSetDefclassWatchInstances(env,
+        PyObject_IsTrue(state), clips_defclass_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setDefclassWatchSlots */
+static char e_setDefclassWatchSlots__doc__[] = "\
+env_setDefclassWatchSlots(env, state, defclass)\n\
+tell to system if defclass slots are to be watched\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defclass (defclass) - the defclass object";
+static PyObject *e_setDefclassWatchSlots(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *state = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!OO!",
+                         &clips_EnvType, &pyenv,
+                         &state, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSetDefclassWatchSlots(env,
+        PyObject_IsTrue(state), clips_defclass_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_slotAllowedValues */
+static char e_slotAllowedValues__doc__[] = "\
+env_slotAllowedValues(env, defclass, name) -> (MULTIFIELD, list)\n\
+retrieve allowed values for specified slot\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *e_slotAllowedValues(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSlotAllowedValues(env, clips_defclass_value(p), s, &o);
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_slotCardinality */
+static char e_slotCardinality__doc__[] = "\
+env_slotCardinality(env, defclass, name) -> (MULTIFIELD, list)\n\
+retrieve cardinality information for specified slot\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *e_slotCardinality(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSlotCardinality(env, clips_defclass_value(p), s, &o);
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+#if CLIPS_MINOR > 23
+
+/* slotAllowedClasses */
+static char e_slotAllowedClasses__doc__[] = "\
+env_slotAllowedClasses(env, defclass, name) -> (MULTIFIELD, list)\n\
+retrieve the allowed classes for a slot of given class\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *e_slotAllowedClasses(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &name))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSlotAllowedClasses(env, clips_defclass_value(p), name, &o);
+    rv = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* slotDefaultValue */
+static char e_slotDefaultValue__doc__[] = "\
+env_slotDefaultValue(env, defclass, name) -> (MULTIFIELD, list)\n\
+retrieve default value(s) for a slot of given defclass\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - name of the slot to inspect";
+static PyObject *e_slotDefaultValue(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DeftemplObject *p = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+    PyObject *rv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &name))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSlotDefaultValue(env, clips_defclass_value(p), name, &o);
+    rv = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!rv) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(rv);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+#else
+UNIMPLEMENT_VERSION(env_slotAllowedClasses, e_slotAllowedClasses)
+UNIMPLEMENT_VERSION(env_slotDefaultValue, e_slotDefaultValue)
+#endif /* CLIPS_MINOR > 23 */
+
+/* env_slotDirectAccessP */
+static char e_slotDirectAccessP__doc__[] = "\
+env_slotDirectAccessP(env, defclass, name) -> bool\n\
+tell if slot is directly accessible\n\
+returns: True if slot is directly accessible, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *e_slotDirectAccessP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    i = EnvSlotDirectAccessP(env, clips_defclass_value(p), s);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_slotExistP */
+static char e_slotExistP__doc__[] = "\
+env_slotExistP(env, defclass, name, inherit) -> bool\n\
+tell if slot exists\n\
+returns: True if slot exists, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *e_slotExistP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!sO",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &s, &q))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    i = EnvSlotExistP(env, clips_defclass_value(p), s, PyObject_IsTrue(q));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_slotFacets */
+static char e_slotFacets__doc__[] = "\
+env_slotFacets(env, defclass, name) -> (MULTIFIELD, list)\n\
+retrieve facet values information for specified slot\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *e_slotFacets(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSlotFacets(env, clips_defclass_value(p), s, &o);
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_slotInitableP */
+static char e_slotInitableP__doc__[] = "\
+env_slotInitableP(env, defclass, name) -> bool\n\
+tell if slot is initializable\n\
+returns: True if slot can be initialized, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *e_slotInitableP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    i = EnvSlotInitableP(env, clips_defclass_value(p), s);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_slotPublicP */
+static char e_slotPublicP__doc__[] = "\
+env_slotPublicP(env, defclass, name) -> bool\n\
+tell if slot is public\n\
+returns: True if slot is public, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *e_slotPublicP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv, &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    i = EnvSlotPublicP(env, clips_defclass_value(p), s);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_slotRange */
+static char e_slotRange__doc__[] = "\
+env_slotRange(env, defclass, name) -> (MULTIFIELD, list)\n\
+retrieve numeric range information for specified slot\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *e_slotRange(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSlotRange(env, clips_defclass_value(p), s, &o);
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_slotSources */
+static char e_slotSources__doc__[] = "\
+env_slotSources(env, defclass, name) -> (MULTIFIELD, list)\n\
+retrieve the name of class sources for specified slot\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *e_slotSources(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSlotSources(env, clips_defclass_value(p), s, &o);
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_slotTypes */
+static char e_slotTypes__doc__[] = "\
+env_slotTypes(env, defclass, name) -> (MULTIFIELD, list)\n\
+retrieve cardinality information for specified slot\n\
+returns: MULTIFIELD and a list of pairs (type, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *e_slotTypes(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *q = NULL;
+    char *s = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSlotTypes(env, clips_defclass_value(p), s, &o);
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_slotWritableP */
+static char e_slotWritableP__doc__[] = "\
+env_slotWritableP(env, defclass, name) -> bool\n\
+tell whether slot can be overwritten or not\n\
+returns: True if slot is writeable, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  name (str) - the slot name";
+static PyObject *e_slotWritableP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    char *s = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &s))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    i = EnvSlotWritableP(env, clips_defclass_value(p), s);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_subclassP */
+static char e_subclassP__doc__[] = "\
+env_subclassP(env, defclass1, defclass2) -> bool\n\
+tell if defclass1 is a subclass of defclass2\n\
+returns: True if relationship is satisfied, False otherwise\n\
+arguments:\n\
+  defclass1, defclass2 (defclass) - test objects";
+static PyObject *e_subclassP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL, *q = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &clips_DefclassType, &q))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ECHECK_DEFCLASS(env, q);
+    i = EnvSubclassP(env, clips_defclass_value(p), clips_defclass_value(q));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_superclassP */
+static char e_superclassP__doc__[] = "\
+env_superclassP(env, defclass1, defclass2) -> bool\n\
+tell if defclass1 is a superclass of defclass2\n\
+returns: True if relationship is satisfied, False otherwise\n\
+arguments:\n\
+  defclass1, defclass2 (defclass) - test objects";
+static PyObject *e_superclassP(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL, *q = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &clips_DefclassType, &q))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ECHECK_DEFCLASS(env, q);
+    i = EnvSuperclassP(env, clips_defclass_value(p), clips_defclass_value(q));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_undefclass */
+static char e_undefclass__doc__[] = "\
+env_undefclass(env, defclass)\n\
+remove a class and all its subclasses from system\n\
+arguments:\n\
+  defclass (defclass) - the defclass to remove";
+static PyObject *e_undefclass(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefclassType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_RM_DEFCLASS(env, p);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvUndefclass(env, clips_defclass_value(p))) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.13 [E] - Instance functions */
+
+/* env_binaryLoadInstances */
+static char e_binaryLoadInstances__doc__[] = "\
+env_binaryLoadInstances(env, filename) -> numinstances\n\
+binary load a set of instances from named file\n\
+returns: the number of loaded instances\n\
+arguments:\n\
+  filename (str) - the name of binary file to load from";
+static PyObject *e_binaryLoadInstances(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *fn = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &fn))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    i = EnvBinaryLoadInstances(env, fn);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    else RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_binarySaveInstances */
+static char e_binarySaveInstances__doc__[] = "\
+env_binarySaveInstances(env, filename, scope) -> int\n\
+dump instances to file\n\
+returns: the number of saved instances\n\
+arguments:\n\
+  filename (str) - the name of binary file to save to\n\
+  scope (int) - one of LOCAL_SAVE or VISIBLE_SAVE";
+static PyObject *e_binarySaveInstances(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *fn = NULL;
+    long i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!si", &clips_EnvType, &pyenv, &fn, &i))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(i != LOCAL_SAVE && i != VISIBLE_SAVE) {
+        ERROR_VALUE("invalid scope");
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    i = EnvBinarySaveInstances(env, fn, i, NULL, TRUE);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_IO();
+        FAIL();
+    } /* do not know */
+    else RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_createRawInstance */
+static char e_createRawInstance__doc__[] = "\
+env_createRawInstance(env, defclass, name) -> instance\n\
+create an instance of specified class with given name\n\
+returns: the instance as a new object\n\
+arguments:\n\
+  defclass (defclass) - the defclass to create an instance of\n\
+  name (str) - the name of the instance";
+static PyObject *e_createRawInstance(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    clips_InstanceObject *q = NULL;
+    void *ptr = 0;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &name))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvCreateRawInstance(env, clips_defclass_value(p), name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_CREATION();
+        FAIL();
+    }
+    clips_instance_New(env, q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_instance_assign(q, ptr);
+    ENV_CHECK_VALID_INSTANCE(env, q);
+    clips_instance_lock(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_decrementInstanceCount */
+UNIMPLEMENT(env_decrementInstanceCount, e_decrementInstanceCount)
+
+/* env_deleteInstance */
+static char e_deleteInstance__doc__[] = "\
+env_deleteInstance(env [, instance])\n\
+delete specified instance\n\
+arguments:\n\
+  instance (instance) - the instance to delete, all if omitted";
+static PyObject *e_deleteInstance(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_InstanceObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_InstanceType, &p))
+        FAIL();
+    if(p)
+        ENV_CHECK_VALID_INSTANCE(env, p);
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvDeleteInstance(env, p ? clips_instance_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_directGetSlot */
+static char e_directGetSlot__doc__[] = "\
+env_directGetSlot(env, instance, slotname) -> (type, value)\n\
+get value in specified slot of given instance\n\
+returns: a pair (type, value)\n\
+arguments:\n\
+  instance (instance) - the instance to inspect\n\
+  slotname (str) - the slot to retrieve";
+static PyObject *e_directGetSlot(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_InstanceObject *p = NULL;
+    PyObject *q = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!s",
+                         &clips_EnvType, &pyenv,
+                         &clips_InstanceType, &p, &name))
+        FAIL();
+    ENV_CHECK_VALID_INSTANCE(env, p);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvDirectGetSlot(env, clips_instance_value(p), name, &o);
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_directPutSlot */
+static char e_directPutSlot__doc__[] = "\
+env_directPutSlot(env, instance, slotname, (type, value))\n\
+put a value in specified slot of given instance\n\
+arguments:\n\
+  instance (instance) - the instance to inspect\n\
+  slotname (str) - the slot to retrieve\n\
+  type (int) - the type of value to assign\n\
+  value (object or list of pairs) - the value to assign";
+static PyObject *e_directPutSlot(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_InstanceObject *p = NULL;
+    PyObject *q = NULL;
+    char *name = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!sO",
+                         &clips_EnvType, &pyenv,
+                         &clips_InstanceType, &p, &name, &q))
+        FAIL();
+    ENV_CHECK_VALID_INSTANCE(env, p);
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(!i_py2do_e(env, q, &o)) {
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvDirectPutSlot(env, clips_instance_value(p), name, &o)) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_OTHER("instance slot could not be modified");
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_findInstance */
+static char e_findInstance__doc__[] = "\
+env_findInstance(env, name, srchimports [, module]) -> instance\n\
+find the instance with the specified name\n\
+returns: the instance as a new object\n\
+arguments:\n\
+  name (str) - instance name\n\
+  srchimports (bool) - True if imported modules have to be inspected\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_findInstance(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    clips_InstanceObject *q = NULL;
+    char *name = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!sO|O!",
+                         &clips_EnvType, &pyenv,
+                         &name, &p, &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvFindInstance(env,
+        module ? clips_defmodule_value(module) : NULL, name,
+        PyObject_IsTrue(p));
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_instance_New(env, q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_instance_assign(q, ptr);
+    ENV_CHECK_VALID_INSTANCE(env, q);
+    clips_instance_lock(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_getInstanceClass */
+static char e_getInstanceClass__doc__[] = "\
+env_getInstanceClass(env, instance) -> defclass\n\
+retrieve the class of specified instance\n\
+returns: the instance defclass as a new object\n\
+arguments:\n\
+  instance (instance) - the instance to inspect";
+static PyObject *e_getInstanceClass(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_InstanceObject *p = NULL;
+    clips_DefclassObject *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_InstanceType, &p))
+        FAIL();
+    ENV_CHECK_VALID_INSTANCE(env, p);
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetInstanceClass(env, clips_instance_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    clips_defclass_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defclass_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_getInstanceName */
+static char e_getInstanceName__doc__[] = "\
+env_getInstanceName(env, instance) -> str\n\
+retrieve the name of specified instance\n\
+returns: the requested name of instance\n\
+arguments:\n\
+  instance (instance) - the instance to inspect";
+static PyObject *e_getInstanceName(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_InstanceObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_InstanceType, &p))
+        FAIL();
+    ENV_CHECK_VALID_INSTANCE(env, p);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetInstanceName(env, clips_instance_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getInstancePPForm */
+static char e_getInstancePPForm__doc__[] = "\
+env_getInstancePPForm(env, instance) -> str\n\
+retrieve the pretty-print form of specified instance\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  instance (instance) - the instance to inspect";
+static PyObject *e_getInstancePPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_InstanceObject *p = NULL;
+    char *buffer = NEW_ARRAY(char, ppbuffer_size);
+    PyObject *rv = NULL;
+
+    if(!buffer) {
+        ERROR_MEMORY("cannot allocate buffer");
+        FAIL();
+    }
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_InstanceType, &p))
+        FAIL();
+    ENV_CHECK_VALID_INSTANCE(env, p);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetInstancePPForm(env, buffer,
+        ppbuffer_size-1, clips_instance_value(p));
+    RELEASE_MEMORY_ERROR();
+    rv = Py_BuildValue("s", buffer);
+    DELETE(buffer);
+    return rv;
+
+BEGIN_FAIL
+    if(buffer) DELETE(buffer);
+    SKIP();
+END_FAIL
+}
+
+/* getInstancesChanged */
+E_STATUS_FUNC_GET_BOOL(env_getInstancesChanged,
+                       e_getInstancesChanged,
+                       EnvGetInstancesChanged)
+
+/* env_getNextInstance */
+static char e_getNextInstance__doc__[] = "\
+env_getNextInstance(env [, instance]) -> instance\n\
+retrieve next instance object in list, first if argument is omitted\n\
+returns: a instance object, None if already at last instance\n\
+arguments:\n\
+  instance (defrule) - the instance to start from";
+static PyObject *e_getNextInstance(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_InstanceObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_InstanceType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    if(p)
+        ENV_CHECK_VALID_INSTANCE(env, p);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextInstance(env, p ? clips_instance_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_instance_New(env, q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_instance_assign(q, ptr);
+    ENV_CHECK_VALID_INSTANCE(env, q);
+    clips_instance_lock(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_getNextInstanceInClass */
+static char e_getNextInstanceInClass__doc__[] = "\
+env_getNextInstanceInClass(env, defclass [, instance]) -> instance\n\
+retrieve next instance object in class, first if argument is omitted\n\
+returns: a instance object, None if already at last instance\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  instance (instance) - the instance to start from";
+static PyObject *e_getNextInstanceInClass(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_InstanceObject *p = NULL, *q = NULL;
+    clips_DefclassObject *c = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!|O!",
+        &clips_EnvType, &pyenv, &clips_DefclassType, &c,
+        &clips_InstanceType, &p)) FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    if(p) { ENV_CHECK_VALID_INSTANCE(env, p); }
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, c);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextInstanceInClass(env,
+        clips_defclass_value(c), p ? clips_instance_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_instance_New(env, q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_instance_assign(q, ptr);
+    ENV_CHECK_VALID_INSTANCE(env, q);
+    clips_instance_lock(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* getNextInstanceInClassAndSubclasses */
+static char e_getNextInstanceInClassAndSubclasses__doc__[] = "\
+getNextInstanceInClassAndSubclasses(env, defclass [, instance]) -> instance\n\
+retrieve next instance in class/subclasses, first if argument is omitted\n\
+returns: a instance object, None if already at last instance\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  instance (instance) - the instance to start from";
+static PyObject *e_getNextInstanceInClassAndSubclasses(PyObject *self, PyObject *args) {
+    clips_InstanceObject *p = NULL, *q = NULL;
+    clips_DefclassObject *c = NULL;
+    DATA_OBJECT o = { 0 };
+    void *ptr = NULL;
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &c, &clips_InstanceType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    if(p)
+        ENV_CHECK_VALID_INSTANCE(env, p);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, c);
+    /* we should iterate from the start in order to keep the iteration data */
+    ACQUIRE_MEMORY_ERROR();
+    if(p) {
+        ptr = EnvGetNextInstanceInClassAndSubclasses_PY(env,
+            clips_defclass_value(c), NULL, &o);
+        /* move cursor to the instance we passed in */
+        while(ptr && ptr != clips_instance_value(p))
+            ptr = EnvGetNextInstanceInClassAndSubclasses_PY(env,
+                clips_defclass_value(c), ptr, &o);
+        /* move cursor one step forward if conditions met (may return NULL) */
+        if(ptr)
+            ptr = EnvGetNextInstanceInClassAndSubclasses_PY(env,
+                clips_defclass_value(c), ptr, &o);
+    } else
+        ptr = EnvGetNextInstanceInClassAndSubclasses_PY(env,
+            clips_defclass_value(c), NULL, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_instance_New(env, q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_instance_assign(q, ptr);
+    ENV_CHECK_VALID_INSTANCE(env, q);
+    clips_instance_lock(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_incrementInstanceCount */
+UNIMPLEMENT(env_incrementInstanceCount, e_incrementInstanceCount)
+
+/* env_instances */
+static char e_instances__doc__[] = "\
+env_instances(env, output [, module] [, class [, subclassflag]]])\n\
+list instances in specified defmodule to logical output\n\
+arguments:\n\
+  output (str) - the name of logical output stream\n\
+  module (defmodule) - the defmodule to inspect, all if omitted\n\
+  class (str) - the class name to inspect, all if omitted\n\
+  subclassflag (bool) - True if all subclasses must be recursed";
+static PyObject *e_instances(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = Py_None;
+    char *name = NULL, *output = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!sO",
+                         &clips_EnvType, &pyenv, &output,
+                         &clips_DefmoduleType, &module, &name, &p)) {
+        PyErr_Clear();
+        module = NULL;
+        if(!PyArg_ParseTuple(args, "O!s|sO",
+                             &clips_EnvType, &pyenv, &output, &name, &p)) {
+            PyErr_Clear();
+            ERROR_TYPE("invalid argument(s) or invalid argument order");
+            FAIL();
+        }
+    }
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvInstances(env, output,
+        module ? clips_defmodule_value(module) : NULL,
+        name, p ? PyObject_IsTrue(p) : FALSE);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_loadInstances */
+static char e_loadInstances__doc__[] = "\
+env_loadInstances(env, filename) -> int\n\
+load instance from specified file\n\
+returns: the number of loaded instances\n\
+arguments:\n\
+  filename (str) - the name of file to load instances from";
+static PyObject *e_loadInstances(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *fn = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &fn))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    i = EnvLoadInstances(env, fn);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_makeInstance */
+static char e_makeInstance__doc__[] = "\
+env_makeInstance(env, command) -> instance\n\
+create and initialize an instance using given command\n\
+returns: a new instance\n\
+arguments:\n\
+  command (str) - command used to create instance";
+static PyObject *e_makeInstance(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_InstanceObject *q = NULL;
+    char *s = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &s))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvMakeInstance(env, s);
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    if(!ptr) {
+        ERROR_CLIPS_CREATION();
+        FAIL();
+    }
+    clips_instance_New(env, q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_instance_assign(q, ptr);
+    ENV_CHECK_VALID_INSTANCE(env, q);
+    clips_instance_lock(q);
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_restoreInstances */
+static char e_restoreInstances__doc__[] = "\
+env_restoreInstances(env, filename) -> numinstances\n\
+restore instance from specified file\n\
+returns: number of restored instances\n\
+arguments:\n\
+  filename (str) - the name of file to restore instances from";
+static PyObject *e_restoreInstances(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *fn = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &fn))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    i = EnvRestoreInstances(env, fn);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_IO();
+        FAIL();
+    }
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_saveInstances */
+static char e_saveInstances__doc__[] = "\
+env_saveInstances(env, filename, scope)\n\
+save instances to specified file\n\
+returns: the number of saved instances\n\
+arguments:\n\
+  filename (str) - the name of file to save instances to\n\
+  scope (int) - one of LOCAL_SAVE or VISIBLE_SAVE";
+static PyObject *e_saveInstances(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *fn = NULL;
+    long i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!si", &clips_EnvType, &pyenv, &fn, &i))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(i != LOCAL_SAVE && i != VISIBLE_SAVE) {
+        ERROR_VALUE("invalid scope");
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    i = EnvSaveInstances(env, fn, i, NULL, TRUE);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_IO();
+        FAIL();
+    } /* do not know */
+    else RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_send */
+static char e_send__doc__[] = "\
+env_send(env, instance, type, message [, arguments])\n\
+send a message to specified object\n\
+returns: the result value for the operation if any\n\
+arguments:\n\
+  instance (instance) - instance to send message to\n\
+  message (str) - message to send\n\
+  arguments (str) - blank separated constant arguments";
+static PyObject *e_send(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    PyObject *p = NULL, *q = NULL;
+    char *msg = NULL, *msa = NULL;
+    DATA_OBJECT o = { 0 }, rv = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!O!s|s",
+                         &clips_EnvType, &pyenv,
+                         &clips_InstanceType, &p, &msg, &msa))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CHECK_VALID_INSTANCE(env, p);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    SetType(o, INSTANCE_ADDRESS);
+    SetValue(o, clips_instance_value(p));
+    EnvSend(env, &o, msg, msa, &rv);
+    q = i_do2py(&rv);
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    if(q) {
+        RETURN_PYOBJECT(q);
+    } else RETURN_NONE();
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* setInstancesChanged */
+E_STATUS_FUNC_SET_BOOL(env_setInstancesChanged,
+                       e_setInstancesChanged,
+                       EnvSetInstancesChanged)
+
+/* env_unmakeInstance */
+static char e_unmakeInstance__doc__[] = "\
+env_unmakeInstance(env [, instance])\n\
+delete specified instance (passing a message)\n\
+arguments:\n\
+  instance (instance) - instance to delete, all if omitted";
+static PyObject *e_unmakeInstance(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_InstanceObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_InstanceType, &p))
+        FAIL();
+    if(p)
+        ENV_CHECK_VALID_INSTANCE(env, p);
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvUnmakeInstance(env, p ? clips_instance_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_validInstanceAddress */
+static char e_validInstanceAddress__doc__[] = "\
+env_validInstanceAddress(env, instance) -> bool\n\
+tell whether the instance still exists or not\n\
+returns: True if instance exists, False otherwise\n\
+arguments:\n\
+  instance (instance) - istance to test";
+static PyObject *e_validInstanceAddress(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_InstanceObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_InstanceType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    i = EnvValidInstanceAddress(env, clips_instance_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_loadInstancesFromString */
+static char e_loadInstancesFromString__doc__[] = "\
+env_loadInstancesFromString(env, string [, maxpos]) -> int\n\
+load instances from a string\n\
+returns: the number of loaded instances\n\
+arguments:\n\
+  string (str) - string to read from\n\
+  maxpos (int) - last char to read, all string if omitted";
+static PyObject *e_loadInstancesFromString(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *s = NULL;
+    int i = -1;
+
+    if(!PyArg_ParseTuple(args, "O!s|i", &clips_EnvType, &pyenv, &s, &i))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    i = EnvLoadInstancesFromString(env, s, i);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_restoreInstancesFromString */
+static char e_restoreInstancesFromString__doc__[] = "\
+env_restoreInstancesFromString(env, string [, maxpos]) -> int\n\
+restore instances from a string\n\
+returns: number of restored instances\n\
+arguments:\n\
+  string (str) - string to read from\n\
+  maxpos (int) - last char to read, all string if omitted";
+static PyObject *e_restoreInstancesFromString(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *s = NULL;
+    int i = -1;
+
+    if(!PyArg_ParseTuple(args, "O!s|i", &clips_EnvType, &pyenv, &s, &i))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    i = EnvRestoreInstancesFromString(env, s, i);
+    RELEASE_MEMORY_ERROR();
+    if(i < 0) {
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.14 [E] - DefmessageHandler functions */
+
+/* env_findDefmessageHandler */
+static char e_findDefmessageHandler__doc__[] = "\
+env_findDefmessageHandler(env, defclass, name, type) -> int\n\
+find the matching message handler attached to defclass\n\
+returns: index of message handler\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect object\n\
+  name (str) - message handler name\n\
+  type (str) - one of 'around', 'before', 'primary', 'after'";
+static PyObject *e_findDefmessageHandler(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    char *name = NULL, *type = NULL;
+    unsigned int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!ss",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &name, &type))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    i = EnvFindDefmessageHandler(env, clips_defclass_value(p), name, type);
+    RELEASE_MEMORY_ERROR();
+    if(i == 0) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefmessageHandlerList */
+static char e_getDefmessageHandlerList__doc__[] = "\
+env_getDefmessageHandlerList(env, [defclass [, inh]]) -> (MULTIFIELD, list)\n\
+retrieve list of message handlers attached to defclass\n\
+returns: MULTIFIELD and a list of pairs (STRING, value)\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect, all if omitted\n\
+  inh (bool) - True if inherited handlers are to list";
+static PyObject *e_getDefmessageHandlerList(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *p1 = NULL, *q = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!|O!O",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &p1))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p) { ECHECK_DEFCLASS(env, p); }
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDefmessageHandlerList(env,
+        p ? clips_defclass_value(p) : NULL,
+        &o, p1 ? PyObject_IsTrue(p1) : FALSE);
+    q = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!q) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_getDefmessageHandlerName */
+static char e_getDefmessageHandlerName__doc__[] = "\
+env_getDefmessageHandlerName(env, defclass, index) -> str\n\
+retrieve the name of specified message handler\n\
+returns: name as string\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *e_getDefmessageHandlerName(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    char *name = NULL;
+    unsigned int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!i",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetDefmessageHandlerName(env, clips_defclass_value(p), i);
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefmessageHandlerPPForm */
+static char e_getDefmessageHandlerPPForm__doc__[] = "\
+env_getDefmessageHandlerPPForm(env, defclass, index) -> str\n\
+retrieve the pretty-print form of specified message handler\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *e_getDefmessageHandlerPPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    char *s = NULL;
+    unsigned int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!i",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvGetDefmessageHandlerPPForm(env, clips_defclass_value(p), i);
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefmessageHandlerType */
+static char e_getDefmessageHandlerType__doc__[] = "\
+env_getDefmessageHandlerType(env, defclass, index) -> str\n\
+retrieve type of specified message handler\n\
+returns: type as string\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *e_getDefmessageHandlerType(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    char *s = NULL;
+    unsigned int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!i",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvGetDefmessageHandlerType(env, clips_defclass_value(p), i);
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefmessageHandlerWatch */
+static char e_getDefmessageHandlerWatch__doc__[] = "\
+env_getDefmessageHandlerWatch(env, defclass, index) -> bool\n\
+tell if specified message handler is being watched\n\
+returns: True if the message handler is being watched, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *e_getDefmessageHandlerWatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!i",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    i = EnvGetDefmessageHandlerWatch(
+        env, clips_defclass_value(p), (unsigned int)i);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getNextDefmessageHandler */
+static char e_getNextDefmessageHandler__doc__[] = "\
+env_getNextDefmessageHandler(env, defclass [, index]) -> int\n\
+return index of next message handler for specified class\n\
+returns: index as an integer, None if already at last handler\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of current handler, 0 or omitted for first";
+static PyObject *e_getNextDefmessageHandler(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!|i",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i < 0) {
+        ERROR_VALUE("index must be positive or zero");
+        FAIL();
+    }
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    i = EnvGetNextDefmessageHandler(env, clips_defclass_value(p), i);
+    RELEASE_MEMORY_ERROR();
+    if(i == 0)
+        RETURN_NONE();
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_isDefmessageHandlerDeletable */
+static char e_isDefmessageHandlerDeletable__doc__[] = "\
+env_isDefmessageHandlerDeletable(env, defclass, index) -> bool\n\
+tell whether or not the specified message handler can be deleted\n\
+returns: True if the message handler can be deleted, False otherwise\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *e_isDefmessageHandlerDeletable(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!i",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    i = EnvIsDefmessageHandlerDeletable(
+        env, clips_defclass_value(p), (unsigned int)i);
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_listDefmessageHandlers */
+static char e_listDefmessageHandlers__doc__[] = "\
+env_listDefmessageHandlers(env, output, [, defclass [, inhflag]])\n\
+list message handlers to logical output\n\
+arguments:\n\
+  output (str) - the name of output stream\n\
+  defclass (defclass) - the defclass to inspect\n\
+  inhflag (bool) - True to list inherited handlers";
+static PyObject *e_listDefmessageHandlers(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    PyObject *p1 = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!O",
+                         &clips_EnvType, &pyenv,
+                         &s, &clips_DefclassType, &p, &p1))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p)
+        ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvListDefmessageHandlers(env, s,
+        p ? clips_defclass_value(p) : NULL, p1 ? PyObject_IsTrue(p1) : FALSE);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_previewSend */
+static char e_previewSend__doc__[] = "\
+env_previewSend(env, output, defclass, messagename)\n\
+list message handlers applicable to instances to logical output\n\
+arguments:\n\
+  output (str) - logical output stream name\n\
+  defclass (defclass) - the defclass to inspect\n\
+  messagename (str) - the name of message";
+static PyObject *e_previewSend(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    char *s = NULL, *m = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!sO!s",
+                         &clips_EnvType, &pyenv, &s,
+                         &clips_DefclassType, &p, &m))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvPreviewSend(env, s, clips_defclass_value(p), m);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setDefmessageHandlerWatch */
+static char e_setDefmessageHandlerWatch__doc__[] = "\
+env_setDefmessageHandlerWatch(env, state, defclass, index)\n\
+set watch on message handler to specified state\n\
+arguments:\n\
+  state (bool) - the new watch state\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *e_setDefmessageHandlerWatch(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    int i = 0;
+    PyObject *state = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!OO!i",
+                         &clips_EnvType, &pyenv,
+                         &state, &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSetDefmessageHandlerWatch(env, PyObject_IsTrue(state),
+        clips_defclass_value(p), (unsigned int)i);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_undefmessageHandler */
+static char e_undefmessageHandler__doc__[] = "\
+env_undefmessageHandler(env, defclass, index)\n\
+remove specified message handler from system\n\
+arguments:\n\
+  defclass (defclass) - the defclass to inspect\n\
+  index (int) - index of handler";
+static PyObject *e_undefmessageHandler(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefclassObject *p = NULL;
+    unsigned int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!i",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefclassType, &p, &i))
+        FAIL();
+    if(i <= 0) {
+        ERROR_VALUE("index must be positive");
+        FAIL();
+    }
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFCLASS(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvUndefmessageHandler(env, clips_defclass_value(p), i)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* 4.15 [E] - Definstances Functions */
+
+/* helper to check whether there is still this construct */
+F_INLINE void *env_definstancesExists(void *env, void *ptr) {
+    void *rv = EnvGetNextDefinstances(env, NULL);
+    while(rv != NULL) {
+        if(rv == ptr) return rv;
+        else rv = EnvGetNextDefinstances(env, rv);
+    }
+    return NULL;
+}
+#define EPYDEFINSTANCES_EXISTS(_e, _p) \
+    env_definstancesExists(_e, clips_definstances_value(_p))
+#define ECHECK_DEFINSTANCES(_e, _p) do { \
+        if(!EPYDEFINSTANCES_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_NOTFOUND(); \
+            FAIL(); \
+        } \
+    } while(0)
+#define ECHECK_RM_DEFINSTANCES(_e, _p) do { \
+        if(_p && !EPYDEFINSTANCES_EXISTS(_e, _p)) { \
+            ERROR_CLIPS_REMOVE(); \
+            FAIL(); \
+        } \
+    } while(0)
+/* API functions with documentation */
+
+/* env_definstancesModule */
+static char e_definstancesModule__doc__[] = "\
+env_definstancesModule(env, definstances) -> str\n\
+retrieve the module name where specified definstances is defined\n\
+returns: module name as string\n\
+arguments:\n\
+  definstances (definstances) - the definstances to inspect";
+static PyObject *e_definstancesModule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefinstancesObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefinstancesType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFINSTANCES(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    s = EnvDefinstancesModule(env, clips_definstances_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_findDefinstances */
+static char e_findDefinstances__doc__[] = "\
+env_findDefinstances(env, name) -> definstances\n\
+return the definstances object associated with name\n\
+returns: the definstances as a new object\n\
+arguments:\n\
+  name (str) - the name to look for";
+static PyObject *e_findDefinstances(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DefinstancesObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &name))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvFindDefinstances(env, name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_definstances_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_definstances_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefinstancesList */
+static char e_getDefinstancesList__doc__[] = "\
+env_getDefinstancesList(env [, module]) -> (MULTIFIELD, list)\n\
+retrieve the list of definstances objects in the specified defmodule\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)\n\
+arguments:\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_getDefinstancesList(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDefinstancesList(
+        env, &o, module ? clips_defmodule_value(module) : NULL);
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefinstancesName */
+static char e_getDefinstancesName__doc__[] = "\
+env_getDefinstancesName(env, definstances) -> str\n\
+retrieve the name of specified definstances\n\
+returns: name as a string\n\
+arguments:\n\
+  definstances (definstances) - the definstances to inspect";
+static PyObject *e_getDefinstancesName(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefinstancesObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefinstancesType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFINSTANCES(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetDefinstancesName(env, clips_definstances_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefinstancesPPForm */
+static char e_getDefinstancesPPForm__doc__[] = "\
+env_getDefinstancesPPForm(env, definstances) -> str\n\
+retrieve the pretty-print form of specified definstances\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  definstances (definstances) - the definstances to inspect";
+static PyObject *e_getDefinstancesPPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefinstancesObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefinstancesType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFINSTANCES(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetDefinstancesPPForm(env, clips_definstances_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getNextDefinstances */
+static char e_getNextDefinstances__doc__[] = "\
+env_getNextDefinstances(env [, definstances]) -> definstances\n\
+retrieve next definstances object in list, first if argument is omitted\n\
+returns: a definstances object, None if already at last definstances\n\
+arguments:\n\
+  definstances (definstances) - the definstances to start from";
+static PyObject *e_getNextDefinstances(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefinstancesObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefinstancesType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(p)
+        ECHECK_DEFINSTANCES(env, p);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextDefinstances(env, p ? clips_definstances_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_definstances_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_definstances_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_isDefinstancesDeletable */
+static char e_isDefinstancesDeletable__doc__[] = "\
+env_isDefinstancesDeletable(env, definstances) -> bool\n\
+tell whether or not the definstances can be deleted\n\
+returns: True if the definstances can be deleted, False otherwise\n\
+arguments:\n\
+  definstances (definstances) - the definstances to be inspected";
+static PyObject *e_isDefinstancesDeletable(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefinstancesObject *p = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefinstancesType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_DEFINSTANCES(env, p);
+    i = EnvIsDefinstancesDeletable(env, clips_definstances_value(p));
+    RETURN_BOOL(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_listDefinstances */
+static char e_listDefinstances__doc__[] = "\
+env_listDefinstances(env, logicalname [, module])\n\
+list definstances to output identified by logicalname\n\
+arguments:\n\
+  logicalname (str) - the logical name of output\n\
+  module (defmodule) - the defmodule to inspect, all if omitted";
+static PyObject *e_listDefinstances(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *module = NULL;
+    char *lname = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O!",
+                         &clips_EnvType, &pyenv,
+                         &lname, &clips_DefmoduleType, &module))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvListDefinstances(
+        env, lname, module ? clips_defmodule_value(module) : NULL);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_undefinstances */
+static char e_undefinstances__doc__[] = "\
+env_undefinstances(env [, definstances])\n\
+delete a definstances object or all definstances objects\n\
+arguments:\n\
+  definstances (definstances) - object to be deleted, all if omitted";
+static PyObject *e_undefinstances(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefinstancesObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv,
+                         &clips_DefinstancesType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ECHECK_RM_DEFINSTANCES(env, p);
+    ENV_CLIPS_LOCK_GC(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    if(!EnvUndefinstances(env, p ? clips_definstances_value(p) : NULL)) {
+        RELEASE_MEMORY_ERROR();
+        ENV_CLIPS_UNLOCK_GC(pyenv);
+        ERROR_CLIPS_REMOVE();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    ENV_CLIPS_UNLOCK_GC(pyenv);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_findDefmodule */
+static char e_findDefmodule__doc__[] = "\
+env_findDefmodule(env, name) -> defmodule\n\
+return the defmodule object associated with name\n\
+returns: the defmodule as a new object\n\
+arguments:\n\
+  name (str) - the name to look for";
+static PyObject *e_findDefmodule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *name = NULL;
+    void *ptr = NULL;
+    clips_DefmoduleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &name))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvFindDefmodule(env, name);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    clips_defmodule_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defmodule_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getCurrentModule */
+static char e_getCurrentModule__doc__[] = "\
+env_getCurrentModule(env) -> defmodule\n\
+return current module\n\
+returns: current module as a new object";
+static PyObject *e_getCurrentModule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *p = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_EnvType, &pyenv))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetCurrentModule(env);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    clips_defmodule_New(p);
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defmodule_value(p) = ptr;
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefmoduleList */
+static char e_getDefmoduleList__doc__[] = "\
+env_getDefmoduleList(env) -> (MULTIFIELD, list)\n\
+return the list of modules in system\n\
+returns: MULTIFIELD and a list of pairs (STRING, name)";
+static PyObject *e_getDefmoduleList(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    PyObject *p = NULL;
+    DATA_OBJECT o = { 0 };
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_EnvType, &pyenv))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvGetDefmoduleList(env, &o);
+    p = i_do2py_e(env, &o);
+    RELEASE_MEMORY_ERROR();
+    if(!p) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* env_getDefmoduleName */
+static char e_getDefmoduleName__doc__[] = "\
+env_getDefmoduleName(env, defmodule) -> str\n\
+retrieve the name of specified defmodule\n\
+returns: name as a string\n\
+arguments:\n\
+  defmodule (defmodule) - the defmodule to inspect";
+static PyObject *e_getDefmoduleName(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefmoduleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    name = EnvGetDefmoduleName(env, clips_defmodule_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!name) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(name);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getDefmodulePPForm */
+static char e_getDefmodulePPForm__doc__[] = "\
+env_getDefmodulePPForm(env, defmodule) -> str\n\
+retrieve the pretty-print form of specified defmodule\n\
+returns: the requested pretty-print form as a string\n\
+arguments:\n\
+  defmodule (defmodule) - the defmodule to inspect";
+static PyObject *e_getDefmodulePPForm(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *p = NULL;
+    char *s = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefmoduleType, &p))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    env = clips_environment_value(pyenv);
+    s = EnvGetDefmodulePPForm(env, clips_defmodule_value(p));
+    RELEASE_MEMORY_ERROR();
+    if(!s) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    RETURN_STR(s);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_getNextDefmodule */
+static char e_getNextDefmodule__doc__[] = "\
+env_getNextDefmodule(env [, defmodule]) -> defmodule\n\
+retrieve next defmodule object in list, first if argument is omitted\n\
+returns: a defmodule object, None if already at last defmodule\n\
+arguments:\n\
+  defmodule (defmodule) - the defmodule to start from";
+static PyObject *e_getNextDefmodule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *p = NULL, *q = NULL;
+    void *ptr = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|O!",
+                         &clips_EnvType, &pyenv, &clips_DefmoduleType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    ptr = EnvGetNextDefmodule(env, p ? clips_defmodule_value(p) : NULL);
+    RELEASE_MEMORY_ERROR();
+    if(!ptr)
+        RETURN_NONE();
+    clips_defmodule_New(q);
+    if(!q) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_defmodule_value(q) = ptr;
+    RETURN_PYOBJECT(q);
+
+BEGIN_FAIL
+    Py_XDECREF(q);
+END_FAIL
+}
+
+/* env_listDefmodules */
+static char e_listDefmodules__doc__[] = "\
+env_listDefmodules(env, output)\n\
+list modules to logical output\n\
+arguments:\n\
+  output (str) - logical name of output stream";
+static PyObject *e_listDefmodules(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *output = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s", &clips_EnvType, &pyenv, &output))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvListDefmodules(env, output);
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_setCurrentModule */
+static char e_setCurrentModule__doc__[] = "\
+env_setCurrentModule(env, defmodule)\n\
+set current module to the one specified\n\
+arguments:\n\
+  defmodule (defmodule) - new current defmodule";
+static PyObject *e_setCurrentModule(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    clips_DefmoduleObject *p = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!O!",
+                         &clips_EnvType, &pyenv, &clips_DefmoduleType, &p))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvSetCurrentModule(env, clips_defmodule_value(p));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_sendCommand [undocumented] */
+static char e_sendCommand__doc__[] = "\
+env_sendCommand(env, command [, verbose])\n\
+send a full command to the engine as if it was typed at the prompt\n\
+arguments:\n\
+  command (str) - the complete command to send\n\
+  verbose (bool) - if True command can produce output";
+static PyObject *e_sendCommand(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    char *command = NULL;
+    int res = 0, verbose = FALSE;
+    PyObject *v = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!s|O",
+                         &clips_EnvType, &pyenv, &command, &v))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    verbose = (v && PyObject_IsTrue(v)) ? TRUE : FALSE;
+    ACQUIRE_MEMORY_ERROR();
+    FlushPPBuffer(env);
+    SetPPBufferStatus(env, OFF);
+    RouteCommand(env, command, verbose);
+    res = GetEvaluationError(env);
+    FlushPPBuffer(env);
+    SetHaltExecution(env, FALSE);
+    SetEvaluationError(env, FALSE);
+    FlushBindList(env);
+    RELEASE_MEMORY_ERROR();
+    if(res) {
+        ERROR_CLIPS_PARSEA();
+        FAIL();
+    }
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* env_forceCleanup() [undocumented] */
+static char e_forceCleanup__doc__[] = "\
+env_forceCleanup(env [, alldepths, heuristics])\n\
+attempt to force a garbage collection\n\
+arguments:\n\
+  alldepths (bool) - true to clean up all depths (default)\n\
+  heuristics (bool) - true to use heuristics (default)";
+static PyObject *e_forceCleanup(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+    PyObject *alldepths = NULL, *heuristics = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!|OO",
+                         &clips_EnvType, &pyenv,
+                         &alldepths, &heuristics))
+        FAIL();
+    CHECK_NOCURENV(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    env = clips_environment_value(pyenv);
+    if(EngineData(env)->ExecutingRule != NULL) {
+        ERROR_CLIPSSYS_CLEANUP();
+        FAIL();
+    }
+    ACQUIRE_MEMORY_ERROR();
+    PeriodicCleanup(env,
+        alldepths ? TRUE : PyObject_IsTrue(alldepths),
+        heuristics ? TRUE : PyObject_IsTrue(heuristics));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* ======================================================================== */
+
+/* 8.2 - Memory Management */
+
+/* getConserveMemory */
+STATUS_FUNC_GET_BOOL(getConserveMemory, m_getConserveMemory, GetConserveMemory)
+
+/* memRequests */
+STATUS_FUNC_GET(memRequests, m_memRequests, MemRequests, "i")
+
+/* memUsed */
+STATUS_FUNC_GET(memUsed, m_memUsed, MemUsed, "i")
+
+/* releaseMem */
+static char m_releaseMem__doc__[] = "\
+releaseMem(tell [, bytes]) -> int\n\
+release specified amount of memory\n\
+returns: the effective amount of freed memory\n\
+arguments:\n\
+  tell (bool) - True to print out a message\n\
+  bytes (int) - bytes to free, all if omitted";
+static PyObject *m_releaseMem(PyObject *self, PyObject *args) {
+    PyObject *tell = NULL;
+    int b = -1;
+    long b1 = 0;
+
+    if(!PyArg_ParseTuple(args, "O|i", &tell, &b))
+        FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    b1 = ReleaseMem(b, PyObject_IsTrue(tell));
+    RELEASE_MEMORY_ERROR();
+    RETURN_INT(b1);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setConserveMemory */
+STATUS_FUNC_SET_BOOL(setConserveMemory, m_setConserveMemory, SetConserveMemory)
+
+/* setOutOfMemoryFunction */
+UNIMPLEMENT(setOutOfMemoryFunction, m_setOutOfMemoryFunction)
+
+
+/* functions related to pretty-print (and similar) buffers can be put here */
+static char m_getPPBufferSize__doc__[] = "\
+getPPBufferSize() -> int\n\
+retrieve current size of pretty-print form buffers\n\
+returns: the above said size";
+static PyObject *m_getPPBufferSize(PyObject *self, PyObject *args) {
+    CHECK_NOARGS(args);
+    RETURN_INT((unsigned long)ppbuffer_size);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+static char m_setPPBufferSize__doc__[] = "\
+setPPBufferSize(bytes)\n\
+specify new size for pretty-print form buffers\n\
+arguments:\n\
+  size (long) - the number of bytes: it has a lower limit";
+static PyObject *m_setPPBufferSize(PyObject *self, PyObject *args) {
+    int l = 0;
+
+    if(!PyArg_ParseTuple(args, "i", &l))
+        FAIL();
+    if(l < MIN_PPBUFFER_SIZE) {
+        ERROR_VALUE("size is too small");
+        FAIL();
+    }
+    ppbuffer_size = (size_t)l;
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+
+/* ======================================================================== */
+
+/* Standard Environment Functions */
+
+/* number of created environments and maximum number of environments */
+static int num_environments = 1;
+static int max_environments = INITIAL_MAX_ENVIRONMENTS;
+
+
+/* retrieve current number of enviroments allowing index based retrieval */
+static char v_getNumberOfEnvironments__doc__[] = "\
+getNumberOfEnvironments() -> int\n\
+retrieve current number of all created environments\n\
+returns: number of created environments";
+static PyObject *v_getNumberOfEnvironments(PyObject *self, PyObject *args) {
+    CHECK_NOARGS(args);
+    RETURN_INT(num_environments);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* offer a way to modify maximum number of environments */
+static char v_getMaxEnvironments__doc__[] = "\
+getMaxEnvironments() -> int\n\
+retrieve current limit for number of environments\n\
+returns: current maximum number of environments";
+static PyObject *v_getMaxEnvironments(PyObject *self, PyObject *args) {
+    CHECK_NOARGS(args);
+    RETURN_INT(max_environments);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+static char v_setMaxEnvironments__doc__[] = "\
+setMaxEnvironments(limit)\n\
+specify new limit for number of environments\n\
+arguments:\n\
+  limit (int) - maximum number of allowed environments";
+static PyObject *v_setMaxEnvironments(PyObject *self, PyObject *args) {
+    int l = 0;
+
+    if(!PyArg_ParseTuple(args, "i", &l))
+        FAIL();
+    if(l < num_environments) {
+        ERROR_VALUE("limit is less than current amount");
+        FAIL();
+    }
+    max_environments = l;
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* addEnvironmentCleanupFunction */
+UNIMPLEMENT(addEnvironmentCleanupFunction, v_addEnvironmentCleanupFunction)
+
+/* allocateEnvironmentData */
+UNIMPLEMENT(allocateEnvironmentData, v_allocateEnvironmentData)
+
+
+/* prototypes for router handling functions - see below */
+int clips_env_queryFunction(void *, char *);
+int clips_env_printFunction(void *, char *, char *);
+int clips_env_getcFunction(void *, char *);
+int clips_env_ungetcFunction(void *, int, char *);
+int clips_env_exitFunction(void *, int);
+
+/* createEnvironment */
+static char v_createEnvironment__doc__[] = "\
+createEnvironment() -> environment\n\
+create a new CLIPS execution environment separated from current one\n\
+returns: a new environment object";
+static PyObject *v_createEnvironment(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *oldptr = NULL;
+    void *env = NULL;
+#ifdef USE_NONASSERT_CLIPSGCLOCK
+    LOPTR_ITEM ***hm = NULL;
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+
+    CHECK_NOARGS(args);
+    if(num_environments >= max_environments) {
+        ERROR_CLIPSSYS_MAXENV();
+        FAIL();
+    }
+    /* save current environment, we need to reset it before we are back */
+    if(!(oldptr = GetCurrentEnvironment())) {
+        ERROR_CLIPS_NOENV();
+        FAIL();
+    }
+    env = CreateEnvironment();
+    if(!env) {
+        ERROR_CLIPS_CREATION();
+        FAIL();
+    }
+    clips_environment_New(pyenv);
+#ifdef USE_NONASSERT_CLIPSGCLOCK
+    if(!AllocateEnvironmentData(
+       env, STRAYFACTS_DATA, sizeof(LOPTR_ITEM ***), NULL)) {
+        ERROR_CLIPS_CREATION();
+        FAIL();
+    }
+    /* STRAYFACTS_DATA will contain just a copy of the pointer to the map */
+    hm = (LOPTR_ITEM ***)GetEnvironmentData(env, STRAYFACTS_DATA);
+    *hm = pyenv->clips_StrayFacts;  /* no real thin ice, it was allocated */
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+    if(!pyenv) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    clips_environment_value(pyenv) = env;
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    EnvAddRouter(env, "python", 0,
+                 clips_env_queryFunction,
+                 clips_env_printFunction,
+                 clips_env_getcFunction,
+                 clips_env_ungetcFunction,
+                 clips_env_exitFunction);
+    EnvActivateRouter(env, "python");
+    /* as said above restore environment in order to avoid problems */
+    SetCurrentEnvironment(oldptr);
+    /* if we are here the environment creation was successful */
+    RELEASE_MEMORY_ERROR();
+    num_environments++;
+    RETURN_PYOBJECT(pyenv);
+
+BEGIN_FAIL
+    if(env) {
+        DestroyEnvironment(env);
+        SetCurrentEnvironment(oldptr);
+    }
+    Py_XDECREF(pyenv);
+END_FAIL
+}
+
+/* destroyEnvironment */
+UNIMPLEMENT(destroyEnvironment, v_destroyEnvironment)
+
+/* getCurrentEnvironment */
+static char v_getCurrentEnvironment__doc__[] = "\
+getCurrentEnvironment() -> environment\n\
+return current environment\n\
+returns: an environment object";
+static PyObject *v_getCurrentEnvironment(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    void *env = NULL;
+
+    CHECK_NOARGS(args);
+    env = GetCurrentEnvironment();
+    if(!env) {
+        ERROR_CLIPS_RETVAL();
+        FAIL();
+    }
+    clips_environment_New(pyenv);
+    clips_environment_value(pyenv) = env;
+    INJECT_ADDITIONAL_ENVIRONMENT_DATA(pyenv);
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    RETURN_PYOBJECT(pyenv);
+
+BEGIN_FAIL
+    Py_XDECREF(pyenv);
+END_FAIL
+}
+
+/* getEnvironmentData */
+UNIMPLEMENT(getEnvironmentData, v_getEnvironmentData)
+
+/* getEnvironmentIndex */
+static char v_getEnvironmentIndex__doc__[] = "\
+getEnvironmentIndex(environment) -> int\n\
+return unique index of specified environment\n\
+returns: an integer value\n\
+arguments:\n\
+  environment (environment) - the environment to inspect";
+static PyObject *v_getEnvironmentIndex(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_EnvType, &pyenv))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    i = GetEnvironmentIndex(clips_environment_value(pyenv));
+    RETURN_INT(i);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setCurrentEnvironment */
+static char v_setCurrentEnvironment__doc__[] = "\
+setCurrentEnvironment(environment)\n\
+switch to specified environment\n\
+arguments:\n\
+  environment (environment) - the environment to switch to";
+static PyObject *v_setCurrentEnvironment(PyObject *self, PyObject *args) {
+    clips_EnvObject *pyenv = NULL;
+
+    if(!PyArg_ParseTuple(args, "O!", &clips_EnvType, &pyenv))
+        FAIL();
+    CHECK_VALID_ENVIRONMENT(pyenv);
+    /* we cannot preserve GC counter status for current environment */
+    /* RESET_ASSERTED_FACTS(); */ /* reset GC counter for old environment... */
+    COPY_ADDITIONAL_ENVIRONMENT_DATA(pyenv);
+    ACQUIRE_MEMORY_ERROR();
+    SetCurrentEnvironment(clips_environment_value(pyenv));
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* setCurrentEnvironmentByIndex */
+/* if GC locking is enabled we cannot consider this function safe */
+#ifndef USE_NONASSERT_CLIPSGCLOCK
+static char v_setCurrentEnvironmentByIndex__doc__[] = "\
+setCurrentEnvironmentByIndex(index)\n\
+switch to specified environment passing its index\n\
+arguments:\n\
+  index (int) - unique index of environment to switch to";
+static PyObject *v_setCurrentEnvironmentByIndex(PyObject *self, PyObject *args) {
+    int i = 0;
+
+    if(!PyArg_ParseTuple(args, "i", &i)) FAIL();
+    ACQUIRE_MEMORY_ERROR();
+    if(!SetCurrentEnvironmentByIndex(i)) {
+        RELEASE_MEMORY_ERROR();
+        ERROR_CLIPS_NOTFOUND();
+        FAIL();
+    }
+    RELEASE_MEMORY_ERROR();
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+#else
+UNIMPLEMENT(setCurrentEnvironmentByIndex, v_setCurrentEnvironmentByIndex)
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+
+
+
+/* ======================================================================== */
+
+/* 7 - I/O Routers
+ *  Now, we have to deal with it somehow.
+ *  I/O Routers will probably be not easy to implement in Python, and there
+ *  is the strong need for ideas. One method could be the following:
+ *  - we build some buffers of variable length, which can be written and
+ *    read using the functions required by CLIPS
+ *  - we store them in Python objects, and in a Python structure (which will
+ *    only be accessed through C functions, thus invisible to the user), and
+ *    let Python manage all the memory for it - except for buffer destruction
+ *  At the end of this, we will have the standard CLIPS streams connected to
+ *  as many Python file-like objects, and the user can send input and read
+ *  output to/from these, thus being able to use CLIPS just as a pipe.
+ */
+
+
+/* treat an I/O buffer (a file-like behaving object) as a Python object */
+staticforward PyTypeObject buffer_Type;
+
+typedef struct {
+    PyObject_HEAD
+    char *name;
+    char *buffer;
+    char *readptr;
+    size_t size;
+    BOOL py_readonly;   /* this flag is only used by Python interface */
+} buffer_Object;
+
+#define buffer_Check(v) ((v)->ob_type == &buffer_Type)
+#define buffer_Name(v) (((buffer_Object *)(v))->name)
+#define buffer_Buffer(v) (((buffer_Object *)(v))->buffer)
+#define buffer_Readptr(v) (((buffer_Object *)(v))->readptr)
+#define buffer_Size(v) (((buffer_Object *)(v))->size)
+#define buffer_Readonly(v) (((buffer_Object *)(v))->py_readonly)
+
+/* allocate a named initial buffer with size 0 */
+static buffer_Object *buffer_create(const char *name, BOOL readonly) {
+    buffer_Object *p = PyObject_New(buffer_Object, &buffer_Type);
+    size_t namelen = strlen(name);
+
+    buffer_Name(p) = NEW_ARRAY(char, namelen + 1);
+    if(!p)
+        return NULL;
+    strncpy(buffer_Name(p), name, namelen);
+    buffer_Name(p)[namelen] = '\0';
+    buffer_Size(p) = 0;
+    buffer_Buffer(p) = NULL;
+    buffer_Readptr(p) = NULL;
+    buffer_Readonly(p) = readonly;
+    return p;
+}
+
+/* destroy all memory related to the buffer */
+static void buffer_destroy(buffer_Object *o) {
+    if(buffer_Buffer(o) != NULL)
+        DELETE(buffer_Buffer(o));
+    if(buffer_Name(o) != NULL)
+        DELETE(buffer_Name(o));
+    PyObject_Del(o);
+}
+
+/* same as above, with a cast to delete from Python interpreter */
+static void buffer_dealloc(PyObject *o) {
+    buffer_destroy((buffer_Object *)o);
+}
+
+/* clear the buffer */
+static void buffer_clear(buffer_Object *o) {
+    if(buffer_Buffer(o) != NULL)
+        DELETE(buffer_Buffer(o));
+    buffer_Size(o) = 0;
+    buffer_Buffer(o) = NULL;
+    buffer_Readptr(o) = NULL;
+}
+
+/* append a string to the buffer */
+static BOOL buffer_append(buffer_Object *o, const char *str) {
+    char *newbuffer = NULL; /* should be the result of a realloc() */
+    size_t len = strlen(str);
+    size_t readindex = 0;
+    BOOL rv = FALSE, usedbuffer = buffer_Buffer(o) ? TRUE : FALSE;
+
+    /* in this case realloc() may behave as malloc() */
+    newbuffer = (char *)REALLOC(buffer_Buffer(o), buffer_Size(o) + len + 1);
+    if(!usedbuffer && newbuffer)
+        newbuffer[0] = '\0';
+    if(newbuffer != NULL) {
+        strncat(newbuffer, str, len);
+        buffer_Size(o) += len;
+        newbuffer[buffer_Size(o)] = '\0';
+        if(!buffer_Readptr(o))
+            buffer_Readptr(o) = newbuffer;
+        else {
+            readindex = (size_t)(buffer_Readptr(o) - buffer_Buffer(o));
+            buffer_Readptr(o) = (char *)(newbuffer + readindex);
+        }
+        buffer_Buffer(o) = newbuffer;   /* could have changed */
+        rv = TRUE;
+    }
+    return rv;
+}
+
+/* pick first n characters from string: out must be already allocated */
+static BOOL buffer_head(const buffer_Object *o, char *out, size_t n) {
+    strncpy(out, buffer_Buffer(o), n);
+    out[n] = '\0';
+    return TRUE;
+}
+
+/* remove first n characters from buffer */
+static BOOL buffer_remove(buffer_Object *o, size_t n) {
+    char *newbuffer = NULL;
+    size_t readindex = 0, newsize = 0;
+
+    if(n > buffer_Size(o) || buffer_Size(o) == 0) return FALSE;
+    else {
+        newsize = buffer_Size(o) - n;
+        readindex = (size_t)(buffer_Readptr(o) - buffer_Buffer(o)) - n;
+        newbuffer = NEW_ARRAY(char, newsize + 1);
+        if(newbuffer != NULL) {
+            strncpy(newbuffer,
+                (char *)(buffer_Buffer(o) + n), buffer_Size(o) - n);
+            DELETE(buffer_Buffer(o));
+            buffer_Size(o) = newsize;
+            buffer_Buffer(o) = newbuffer;
+            buffer_Buffer(o)[newsize] = '\0';
+            if(readindex < 0)
+                readindex = 0;
+            buffer_Readptr(o) = (char *)(buffer_Buffer(o) + readindex);
+            return TRUE;
+        }
+        return FALSE;
+    }
+}
+
+/* find the first occurrence of a character in buffer as index */
+static long buffer_chrindex(const buffer_Object *o, int c) {
+    char *ptr = NULL;
+
+    if(buffer_Size(o) == 0) return -1;
+    else {
+        ptr = strchr(buffer_Buffer(o), c);
+        if(!ptr)
+            return -1;
+        else
+            return (long)(ptr - buffer_Buffer(o));
+    }
+}
+
+/* putchar function */ /* NOT USED */ /*
+static BOOL buffer_putchar(buffer_Object *o, int c) {
+    char fakestr[2] = { (char)c, 0 };
+
+    return buffer_append(o, fakestr);
+}
+*/
+
+/* getchar function */
+static int buffer_getchar(buffer_Object *o) {
+    int c = 0;
+
+    if((size_t)(buffer_Readptr(o) - buffer_Buffer(o)) < buffer_Size(o)) {
+        c = (int)(*buffer_Readptr(o));
+        buffer_Readptr(o)++;
+        return c;
+    } else return -1;
+}
+
+/* ungetchar function */
+static int buffer_ungetchar(buffer_Object *o, int c) {
+    char *ptr = (char *)(buffer_Readptr(o) - 1);
+
+    if(ptr[0] == (char)c && ptr >= buffer_Buffer(o)) {
+        buffer_Readptr(o)--;
+        return c;
+    } else return -1;
+}
+
+/* the Python buffer Type */
+static PyTypeObject buffer_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "streambuffer",
+    sizeof(buffer_Object),
+    0,
+    buffer_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+
+/* stream dictionary handlers */
+static BOOL bufdict_Add(char *name, BOOL readonly) {
+    buffer_Object *o = NULL;
+
+    o = buffer_create(name, readonly);
+    if(!o)
+        return FALSE;
+    else {
+        PyDict_SetItemString((PyObject *)clips_Streams, name, (PyObject *)o);
+        return TRUE;
+    }
+}
+
+static buffer_Object *bufdict_Get(char *name) {
+    PyObject *o = PyDict_GetItemString((PyObject *)clips_Streams, name);
+    if(o != NULL && buffer_Check(o))
+        return (buffer_Object *)o;
+    else return NULL;
+}
+
+static BOOL bufdict_Remove(char *name) {
+    PyObject *o = NULL;
+
+    if(!(o = PyDict_GetItemString((PyObject *)clips_Streams, name)))
+        return FALSE;
+    if(PyDict_DelItemString((PyObject *)clips_Streams, name) == -1)
+        return FALSE;
+    else {
+        /* we know that we are the last ones to use this */
+        buffer_clear((buffer_Object *)o);
+        Py_DECREF(o);
+        return TRUE;
+    }
+}
+
+/* clips router helpers (page 161..163 of apg) */
+int clips_queryFunction(char *logicalName) {
+    return bufdict_Get(logicalName) != NULL ? TRUE : FALSE;
+}
+
+int clips_printFunction(char *logicalName, char *str) {
+    buffer_Object *o = bufdict_Get(logicalName);
+
+    if(o != NULL) {
+        if(!buffer_append(o, str))
+            return FALSE;
+        else return TRUE;
+    } else return FALSE;
+}
+
+int clips_getcFunction(char *logicalName) {
+    buffer_Object *o = bufdict_Get(logicalName);
+    int c = 0;
+
+    if(o != NULL) {
+        c = buffer_getchar(o);
+        if(c < 0)
+            return EOF;
+        else return c;
+    } else return EOF;
+}
+
+int clips_ungetcFunction(int ch, char *logicalName) {
+    buffer_Object *o = bufdict_Get(logicalName);
+    int c = 0;
+
+    if(o != NULL) {
+        c = buffer_ungetchar(o, ch);
+        if(c < 0)
+            return EOF;
+        else return c;
+    } else return EOF;
+}
+
+int clips_exitFunction(int exitCode) {
+    return 0;
+}
+
+
+/* clips router helpers [environmental] (page 161..163 of apg) */
+int clips_env_queryFunction(void *env, char *logicalName) {
+    return bufdict_Get(logicalName) != NULL ? TRUE : FALSE;
+}
+
+int clips_env_printFunction(void *env, char *logicalName, char *str) {
+    buffer_Object *o = bufdict_Get(logicalName);
+
+    if(o != NULL) {
+        if(!buffer_append(o, str))
+            return FALSE;
+        else return TRUE;
+    } else return FALSE;
+}
+
+int clips_env_getcFunction(void *env, char *logicalName) {
+    buffer_Object *o = bufdict_Get(logicalName);
+    int c = 0;
+
+    if(o != NULL) {
+        c = buffer_getchar(o);
+        if(c < 0)
+            return EOF;
+        else return c;
+    } else return EOF;
+}
+
+int clips_env_ungetcFunction(void *env, int ch, char *logicalName) {
+    buffer_Object *o = bufdict_Get(logicalName);
+    int c = 0;
+
+    if(o != NULL) {
+        c = buffer_ungetchar(o, ch);
+        if(c < 0)
+            return EOF;
+        else return c;
+    } else return EOF;
+}
+
+int clips_env_exitFunction(void *env, int exitCode) {
+    return 0;
+}
+
+
+/* Python router interface functions */
+
+/* routerWrite - write to Python router */
+static char g_routerWrite__doc__[] = "\
+routerWrite(streamname, string)\n\
+write a string to logical stream\n\
+arguments:\n\
+  streamname (str) - the name of logical stream\n\
+  string (str) - data to write";
+static PyObject *g_routerWrite(PyObject *self, PyObject *args) {
+    buffer_Object *o = NULL;
+    char *name = NULL, *str = NULL;
+
+    if(!PyArg_ParseTuple(args, "ss", &name, &str))
+        FAIL();
+    o = bufdict_Get(name);
+    if(!o) {
+        ERROR_ROUTER_NOSTREAM();
+        FAIL();
+    }
+    if(buffer_Readonly(o)) {
+        ERROR_ROUTER_READONLY();
+        FAIL();
+    }
+    if(!buffer_append(o, str)) {
+        ERROR_ROUTER_INVALID();
+        FAIL();
+    }
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* routerClear - clear Python router */
+static char g_routerClear__doc__[] = "\
+routerClear(streamname)\n\
+clear logical stream\n\
+arguments:\n\
+  streamname (str) - the name of logical stream";
+static PyObject *g_routerClear(PyObject *self, PyObject *args) {
+    buffer_Object *o = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    o = bufdict_Get(name);
+    if(!o) {
+        ERROR_ROUTER_NOSTREAM();
+        FAIL();
+    }
+    buffer_clear(o);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* routerRead - read from Python router */
+static char g_routerRead__doc__[] = "\
+routerRead(streamname)\n\
+read from logical stream\n\
+arguments:\n\
+  streamname (str) - the name of logical stream";
+static PyObject *g_routerRead(PyObject *self, PyObject *args) {
+    buffer_Object *o = NULL;
+    PyObject *p = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    o = bufdict_Get(name);
+    if(!o) {
+        ERROR_ROUTER_NOSTREAM();
+        FAIL();
+    }
+    p = Py_BuildValue("s", buffer_Buffer(o));
+    if(!p) {
+        ERROR_MEMORY_CREATION();
+        FAIL();
+    }
+    buffer_clear(o);
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    Py_XDECREF(p);
+END_FAIL
+}
+
+/* routerReadline - read a line from Python router */
+static char g_routerReadline__doc__[] = "\
+routerReadline(streamname)\n\
+read a single text line from logical stream\n\
+arguments:\n\
+  streamname (str) - the name of logical stream";
+static PyObject *g_routerReadline(PyObject *self, PyObject *args) {
+    buffer_Object *o = NULL;
+    PyObject *p = NULL;
+    char *name = NULL, *tmp = NULL;
+    int n = 0;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    o = bufdict_Get(name);
+    if(!o) {
+        ERROR_ROUTER_NOSTREAM();
+        FAIL();
+    }
+
+    n = buffer_chrindex(o, '\n');
+    if(n < 0) {
+        p = Py_BuildValue("s", buffer_Buffer(o));
+        buffer_clear(o);
+        if(!p) {
+            ERROR_MEMORY_CREATION();
+            FAIL();
+        }
+    } else {
+        tmp = NEW_ARRAY(char, n + 2);
+        if(!tmp || !buffer_head(o, tmp, n + 1)) {
+            ERROR_MEMORY_CREATION();
+            FAIL();
+        }
+        p = Py_BuildValue("s", tmp);
+        if(!p) {
+            ERROR_MEMORY_CREATION();
+            FAIL();
+        }
+        DELETE(tmp);
+        buffer_remove(o, n);
+    }
+    RETURN_PYOBJECT(p);
+
+BEGIN_FAIL
+    if(tmp != NULL)
+        DELETE(tmp);
+    Py_XDECREF(p);
+END_FAIL
+}
+
+
+
+/* ======================================================================== */
+
+/* external functions definition system */
+
+/* when FALSE, do not print tracebacks from within CLIPS */
+static BOOL clips_EnableExternalTraceback = FALSE;
+
+
+/* we allow only alphanumerics and hyphens for function names (sorry...) */
+static BOOL checkFuncName(char *name) {
+    if(isalpha(*name) || *name == '_') name++;
+    while(*name) {
+        if(isalnum(*name) || *name == '-' || *name == '_')
+            name++;
+        else return FALSE;
+    }
+    return TRUE;
+}
+
+/* addPythonFunction - register a new Python function for CLIPS */
+static char f_addPythonFunction__doc__[] = "\
+addPythonFunction(name, function)\n\
+add a Python external function to call from CLIPS: the passed in function\n\
+should expect arguments as (type, value) pairs and return such a pair\n\
+arguments:\n\
+  name (str) - name that the function will have in CLIPS\n\
+  function (callable) - the function to be called from within CLIPS";
+static PyObject *f_addPythonFunction(PyObject *self, PyObject *args) {
+    PyObject *pfunc = NULL;
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "sO", &name, &pfunc))
+        FAIL();
+    if (!PyCallable_Check(pfunc)) {
+        ERROR_TYPE("callable expected as second argument");
+        FAIL();
+    }
+    if(!checkFuncName(name)) {
+        ERROR_VALUE("invalid function name");
+        FAIL();
+    }
+    if(PyDict_SetItemString((PyObject *)clips_PythonFunctions,
+                            name, (PyObject *)pfunc)) {
+        ERROR_CLIPS_OTHER("could not register external function");
+        FAIL();
+    }
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* removePythonFunction - deregister a Python function from CLIPS */
+static char f_removePythonFunction__doc__[] = "\
+removePythonFunction(name)\n\
+remove a previously registered external Python function\n\
+arguments:\n\
+  name (str) - name that the function has in CLIPS";
+static PyObject *f_removePythonFunction(PyObject *self, PyObject *args) {
+    char *name = NULL;
+
+    if(!PyArg_ParseTuple(args, "s", &name))
+        FAIL();
+    if(PyDict_DelItemString((PyObject *)clips_PythonFunctions, name)) {
+        ERROR_CLIPS_OTHER("could not remove external function");
+        FAIL();
+    }
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+/* clearPythonFunctions - deregister all registered Python functions */
+static char f_clearPythonFunctions__doc__[] = "\
+clearPythonFunctions()\n\
+remove all previously registered external Python functions";
+static PyObject *f_clearPythonFunctions(PyObject *self, PyObject *args) {
+    CHECK_NOARGS(args);
+    PyDict_Clear((PyObject *)clips_PythonFunctions);
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* allow/disallow printing a trace on bad functions or exceptions */
+static char f_setPrintExternalTraceback__doc__[] = "\
+setPrintExternalTraceback(bool)\n\
+allow or disallow printing a standard traceback on calls within CLIPS\n\
+arguments:\n\
+  bool (bool) - allow when True and disallow otherwise";
+static PyObject *f_setPrintExternalTraceback(PyObject *self, PyObject *args) {
+    PyObject *bval = NULL;
+
+    if(!PyArg_ParseTuple(args, "O", &bval))
+        FAIL();
+    clips_EnableExternalTraceback = PyObject_IsTrue(bval) ? TRUE : FALSE;
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+static char f_getPrintExternalTraceback__doc__[] = "\
+getPrintExternalTraceback() -> bool\n\
+report whether printing a traceback from within CLIPS is allowed or not";
+static PyObject *f_getPrintExternalTraceback(PyObject *self, PyObject *args) {
+    CHECK_NOARGS(args);
+    return Py_BuildValue("i", clips_EnableExternalTraceback ? 1 : 0);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+/* functions that print an error to CLIPS */
+static void InvalidFunctionError(void *env, char *name) {
+    PrintErrorID(env, "PYTHONFN", 1, TRUE);
+    EnvPrintRouter(env, WERROR, "External function ");
+    EnvPrintRouter(env, WERROR, name);
+    EnvPrintRouter(env, WERROR, " not found.\n");
+}
+static void FunctionExceptionError(void *env, char *name) {
+    PrintErrorID(env, "PYTHONXC", 1, TRUE);
+    EnvPrintRouter(env, WERROR, "Call to function ");
+    EnvPrintRouter(env, WERROR, name);
+    EnvPrintRouter(env, WERROR, " failed.\n");
+}
+
+/* the following is the function that is actually called by CLIPS
+ * declared as
+ * EnvDefineFunction2("python-call", 'u', PTIF EnvPythonExternalCall,
+ *                    "EnvPythonExternalCall", "1*uw");
+ */
+/* some notes about this:
+ *  this function will be called with an undefined number of arguments by
+ *  CLIPS, and will store its return value in an unknown DATA_OBJECT; when
+ *  the Python call fails, it will return the symbol FALSE after sending
+ *  an error message to the 'werror' output router, as all functions in
+ *  CLIPS should return a value also in case of error
+ */
+#define ECLIPS_RETURN_FALSE(_e, _v) do { \
+    SetpType(_v, SYMBOL); SetpValue(_v, ECLIPS_FALSE_SYMBOL(_e)); return; \
+    }  while(0)
+void EnvPythonExternalCall(void *env, DATA_OBJECT_PTR retval) {
+    char *funcname = NULL;
+    int argcnt = 0, i = 0;
+    DATA_OBJECT arg;
+    PyObject *to_call = NULL, *result = NULL, *o = NULL;
+    PyTupleObject *pyargs = NULL;
+
+    if(EnvArgCountCheck(env, "python-call", AT_LEAST, 1) < 0)
+        ECLIPS_RETURN_FALSE(env, retval);
+    if(EnvArgTypeCheck(env, "python-call", 1, SYMBOL, &arg) < 0)
+        ECLIPS_RETURN_FALSE(env, retval);
+    argcnt = EnvRtnArgCount(env);
+    /* now arg contains the function name */
+    funcname = DOToString(arg);
+    if(!(to_call = PyDict_GetItemString((PyObject *)clips_PythonFunctions,
+                                        funcname))) {
+        InvalidFunctionError(env, funcname);
+        if(clips_EnableExternalTraceback) {
+            ERROR_VALUE("invalid function name");
+            PyErr_Print();
+        }
+        SetEvaluationError(env, TRUE);
+        SetHaltExecution(env, TRUE);
+        ECLIPS_RETURN_FALSE(env, retval);
+    }
+    pyargs = (PyTupleObject *)PyTuple_New(argcnt - 1);
+    if(!pyargs) {
+        FunctionExceptionError(env, funcname);
+        if(clips_EnableExternalTraceback) {
+            ERROR_MEMORY("can not pass parameters");
+            PyErr_Print();
+        }
+        SetEvaluationError(env, TRUE);
+        SetHaltExecution(env, TRUE);
+        ECLIPS_RETURN_FALSE(env, retval);
+    }
+    for(i = 2; i <= argcnt; i++) {
+        EnvRtnUnknown(env, i, &arg);
+        o = i_do2py_e(env, &arg);
+        if(!o) {
+            Py_DECREF(pyargs);
+            FunctionExceptionError(env, funcname);
+            if(clips_EnableExternalTraceback) {
+                ERROR_VALUE("can not convert parameters");
+                PyErr_Print();
+            }
+            SetEvaluationError(env, TRUE);
+            SetHaltExecution(env, TRUE);
+            ECLIPS_RETURN_FALSE(env, retval);
+        }
+        PyTuple_SetItem((PyObject *)pyargs, i - 2, o);
+    }
+    result = PyEval_CallObject(to_call, (PyObject *)pyargs);
+    Py_DECREF(pyargs);
+    if(!result) {
+        FunctionExceptionError(env, funcname);
+        if(PyErr_Occurred()) {
+            if(clips_EnableExternalTraceback)
+                PyErr_Print();
+            else PyErr_Clear();
+            SetEvaluationError(env, TRUE);
+            SetHaltExecution(env, TRUE);
+            ECLIPS_RETURN_FALSE(env, retval);
+        }
+    } else {
+        i_py2do_e(env, result, retval);
+        Py_DECREF(result);
+    }
+}
+
+void PythonExternalCall(DATA_OBJECT_PTR retval) {
+    EnvPythonExternalCall(GetCurrentEnvironment(), retval);
+}
+
+
+
+/* ======================================================================== */
+
+/* specific utilities */
+
+/* test for types, for we cannot expose type objects as objects */
+#define TYPE_TEST_FUNC(func, type) \
+    static char func##__doc__[] = "type test function"; \
+    static PyObject *func(PyObject *self, PyObject *args) { \
+        PyObject *p = NULL; \
+        if(!PyArg_ParseTuple(args, "O", &p)) \
+            FAIL(); \
+        return Py_BuildValue("i", PyObject_TypeCheck(p, &type)); \
+        BEGIN_FAIL \
+        END_FAIL \
+    }
+
+TYPE_TEST_FUNC(g_isEnvironment, clips_EnvType)
+TYPE_TEST_FUNC(g_isDeftemplate, clips_DeftemplType)
+TYPE_TEST_FUNC(g_isFact, clips_FactType)
+TYPE_TEST_FUNC(g_isInstance, clips_InstanceType)
+TYPE_TEST_FUNC(g_isDefmodule, clips_DefmoduleType)
+TYPE_TEST_FUNC(g_isDeffacts, clips_DeffactsType)
+TYPE_TEST_FUNC(g_isDefrule, clips_DefruleType)
+TYPE_TEST_FUNC(g_isActivation, clips_ActivationType)
+TYPE_TEST_FUNC(g_isDefglobal, clips_DefglobalType)
+TYPE_TEST_FUNC(g_isDeffunction, clips_DeffunctionType)
+TYPE_TEST_FUNC(g_isDefgeneric, clips_DefgenericType)
+TYPE_TEST_FUNC(g_isDefmethod, clips_DefmethodType)
+TYPE_TEST_FUNC(g_isDefclass, clips_DefclassType)
+TYPE_TEST_FUNC(g_isDefinstances, clips_DefinstancesType)
+
+
+/* set/reset suppression of fatal environment messages on stderr (stdout) */
+static char g_setEnableEnvironmentFatalMessages__doc__[] = "\
+setEnableEnvironmentFatalMessages(bool)\n\
+allow or disallow printing fatal CLIPS environment error messages\n\
+arguments:\n\
+  bool (bool) - allow when True and disallow otherwise";
+static PyObject *g_setEnableEnvironmentFatalMessages(PyObject *self, PyObject *args) {
+    PyObject *bval = NULL;
+
+    if(!PyArg_ParseTuple(args, "O", &bval))
+        FAIL();
+    clips_ShowEnvironmentFatalErrors = PyObject_IsTrue(bval) ? TRUE : FALSE;
+    RETURN_NONE();
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+static char g_getEnableEnvironmentFatalMessages__doc__[] = "\
+getEnableEnvironmentFatalMessages() -> bool\n\
+report whether printing fatal CLIPS environment errors is allowed or not";
+static PyObject *g_getEnableEnvironmentFatalMessages(PyObject *self, PyObject *args) {
+    CHECK_NOARGS(args);
+    RETURN_BOOL(clips_ShowEnvironmentFatalErrors);
+
+BEGIN_FAIL
+    SKIP();
+END_FAIL
+}
+
+
+
+/* ======================================================================== */
+
+#ifdef USE_TEST_DEALLOC_ENV
+/* this is a stupid hack to try to force the module to call the environment
+ * data deallocation function once it's unloaded, in order to ask the CLIPS
+ * engine to release all its allocated memory; it relies on an object that
+ * is only created once at module initialization and can never be created by
+ * a module user; it is also not guaranteed to function asexpected
+ */
+
+staticforward PyTypeObject guard_Type;
+
+typedef struct {
+    PyObject_HEAD
+} guard_Object;
+
+
+/* guard destruction: as a "side effect" perform module finalization */
+static void guard_dealloc(PyObject *o) {
+    /* this is a good place to perform every kind of unhandled cleanup */
+
+    /* destroy all open CLIPS I/O buffers */
+    bufdict_Remove("t");
+    bufdict_Remove("stdin");
+    bufdict_Remove("stdout");
+    bufdict_Remove("wprompt");
+    bufdict_Remove("wdialog");
+    bufdict_Remove("wdisplay");
+    bufdict_Remove("werror");
+    bufdict_Remove("wwarning");
+    bufdict_Remove("wtrace");
+    bufdict_Remove("temporary");
+
+    /* invoke CLIPS specific all environments destruction */
+    DeallocateEnvironmentData();
+
+    /* and only finally destroy the object itself */
+    PyObject_Del(o);
+
+    /* other things like removal of external functions are not needed here */
+}
+
+
+/* the Python internal guard Type */
+static PyTypeObject guard_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "__PyCLIPS_$iGuardType__",  /* the name is intentionally unusable */
+    sizeof(guard_Object),
+    0,
+    guard_dealloc, /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+};
+
+/* also prepare an object living in module namespace with an unusable name */
+#define PREPARE_DEALLOC_ENV() guard_Object *_ig = NULL;
+#define INSTALL_DEALLOC_ENV(_m) do { \
+        guard_Type.ob_type = &PyType_Type; \
+        _ig = PyObject_New(guard_Object, &guard_Type); \
+        PyModule_AddObject(_m, "__PyCLIPS_$iGuardObject__", (PyObject *)_ig); \
+    } while(0)
+
+#else
+
+#define PREPARE_DEALLOC_ENV()
+#define INSTALL_DEALLOC_ENV()
+
+#endif /* USE_TEST_DEALLOC_ENV */
+
+/* ======================================================================== */
+
+/* global methods map */
+static PyMethodDef g_methods[] = {
+    MMAP_ENTRY(addClearFunction, g_addClearFunction),
+    MMAP_ENTRY(addPeriodicFunction, g_addPeriodicFunction),
+    MMAP_ENTRY(addResetFunction, g_addResetFunction),
+    MMAP_ENTRY(bload, g_bload),
+    MMAP_ENTRY(bsave, g_bsave),
+    MMAP_ENTRY(clear, g_clear),
+    MMAP_ENTRY(functionCall, g_functionCall),
+    MMAP_ENTRY(getAutoFloatDividend, g_getAutoFloatDividend),
+    MMAP_ENTRY(getDynamicConstraintChecking, g_getDynamicConstraintChecking),
+    MMAP_ENTRY(getSequenceOperatorRecognition, g_getSequenceOperatorRecognition),
+    MMAP_ENTRY(getStaticConstraintChecking, g_getStaticConstraintChecking),
+    MMAP_ENTRY(load, g_load),
+    MMAP_ENTRY(reset, g_reset),
+    MMAP_ENTRY(save, g_save),
+    MMAP_ENTRY(setAutoFloatDividend, g_setAutoFloatDividend),
+    MMAP_ENTRY(setDynamicConstraintChecking, g_setDynamicConstraintChecking),
+    MMAP_ENTRY(setSequenceOperatorRecognition, g_setSequenceOperatorRecognition),
+    MMAP_ENTRY(setStaticConstraintChecking, g_setStaticConstraintChecking),
+    MMAP_ENTRY(batchStar, g_batchStar),
+    MMAP_ENTRY(build, g_build),
+    MMAP_ENTRY(eval, g_eval),
+    MMAP_ENTRY(dribbleActive, g_dribbleActive),
+    MMAP_ENTRY(dribbleOff, g_dribbleOff),
+    MMAP_ENTRY(dribbleOn, g_dribbleOn),
+    MMAP_ENTRY(getWatchItem, g_getWatchItem),
+    MMAP_ENTRY(unwatch, g_unwatch),
+    MMAP_ENTRY(watch, g_watch),
+    MMAP_ENTRY(deftemplateModule, g_deftemplateModule),
+    MMAP_ENTRY(deftemplateSlotAllowedValues, g_deftemplateSlotAllowedValues),
+    MMAP_ENTRY(deftemplateSlotCardinality, g_deftemplateSlotCardinality),
+    MMAP_ENTRY(deftemplateSlotDefaultP, g_deftemplateSlotDefaultP),
+    MMAP_ENTRY(deftemplateSlotDefaultValue, g_deftemplateSlotDefaultValue),
+    MMAP_ENTRY(deftemplateSlotExistP, g_deftemplateSlotExistP),
+    MMAP_ENTRY(deftemplateSlotMultiP, g_deftemplateSlotMultiP),
+    MMAP_ENTRY(deftemplateSlotNames, g_deftemplateSlotNames),
+    MMAP_ENTRY(deftemplateSlotRange, g_deftemplateSlotRange),
+    MMAP_ENTRY(deftemplateSlotSingleP, g_deftemplateSlotSingleP),
+    MMAP_ENTRY(deftemplateSlotTypes, g_deftemplateSlotTypes),
+    MMAP_ENTRY(findDeftemplate, g_findDeftemplate),
+    MMAP_ENTRY(getDeftemplateList, g_getDeftemplateList),
+    MMAP_ENTRY(getDeftemplateName, g_getDeftemplateName),
+    MMAP_ENTRY(getDeftemplatePPForm, g_getDeftemplatePPForm),
+    MMAP_ENTRY(getDeftemplateWatch, g_getDeftemplateWatch),
+    MMAP_ENTRY(getNextDeftemplate, g_getNextDeftemplate),
+    MMAP_ENTRY(isDeftemplateDeletable, g_isDeftemplateDeletable),
+    MMAP_ENTRY(listDeftemplates, g_listDeftemplates),
+    MMAP_ENTRY(setDeftemplateWatch, g_setDeftemplateWatch),
+    MMAP_ENTRY(undeftemplate, g_undeftemplate),
+    MMAP_ENTRY(assertFact, g_assertFact),
+    MMAP_ENTRY(assertString, g_assertString),
+    MMAP_ENTRY(assignFactSlotDefaults, g_assignFactSlotDefaults),
+    MMAP_ENTRY(createFact, g_createFact),
+    MMAP_ENTRY(decrementFactCount, g_decrementFactCount),
+    MMAP_ENTRY(factIndex, g_factIndex),
+    MMAP_ENTRY(facts, g_facts),
+    MMAP_ENTRY(getFactDuplication, g_getFactDuplication),
+    MMAP_ENTRY(getFactListChanged, g_getFactListChanged),
+    MMAP_ENTRY(getFactPPForm, g_getFactPPForm),
+    MMAP_ENTRY(getFactSlot, g_getFactSlot),
+    MMAP_ENTRY(getNextFact, g_getNextFact),
+    MMAP_ENTRY(getNextFactInTemplate, g_getNextFactInTemplate),
+    MMAP_ENTRY(incrementFactCount, g_incrementFactCount),
+    MMAP_ENTRY(loadFacts, g_loadFacts),
+    MMAP_ENTRY(ppFact, g_ppFact),
+    MMAP_ENTRY(putFactSlot, g_putFactSlot),
+    MMAP_ENTRY(retract, g_retract),
+    MMAP_ENTRY(saveFacts, g_saveFacts),
+    MMAP_ENTRY(setFactDuplication, g_setFactDuplication),
+    MMAP_ENTRY(setFactListChanged, g_setFactListChanged),
+    MMAP_ENTRY(factDeftemplate, g_factDeftemplate),
+    MMAP_ENTRY(factExistp, g_factExistp),
+    MMAP_ENTRY(factSlotNames, g_factSlotNames),
+    MMAP_ENTRY(getFactList, g_getFactList),
+    MMAP_ENTRY(loadFactsFromString, g_loadFactsFromString),
+    MMAP_ENTRY(deffactsModule, g_deffactsModule),
+    MMAP_ENTRY(findDeffacts, g_findDeffacts),
+    MMAP_ENTRY(getDeffactsList, g_getDeffactsList),
+    MMAP_ENTRY(getDeffactsName, g_getDeffactsName),
+    MMAP_ENTRY(getDeffactsPPForm, g_getDeffactsPPForm),
+    MMAP_ENTRY(getNextDeffacts, g_getNextDeffacts),
+    MMAP_ENTRY(isDeffactsDeletable, g_isDeffactsDeletable),
+    MMAP_ENTRY(listDeffacts, g_listDeffacts),
+    MMAP_ENTRY(undeffacts, g_undeffacts),
+    MMAP_ENTRY(defruleHasBreakpoint, g_defruleHasBreakpoint),
+    MMAP_ENTRY(defruleModule, g_defruleModule),
+    MMAP_ENTRY(findDefrule, g_findDefrule),
+    MMAP_ENTRY(getDefruleList, g_getDefruleList),
+    MMAP_ENTRY(getDefruleName, g_getDefruleName),
+    MMAP_ENTRY(getDefrulePPForm, g_getDefrulePPForm),
+    MMAP_ENTRY(getDefruleWatchActivations, g_getDefruleWatchActivations),
+    MMAP_ENTRY(getDefruleWatchFirings, g_getDefruleWatchFirings),
+    MMAP_ENTRY(getIncrementalReset, g_getIncrementalReset),
+    MMAP_ENTRY(getNextDefrule, g_getNextDefrule),
+    MMAP_ENTRY(isDefruleDeletable, g_isDefruleDeletable),
+    MMAP_ENTRY(listDefrules, g_listDefrules),
+    MMAP_ENTRY(matches, g_matches),
+    MMAP_ENTRY(refresh, g_refresh),
+    MMAP_ENTRY(removeBreak, g_removeBreak),
+    MMAP_ENTRY(setBreak, g_setBreak),
+    MMAP_ENTRY(setDefruleWatchActivations, g_setDefruleWatchActivations),
+    MMAP_ENTRY(setDefruleWatchFirings, g_setDefruleWatchFirings),
+    MMAP_ENTRY(setIncrementalReset, g_setIncrementalReset),
+    MMAP_ENTRY(showBreaks, g_showBreaks),
+    MMAP_ENTRY(undefrule, g_undefrule),
+    MMAP_ENTRY(addRunFunction, g_addRunFunction),
+    MMAP_ENTRY(agenda, g_agenda),
+    MMAP_ENTRY(clearFocusStack, g_clearFocusStack),
+    MMAP_ENTRY(deleteActivation, g_deleteActivation),
+    MMAP_ENTRY(focus, g_focus),
+    MMAP_ENTRY(getActivationName, g_getActivationName),
+    MMAP_ENTRY(getActivationPPForm, g_getActivationPPForm),
+    MMAP_ENTRY(getActivationSalience, g_getActivationSalience),
+    MMAP_ENTRY(getAgendaChanged, g_getAgendaChanged),
+    MMAP_ENTRY(getFocus, g_getFocus),
+    MMAP_ENTRY(getFocusStack, g_getFocusStack),
+    MMAP_ENTRY(getNextActivation, g_getNextActivation),
+    MMAP_ENTRY(getSalienceEvaluation, g_getSalienceEvaluation),
+    MMAP_ENTRY(getStrategy, g_getStrategy),
+    MMAP_ENTRY(listFocusStack, g_listFocusStack),
+    MMAP_ENTRY(popFocus, g_popFocus),
+    MMAP_ENTRY(refreshAgenda, g_refreshAgenda),
+    MMAP_ENTRY(removeRunFunction, g_removeRunFunction),
+    MMAP_ENTRY(reorderAgenda, g_reorderAgenda),
+    MMAP_ENTRY(run, g_run),
+    MMAP_ENTRY(setActivationSalience, g_setActivationSalience),
+    MMAP_ENTRY(setAgendaChanged, g_setAgendaChanged),
+    MMAP_ENTRY(setSalienceEvaluation, g_setSalienceEvaluation),
+    MMAP_ENTRY(setStrategy, g_setStrategy),
+    MMAP_ENTRY(defglobalModule, g_defglobalModule),
+    MMAP_ENTRY(findDefglobal, g_findDefglobal),
+    MMAP_ENTRY(getDefglobalList, g_getDefglobalList),
+    MMAP_ENTRY(getDefglobalName, g_getDefglobalName),
+    MMAP_ENTRY(getDefglobalPPForm, g_getDefglobalPPForm),
+    MMAP_ENTRY(getDefglobalValue, g_getDefglobalValue),
+    MMAP_ENTRY(getDefglobalValueForm, g_getDefglobalValueForm),
+    MMAP_ENTRY(getDefglobalWatch, g_getDefglobalWatch),
+    MMAP_ENTRY(getGlobalsChanged, g_getGlobalsChanged),
+    MMAP_ENTRY(getNextDefglobal, g_getNextDefglobal),
+    MMAP_ENTRY(getResetGlobals, g_getResetGlobals),
+    MMAP_ENTRY(isDefglobalDeletable, g_isDefglobalDeletable),
+    MMAP_ENTRY(listDefglobals, g_listDefglobals),
+    MMAP_ENTRY(setDefglobalValue, g_setDefglobalValue),
+    MMAP_ENTRY(setDefglobalWatch, g_setDefglobalWatch),
+    MMAP_ENTRY(setGlobalsChanged, g_setGlobalsChanged),
+    MMAP_ENTRY(setResetGlobals, g_setResetGlobals),
+    MMAP_ENTRY(showDefglobals, g_showDefglobals),
+    MMAP_ENTRY(undefglobal, g_undefglobal),
+    MMAP_ENTRY(deffunctionModule, g_deffunctionModule),
+    MMAP_ENTRY(findDeffunction, g_findDeffunction),
+    MMAP_ENTRY(getDeffunctionList, g_getDeffunctionList),
+    MMAP_ENTRY(getDeffunctionName, g_getDeffunctionName),
+    MMAP_ENTRY(getDeffunctionPPForm, g_getDeffunctionPPForm),
+    MMAP_ENTRY(getDeffunctionWatch, g_getDeffunctionWatch),
+    MMAP_ENTRY(getNextDeffunction, g_getNextDeffunction),
+    MMAP_ENTRY(isDeffunctionDeletable, g_isDeffunctionDeletable),
+    MMAP_ENTRY(listDeffunctions, g_listDeffunctions),
+    MMAP_ENTRY(setDeffunctionWatch, g_setDeffunctionWatch),
+    MMAP_ENTRY(undeffunction, g_undeffunction),
+    MMAP_ENTRY(defgenericModule, g_defgenericModule),
+    MMAP_ENTRY(findDefgeneric, g_findDefgeneric),
+    MMAP_ENTRY(getDefgenericList, g_getDefgenericList),
+    MMAP_ENTRY(getDefgenericName, g_getDefgenericName),
+    MMAP_ENTRY(getDefgenericPPForm, g_getDefgenericPPForm),
+    MMAP_ENTRY(getDefgenericWatch, g_getDefgenericWatch),
+    MMAP_ENTRY(getNextDefgeneric, g_getNextDefgeneric),
+    MMAP_ENTRY(isDefgenericDeletable, g_isDefgenericDeletable),
+    MMAP_ENTRY(listDefgenerics, g_listDefgenerics),
+    MMAP_ENTRY(setDefgenericWatch, g_setDefgenericWatch),
+    MMAP_ENTRY(undefgeneric, g_undefgeneric),
+    MMAP_ENTRY(getDefmethodDescription, g_getDefmethodDescription),
+    MMAP_ENTRY(getDefmethodList, g_getDefmethodList),
+    MMAP_ENTRY(getDefmethodPPForm, g_getDefmethodPPForm),
+    MMAP_ENTRY(getDefmethodWatch, g_getDefmethodWatch),
+    MMAP_ENTRY(getMethodRestrictions, g_getMethodRestrictions),
+    MMAP_ENTRY(getNextDefmethod, g_getNextDefmethod),
+    MMAP_ENTRY(isDefmethodDeletable, g_isDefmethodDeletable),
+    MMAP_ENTRY(listDefmethods, g_listDefmethods),
+    MMAP_ENTRY(setDefmethodWatch, g_setDefmethodWatch),
+    MMAP_ENTRY(undefmethod, g_undefmethod),
+    MMAP_ENTRY(browseClasses, g_browseClasses),
+    MMAP_ENTRY(classAbstractP, g_classAbstractP),
+    MMAP_ENTRY(classReactiveP, g_classReactiveP),
+    MMAP_ENTRY(classSlots, g_classSlots),
+    MMAP_ENTRY(classSubclasses, g_classSubclasses),
+    MMAP_ENTRY(classSuperclasses, g_classSuperclasses),
+    MMAP_ENTRY(defclassModule, g_defclassModule),
+    MMAP_ENTRY(describeClass, g_describeClass),
+    MMAP_ENTRY(findDefclass, g_findDefclass),
+    MMAP_ENTRY(getClassDefaultsMode, g_getClassDefaultsMode),
+    MMAP_ENTRY(getDefclassList, g_getDefclassList),
+    MMAP_ENTRY(getDefclassName, g_getDefclassName),
+    MMAP_ENTRY(getDefclassPPForm, g_getDefclassPPForm),
+    MMAP_ENTRY(getDefclassWatchInstances, g_getDefclassWatchInstances),
+    MMAP_ENTRY(getDefclassWatchSlots, g_getDefclassWatchSlots),
+    MMAP_ENTRY(getNextDefclass, g_getNextDefclass),
+    MMAP_ENTRY(isDefclassDeletable, g_isDefclassDeletable),
+    MMAP_ENTRY(listDefclasses, g_listDefclasses),
+    MMAP_ENTRY(setClassDefaultsMode, g_setClassDefaultsMode),
+    MMAP_ENTRY(setDefclassWatchInstances, g_setDefclassWatchInstances),
+    MMAP_ENTRY(setDefclassWatchSlots, g_setDefclassWatchSlots),
+    MMAP_ENTRY(slotAllowedValues, g_slotAllowedValues),
+    MMAP_ENTRY(slotCardinality, g_slotCardinality),
+    MMAP_ENTRY(slotAllowedClasses, g_slotAllowedClasses),
+    MMAP_ENTRY(slotDefaultValue, g_slotDefaultValue),
+    MMAP_ENTRY(slotDirectAccessP, g_slotDirectAccessP),
+    MMAP_ENTRY(slotExistP, g_slotExistP),
+    MMAP_ENTRY(slotFacets, g_slotFacets),
+    MMAP_ENTRY(slotInitableP, g_slotInitableP),
+    MMAP_ENTRY(slotPublicP, g_slotPublicP),
+    MMAP_ENTRY(slotRange, g_slotRange),
+    MMAP_ENTRY(slotSources, g_slotSources),
+    MMAP_ENTRY(slotTypes, g_slotTypes),
+    MMAP_ENTRY(slotWritableP, g_slotWritableP),
+    MMAP_ENTRY(subclassP, g_subclassP),
+    MMAP_ENTRY(superclassP, g_superclassP),
+    MMAP_ENTRY(undefclass, g_undefclass),
+    MMAP_ENTRY(binaryLoadInstances, g_binaryLoadInstances),
+    MMAP_ENTRY(binarySaveInstances, g_binarySaveInstances),
+    MMAP_ENTRY(createRawInstance, g_createRawInstance),
+    MMAP_ENTRY(decrementInstanceCount, g_decrementInstanceCount),
+    MMAP_ENTRY(deleteInstance, g_deleteInstance),
+    MMAP_ENTRY(directGetSlot, g_directGetSlot),
+    MMAP_ENTRY(directPutSlot, g_directPutSlot),
+    MMAP_ENTRY(findInstance, g_findInstance),
+    MMAP_ENTRY(getInstanceClass, g_getInstanceClass),
+    MMAP_ENTRY(getInstanceName, g_getInstanceName),
+    MMAP_ENTRY(getInstancePPForm, g_getInstancePPForm),
+    MMAP_ENTRY(getInstancesChanged, g_getInstancesChanged),
+    MMAP_ENTRY(getNextInstance, g_getNextInstance),
+    MMAP_ENTRY(getNextInstanceInClass, g_getNextInstanceInClass),
+    MMAP_ENTRY(getNextInstanceInClassAndSubclasses, g_getNextInstanceInClassAndSubclasses),
+    MMAP_ENTRY(incrementInstanceCount, g_incrementInstanceCount),
+    MMAP_ENTRY(instances, g_instances),
+    MMAP_ENTRY(loadInstances, g_loadInstances),
+    MMAP_ENTRY(makeInstance, g_makeInstance),
+    MMAP_ENTRY(restoreInstances, g_restoreInstances),
+    MMAP_ENTRY(saveInstances, g_saveInstances),
+    MMAP_ENTRY(send, g_send),
+    MMAP_ENTRY(setInstancesChanged, g_setInstancesChanged),
+    MMAP_ENTRY(unmakeInstance, g_unmakeInstance),
+    MMAP_ENTRY(validInstanceAddress, g_validInstanceAddress),
+    MMAP_ENTRY(loadInstancesFromString, g_loadInstancesFromString),
+    MMAP_ENTRY(restoreInstancesFromString, g_restoreInstancesFromString),
+    MMAP_ENTRY(findDefmessageHandler, g_findDefmessageHandler),
+    MMAP_ENTRY(getDefmessageHandlerList, g_getDefmessageHandlerList),
+    MMAP_ENTRY(getDefmessageHandlerName, g_getDefmessageHandlerName),
+    MMAP_ENTRY(getDefmessageHandlerPPForm, g_getDefmessageHandlerPPForm),
+    MMAP_ENTRY(getDefmessageHandlerType, g_getDefmessageHandlerType),
+    MMAP_ENTRY(getDefmessageHandlerWatch, g_getDefmessageHandlerWatch),
+    MMAP_ENTRY(getNextDefmessageHandler, g_getNextDefmessageHandler),
+    MMAP_ENTRY(isDefmessageHandlerDeletable, g_isDefmessageHandlerDeletable),
+    MMAP_ENTRY(listDefmessageHandlers, g_listDefmessageHandlers),
+    MMAP_ENTRY(previewSend, g_previewSend),
+    MMAP_ENTRY(setDefmessageHandlerWatch, g_setDefmessageHandlerWatch),
+    MMAP_ENTRY(undefmessageHandler, g_undefmessageHandler),
+    MMAP_ENTRY(definstancesModule, g_definstancesModule),
+    MMAP_ENTRY(findDefinstances, g_findDefinstances),
+    MMAP_ENTRY(getDefinstancesList, g_getDefinstancesList),
+    MMAP_ENTRY(getDefinstancesName, g_getDefinstancesName),
+    MMAP_ENTRY(getDefinstancesPPForm, g_getDefinstancesPPForm),
+    MMAP_ENTRY(getNextDefinstances, g_getNextDefinstances),
+    MMAP_ENTRY(isDefinstancesDeletable, g_isDefinstancesDeletable),
+    MMAP_ENTRY(listDefinstances, g_listDefinstances),
+    MMAP_ENTRY(undefinstances, g_undefinstances),
+    MMAP_ENTRY(findDefmodule, g_findDefmodule),
+    MMAP_ENTRY(getCurrentModule, g_getCurrentModule),
+    MMAP_ENTRY(getDefmoduleList, g_getDefmoduleList),
+    MMAP_ENTRY(getDefmoduleName, g_getDefmoduleName),
+    MMAP_ENTRY(getDefmodulePPForm, g_getDefmodulePPForm),
+    MMAP_ENTRY(getNextDefmodule, g_getNextDefmodule),
+    MMAP_ENTRY(listDefmodules, g_listDefmodules),
+    MMAP_ENTRY(setCurrentModule, g_setCurrentModule),
+    MMAP_ENTRY(setCurrentModule, g_setCurrentModule),
+    MMAP_ENTRY(sendCommand, g_sendCommand),
+    MMAP_ENTRY(removeClearFunction, g_removeClearFunction),
+    MMAP_ENTRY(removePeriodicFunction, g_removePeriodicFunction),
+    MMAP_ENTRY(removeResetFunction, g_removeResetFunction),
+    MMAP_ENTRY(forceCleanup, g_forceCleanup),
+
+/* -------------------------------------------------------------------- */
+
+    MMAP_ENTRY(env_addClearFunction, e_addClearFunction),
+    MMAP_ENTRY(env_addPeriodicFunction, e_addPeriodicFunction),
+    MMAP_ENTRY(env_addResetFunction, e_addResetFunction),
+    MMAP_ENTRY(env_bload, e_bload),
+    MMAP_ENTRY(env_bsave, e_bsave),
+    MMAP_ENTRY(env_clear, e_clear),
+    MMAP_ENTRY(env_functionCall, e_functionCall),
+    MMAP_ENTRY(env_getAutoFloatDividend, e_getAutoFloatDividend),
+    MMAP_ENTRY(env_getDynamicConstraintChecking, e_getDynamicConstraintChecking),
+    MMAP_ENTRY(env_getSequenceOperatorRecognition, e_getSequenceOperatorRecognition),
+    MMAP_ENTRY(env_getStaticConstraintChecking, e_getStaticConstraintChecking),
+    MMAP_ENTRY(env_load, e_load),
+    MMAP_ENTRY(env_reset, e_reset),
+    MMAP_ENTRY(env_save, e_save),
+    MMAP_ENTRY(env_setAutoFloatDividend, e_setAutoFloatDividend),
+    MMAP_ENTRY(env_setDynamicConstraintChecking, e_setDynamicConstraintChecking),
+    MMAP_ENTRY(env_setSequenceOperatorRecognition, e_setSequenceOperatorRecognition),
+    MMAP_ENTRY(env_setStaticConstraintChecking, e_setStaticConstraintChecking),
+    MMAP_ENTRY(env_batchStar, e_batchStar),
+    MMAP_ENTRY(env_build, e_build),
+    MMAP_ENTRY(env_eval, e_eval),
+    MMAP_ENTRY(env_dribbleActive, e_dribbleActive),
+    MMAP_ENTRY(env_dribbleOff, e_dribbleOff),
+    MMAP_ENTRY(env_dribbleOn, e_dribbleOn),
+    MMAP_ENTRY(env_getWatchItem, e_getWatchItem),
+    MMAP_ENTRY(env_unwatch, e_unwatch),
+    MMAP_ENTRY(env_watch, e_watch),
+    MMAP_ENTRY(env_deftemplateModule, e_deftemplateModule),
+    MMAP_ENTRY(env_deftemplateSlotAllowedValues, e_deftemplateSlotAllowedValues),
+    MMAP_ENTRY(env_deftemplateSlotCardinality, e_deftemplateSlotCardinality),
+    MMAP_ENTRY(env_deftemplateSlotDefaultP, e_deftemplateSlotDefaultP),
+    MMAP_ENTRY(env_deftemplateSlotDefaultValue, e_deftemplateSlotDefaultValue),
+    MMAP_ENTRY(env_deftemplateSlotExistP, e_deftemplateSlotExistP),
+    MMAP_ENTRY(env_deftemplateSlotMultiP, e_deftemplateSlotMultiP),
+    MMAP_ENTRY(env_deftemplateSlotNames, e_deftemplateSlotNames),
+    MMAP_ENTRY(env_deftemplateSlotRange, e_deftemplateSlotRange),
+    MMAP_ENTRY(env_deftemplateSlotSingleP, e_deftemplateSlotSingleP),
+    MMAP_ENTRY(env_deftemplateSlotTypes, e_deftemplateSlotTypes),
+    MMAP_ENTRY(env_findDeftemplate, e_findDeftemplate),
+    MMAP_ENTRY(env_getDeftemplateList, e_getDeftemplateList),
+    MMAP_ENTRY(env_getDeftemplateName, e_getDeftemplateName),
+    MMAP_ENTRY(env_getDeftemplatePPForm, e_getDeftemplatePPForm),
+    MMAP_ENTRY(env_getDeftemplateWatch, e_getDeftemplateWatch),
+    MMAP_ENTRY(env_getNextDeftemplate, e_getNextDeftemplate),
+    MMAP_ENTRY(env_isDeftemplateDeletable, e_isDeftemplateDeletable),
+    MMAP_ENTRY(env_listDeftemplates, e_listDeftemplates),
+    MMAP_ENTRY(env_setDeftemplateWatch, e_setDeftemplateWatch),
+    MMAP_ENTRY(env_undeftemplate, e_undeftemplate),
+    MMAP_ENTRY(env_assertFact, e_assertFact),
+    MMAP_ENTRY(env_assertString, e_assertString),
+    MMAP_ENTRY(env_assignFactSlotDefaults, e_assignFactSlotDefaults),
+    MMAP_ENTRY(env_createFact, e_createFact),
+    MMAP_ENTRY(env_decrementFactCount, e_decrementFactCount),
+    MMAP_ENTRY(env_factIndex, e_factIndex),
+    MMAP_ENTRY(env_facts, e_facts),
+    MMAP_ENTRY(env_getFactDuplication, e_getFactDuplication),
+    MMAP_ENTRY(env_getFactListChanged, e_getFactListChanged),
+    MMAP_ENTRY(env_getFactPPForm, e_getFactPPForm),
+    MMAP_ENTRY(env_getFactSlot, e_getFactSlot),
+    MMAP_ENTRY(env_getNextFact, e_getNextFact),
+    MMAP_ENTRY(env_getNextFactInTemplate, e_getNextFactInTemplate),
+    MMAP_ENTRY(env_incrementFactCount, e_incrementFactCount),
+    MMAP_ENTRY(env_loadFacts, e_loadFacts),
+    MMAP_ENTRY(env_ppFact, e_ppFact),
+    MMAP_ENTRY(env_putFactSlot, e_putFactSlot),
+    MMAP_ENTRY(env_retract, e_retract),
+    MMAP_ENTRY(env_saveFacts, e_saveFacts),
+    MMAP_ENTRY(env_setFactDuplication, e_setFactDuplication),
+    MMAP_ENTRY(env_setFactListChanged, e_setFactListChanged),
+    MMAP_ENTRY(env_factDeftemplate, e_factDeftemplate),
+    MMAP_ENTRY(env_factExistp, e_factExistp),
+    MMAP_ENTRY(env_factSlotNames, e_factSlotNames),
+    MMAP_ENTRY(env_getFactList, e_getFactList),
+    MMAP_ENTRY(env_loadFactsFromString, e_loadFactsFromString),
+    MMAP_ENTRY(env_deffactsModule, e_deffactsModule),
+    MMAP_ENTRY(env_findDeffacts, e_findDeffacts),
+    MMAP_ENTRY(env_getDeffactsList, e_getDeffactsList),
+    MMAP_ENTRY(env_getDeffactsName, e_getDeffactsName),
+    MMAP_ENTRY(env_getDeffactsPPForm, e_getDeffactsPPForm),
+    MMAP_ENTRY(env_getNextDeffacts, e_getNextDeffacts),
+    MMAP_ENTRY(env_isDeffactsDeletable, e_isDeffactsDeletable),
+    MMAP_ENTRY(env_listDeffacts, e_listDeffacts),
+    MMAP_ENTRY(env_undeffacts, e_undeffacts),
+    MMAP_ENTRY(env_defruleHasBreakpoint, e_defruleHasBreakpoint),
+    MMAP_ENTRY(env_defruleModule, e_defruleModule),
+    MMAP_ENTRY(env_findDefrule, e_findDefrule),
+    MMAP_ENTRY(env_getDefruleList, e_getDefruleList),
+    MMAP_ENTRY(env_getDefruleName, e_getDefruleName),
+    MMAP_ENTRY(env_getDefrulePPForm, e_getDefrulePPForm),
+    MMAP_ENTRY(env_getDefruleWatchActivations, e_getDefruleWatchActivations),
+    MMAP_ENTRY(env_getDefruleWatchFirings, e_getDefruleWatchFirings),
+    MMAP_ENTRY(env_getIncrementalReset, e_getIncrementalReset),
+    MMAP_ENTRY(env_getNextDefrule, e_getNextDefrule),
+    MMAP_ENTRY(env_isDefruleDeletable, e_isDefruleDeletable),
+    MMAP_ENTRY(env_listDefrules, e_listDefrules),
+    MMAP_ENTRY(env_matches, e_matches),
+    MMAP_ENTRY(env_refresh, e_refresh),
+    MMAP_ENTRY(env_removeBreak, e_removeBreak),
+    MMAP_ENTRY(env_setBreak, e_setBreak),
+    MMAP_ENTRY(env_setDefruleWatchActivations, e_setDefruleWatchActivations),
+    MMAP_ENTRY(env_setDefruleWatchFirings, e_setDefruleWatchFirings),
+    MMAP_ENTRY(env_setIncrementalReset, e_setIncrementalReset),
+    MMAP_ENTRY(env_showBreaks, e_showBreaks),
+    MMAP_ENTRY(env_undefrule, e_undefrule),
+    MMAP_ENTRY(env_addRunFunction, e_addRunFunction),
+    MMAP_ENTRY(env_agenda, e_agenda),
+    MMAP_ENTRY(env_clearFocusStack, e_clearFocusStack),
+    MMAP_ENTRY(env_deleteActivation, e_deleteActivation),
+    MMAP_ENTRY(env_focus, e_focus),
+    MMAP_ENTRY(env_getActivationName, e_getActivationName),
+    MMAP_ENTRY(env_getActivationPPForm, e_getActivationPPForm),
+    MMAP_ENTRY(env_getActivationSalience, e_getActivationSalience),
+    MMAP_ENTRY(env_getAgendaChanged, e_getAgendaChanged),
+    MMAP_ENTRY(env_getFocus, e_getFocus),
+    MMAP_ENTRY(env_getFocusStack, e_getFocusStack),
+    MMAP_ENTRY(env_getNextActivation, e_getNextActivation),
+    MMAP_ENTRY(env_getSalienceEvaluation, e_getSalienceEvaluation),
+    MMAP_ENTRY(env_getStrategy, e_getStrategy),
+    MMAP_ENTRY(env_listFocusStack, e_listFocusStack),
+    MMAP_ENTRY(env_popFocus, e_popFocus),
+    MMAP_ENTRY(env_refreshAgenda, e_refreshAgenda),
+    MMAP_ENTRY(env_removeRunFunction, e_removeRunFunction),
+    MMAP_ENTRY(env_reorderAgenda, e_reorderAgenda),
+    MMAP_ENTRY(env_run, e_run),
+    MMAP_ENTRY(env_setActivationSalience, e_setActivationSalience),
+    MMAP_ENTRY(env_setAgendaChanged, e_setAgendaChanged),
+    MMAP_ENTRY(env_setSalienceEvaluation, e_setSalienceEvaluation),
+    MMAP_ENTRY(env_setStrategy, e_setStrategy),
+    MMAP_ENTRY(env_defglobalModule, e_defglobalModule),
+    MMAP_ENTRY(env_findDefglobal, e_findDefglobal),
+    MMAP_ENTRY(env_getDefglobalList, e_getDefglobalList),
+    MMAP_ENTRY(env_getDefglobalName, e_getDefglobalName),
+    MMAP_ENTRY(env_getDefglobalPPForm, e_getDefglobalPPForm),
+    MMAP_ENTRY(env_getDefglobalValue, e_getDefglobalValue),
+    MMAP_ENTRY(env_getDefglobalValueForm, e_getDefglobalValueForm),
+    MMAP_ENTRY(env_getDefglobalWatch, e_getDefglobalWatch),
+    MMAP_ENTRY(env_getGlobalsChanged, e_getGlobalsChanged),
+    MMAP_ENTRY(env_getNextDefglobal, e_getNextDefglobal),
+    MMAP_ENTRY(env_getResetGlobals, e_getResetGlobals),
+    MMAP_ENTRY(env_isDefglobalDeletable, e_isDefglobalDeletable),
+    MMAP_ENTRY(env_listDefglobals, e_listDefglobals),
+    MMAP_ENTRY(env_setDefglobalValue, e_setDefglobalValue),
+    MMAP_ENTRY(env_setDefglobalWatch, e_setDefglobalWatch),
+    MMAP_ENTRY(env_setGlobalsChanged, e_setGlobalsChanged),
+    MMAP_ENTRY(env_setResetGlobals, e_setResetGlobals),
+    MMAP_ENTRY(env_showDefglobals, e_showDefglobals),
+    MMAP_ENTRY(env_undefglobal, e_undefglobal),
+    MMAP_ENTRY(env_deffunctionModule, e_deffunctionModule),
+    MMAP_ENTRY(env_findDeffunction, e_findDeffunction),
+    MMAP_ENTRY(env_getDeffunctionList, e_getDeffunctionList),
+    MMAP_ENTRY(env_getDeffunctionName, e_getDeffunctionName),
+    MMAP_ENTRY(env_getDeffunctionPPForm, e_getDeffunctionPPForm),
+    MMAP_ENTRY(env_getDeffunctionWatch, e_getDeffunctionWatch),
+    MMAP_ENTRY(env_getNextDeffunction, e_getNextDeffunction),
+    MMAP_ENTRY(env_isDeffunctionDeletable, e_isDeffunctionDeletable),
+    MMAP_ENTRY(env_listDeffunctions, e_listDeffunctions),
+    MMAP_ENTRY(env_setDeffunctionWatch, e_setDeffunctionWatch),
+    MMAP_ENTRY(env_undeffunction, e_undeffunction),
+    MMAP_ENTRY(env_defgenericModule, e_defgenericModule),
+    MMAP_ENTRY(env_findDefgeneric, e_findDefgeneric),
+    MMAP_ENTRY(env_getDefgenericList, e_getDefgenericList),
+    MMAP_ENTRY(env_getDefgenericName, e_getDefgenericName),
+    MMAP_ENTRY(env_getDefgenericPPForm, e_getDefgenericPPForm),
+    MMAP_ENTRY(env_getDefgenericWatch, e_getDefgenericWatch),
+    MMAP_ENTRY(env_getNextDefgeneric, e_getNextDefgeneric),
+    MMAP_ENTRY(env_isDefgenericDeletable, e_isDefgenericDeletable),
+    MMAP_ENTRY(env_listDefgenerics, e_listDefgenerics),
+    MMAP_ENTRY(env_setDefgenericWatch, e_setDefgenericWatch),
+    MMAP_ENTRY(env_undefgeneric, e_undefgeneric),
+    MMAP_ENTRY(env_getDefmethodDescription, e_getDefmethodDescription),
+    MMAP_ENTRY(env_getDefmethodList, e_getDefmethodList),
+    MMAP_ENTRY(env_getDefmethodPPForm, e_getDefmethodPPForm),
+    MMAP_ENTRY(env_getDefmethodWatch, e_getDefmethodWatch),
+    MMAP_ENTRY(env_getMethodRestrictions, e_getMethodRestrictions),
+    MMAP_ENTRY(env_getNextDefmethod, e_getNextDefmethod),
+    MMAP_ENTRY(env_isDefmethodDeletable, e_isDefmethodDeletable),
+    MMAP_ENTRY(env_listDefmethods, e_listDefmethods),
+    MMAP_ENTRY(env_setDefmethodWatch, e_setDefmethodWatch),
+    MMAP_ENTRY(env_undefmethod, e_undefmethod),
+    MMAP_ENTRY(env_browseClasses, e_browseClasses),
+    MMAP_ENTRY(env_classAbstractP, e_classAbstractP),
+    MMAP_ENTRY(env_classReactiveP, e_classReactiveP),
+    MMAP_ENTRY(env_classSlots, e_classSlots),
+    MMAP_ENTRY(env_classSubclasses, e_classSubclasses),
+    MMAP_ENTRY(env_classSuperclasses, e_classSuperclasses),
+    MMAP_ENTRY(env_defclassModule, e_defclassModule),
+    MMAP_ENTRY(env_describeClass, e_describeClass),
+    MMAP_ENTRY(env_findDefclass, e_findDefclass),
+    MMAP_ENTRY(env_getClassDefaultsMode, e_getClassDefaultsMode),
+    MMAP_ENTRY(env_getDefclassList, e_getDefclassList),
+    MMAP_ENTRY(env_getDefclassName, e_getDefclassName),
+    MMAP_ENTRY(env_getDefclassPPForm, e_getDefclassPPForm),
+    MMAP_ENTRY(env_getDefclassWatchInstances, e_getDefclassWatchInstances),
+    MMAP_ENTRY(env_getDefclassWatchSlots, e_getDefclassWatchSlots),
+    MMAP_ENTRY(env_getNextDefclass, e_getNextDefclass),
+    MMAP_ENTRY(env_isDefclassDeletable, e_isDefclassDeletable),
+    MMAP_ENTRY(env_listDefclasses, e_listDefclasses),
+    MMAP_ENTRY(env_setClassDefaultsMode, e_setClassDefaultsMode),
+    MMAP_ENTRY(env_setDefclassWatchInstances, e_setDefclassWatchInstances),
+    MMAP_ENTRY(env_setDefclassWatchSlots, e_setDefclassWatchSlots),
+    MMAP_ENTRY(env_slotAllowedValues, e_slotAllowedValues),
+    MMAP_ENTRY(env_slotCardinality, e_slotCardinality),
+    MMAP_ENTRY(env_slotAllowedClasses, e_slotAllowedClasses),
+    MMAP_ENTRY(env_slotDefaultValue, e_slotDefaultValue),
+    MMAP_ENTRY(env_slotDirectAccessP, e_slotDirectAccessP),
+    MMAP_ENTRY(env_slotExistP, e_slotExistP),
+    MMAP_ENTRY(env_slotFacets, e_slotFacets),
+    MMAP_ENTRY(env_slotInitableP, e_slotInitableP),
+    MMAP_ENTRY(env_slotPublicP, e_slotPublicP),
+    MMAP_ENTRY(env_slotRange, e_slotRange),
+    MMAP_ENTRY(env_slotSources, e_slotSources),
+    MMAP_ENTRY(env_slotTypes, e_slotTypes),
+    MMAP_ENTRY(env_slotWritableP, e_slotWritableP),
+    MMAP_ENTRY(env_subclassP, e_subclassP),
+    MMAP_ENTRY(env_superclassP, e_superclassP),
+    MMAP_ENTRY(env_undefclass, e_undefclass),
+    MMAP_ENTRY(env_binaryLoadInstances, e_binaryLoadInstances),
+    MMAP_ENTRY(env_binarySaveInstances, e_binarySaveInstances),
+    MMAP_ENTRY(env_createRawInstance, e_createRawInstance),
+    MMAP_ENTRY(env_decrementInstanceCount, e_decrementInstanceCount),
+    MMAP_ENTRY(env_deleteInstance, e_deleteInstance),
+    MMAP_ENTRY(env_directGetSlot, e_directGetSlot),
+    MMAP_ENTRY(env_directPutSlot, e_directPutSlot),
+    MMAP_ENTRY(env_findInstance, e_findInstance),
+    MMAP_ENTRY(env_getInstanceClass, e_getInstanceClass),
+    MMAP_ENTRY(env_getInstanceName, e_getInstanceName),
+    MMAP_ENTRY(env_getInstancePPForm, e_getInstancePPForm),
+    MMAP_ENTRY(env_getInstancesChanged, e_getInstancesChanged),
+    MMAP_ENTRY(env_getNextInstance, e_getNextInstance),
+    MMAP_ENTRY(env_getNextInstanceInClass, e_getNextInstanceInClass),
+    MMAP_ENTRY(env_getNextInstanceInClassAndSubclasses, e_getNextInstanceInClassAndSubclasses),
+    MMAP_ENTRY(env_incrementInstanceCount, e_incrementInstanceCount),
+    MMAP_ENTRY(env_instances, e_instances),
+    MMAP_ENTRY(env_loadInstances, e_loadInstances),
+    MMAP_ENTRY(env_makeInstance, e_makeInstance),
+    MMAP_ENTRY(env_restoreInstances, e_restoreInstances),
+    MMAP_ENTRY(env_saveInstances, e_saveInstances),
+    MMAP_ENTRY(env_send, e_send),
+    MMAP_ENTRY(env_setInstancesChanged, e_setInstancesChanged),
+    MMAP_ENTRY(env_unmakeInstance, e_unmakeInstance),
+    MMAP_ENTRY(env_validInstanceAddress, e_validInstanceAddress),
+    MMAP_ENTRY(env_loadInstancesFromString, e_loadInstancesFromString),
+    MMAP_ENTRY(env_restoreInstancesFromString, e_restoreInstancesFromString),
+    MMAP_ENTRY(env_findDefmessageHandler, e_findDefmessageHandler),
+    MMAP_ENTRY(env_getDefmessageHandlerList, e_getDefmessageHandlerList),
+    MMAP_ENTRY(env_getDefmessageHandlerName, e_getDefmessageHandlerName),
+    MMAP_ENTRY(env_getDefmessageHandlerPPForm, e_getDefmessageHandlerPPForm),
+    MMAP_ENTRY(env_getDefmessageHandlerType, e_getDefmessageHandlerType),
+    MMAP_ENTRY(env_getDefmessageHandlerWatch, e_getDefmessageHandlerWatch),
+    MMAP_ENTRY(env_getNextDefmessageHandler, e_getNextDefmessageHandler),
+    MMAP_ENTRY(env_isDefmessageHandlerDeletable, e_isDefmessageHandlerDeletable),
+    MMAP_ENTRY(env_listDefmessageHandlers, e_listDefmessageHandlers),
+    MMAP_ENTRY(env_previewSend, e_previewSend),
+    MMAP_ENTRY(env_setDefmessageHandlerWatch, e_setDefmessageHandlerWatch),
+    MMAP_ENTRY(env_undefmessageHandler, e_undefmessageHandler),
+    MMAP_ENTRY(env_definstancesModule, e_definstancesModule),
+    MMAP_ENTRY(env_findDefinstances, e_findDefinstances),
+    MMAP_ENTRY(env_getDefinstancesList, e_getDefinstancesList),
+    MMAP_ENTRY(env_getDefinstancesName, e_getDefinstancesName),
+    MMAP_ENTRY(env_getDefinstancesPPForm, e_getDefinstancesPPForm),
+    MMAP_ENTRY(env_getNextDefinstances, e_getNextDefinstances),
+    MMAP_ENTRY(env_isDefinstancesDeletable, e_isDefinstancesDeletable),
+    MMAP_ENTRY(env_listDefinstances, e_listDefinstances),
+    MMAP_ENTRY(env_undefinstances, e_undefinstances),
+    MMAP_ENTRY(env_findDefmodule, e_findDefmodule),
+    MMAP_ENTRY(env_getCurrentModule, e_getCurrentModule),
+    MMAP_ENTRY(env_getDefmoduleList, e_getDefmoduleList),
+    MMAP_ENTRY(env_getDefmoduleName, e_getDefmoduleName),
+    MMAP_ENTRY(env_getDefmodulePPForm, e_getDefmodulePPForm),
+    MMAP_ENTRY(env_getNextDefmodule, e_getNextDefmodule),
+    MMAP_ENTRY(env_listDefmodules, e_listDefmodules),
+    MMAP_ENTRY(env_setCurrentModule, e_setCurrentModule),
+    MMAP_ENTRY(env_sendCommand, e_sendCommand),
+    MMAP_ENTRY(env_removeClearFunction, e_removeClearFunction),
+    MMAP_ENTRY(env_removePeriodicFunction, e_removePeriodicFunction),
+    MMAP_ENTRY(env_removeResetFunction, e_removeResetFunction),
+    MMAP_ENTRY(env_forceCleanup, e_forceCleanup),
+
+    /* -------------------------------------------------------------------- */
+
+    MMAP_ENTRY(getConserveMemory, m_getConserveMemory),
+    MMAP_ENTRY(memRequests, m_memRequests),
+    MMAP_ENTRY(memUsed, m_memUsed),
+    MMAP_ENTRY(releaseMem, m_releaseMem),
+    MMAP_ENTRY(setConserveMemory, m_setConserveMemory),
+    MMAP_ENTRY(setOutOfMemoryFunction, m_setOutOfMemoryFunction),
+    MMAP_ENTRY(getPPBufferSize, m_getPPBufferSize),
+    MMAP_ENTRY(setPPBufferSize, m_setPPBufferSize),
+
+    MMAP_ENTRY(addEnvironmentCleanupFunction, v_addEnvironmentCleanupFunction),
+    MMAP_ENTRY(allocateEnvironmentData, v_allocateEnvironmentData),
+    MMAP_ENTRY(createEnvironment, v_createEnvironment),
+    MMAP_ENTRY(destroyEnvironment, v_destroyEnvironment),
+    MMAP_ENTRY(getCurrentEnvironment, v_getCurrentEnvironment),
+    MMAP_ENTRY(getEnvironmentData, v_getEnvironmentData),
+    MMAP_ENTRY(getEnvironmentIndex, v_getEnvironmentIndex),
+    MMAP_ENTRY(setCurrentEnvironment, v_setCurrentEnvironment),
+    MMAP_ENTRY(setCurrentEnvironmentByIndex, v_setCurrentEnvironmentByIndex),
+
+    MMAP_ENTRY(getNumberOfEnvironments, v_getNumberOfEnvironments),
+    MMAP_ENTRY(getMaxEnvironments, v_getMaxEnvironments),
+    MMAP_ENTRY(setMaxEnvironments, v_setMaxEnvironments),
+
+    /* -------------------------------------------------------------------- */
+
+    MMAP_ENTRY(isEnvironment, g_isEnvironment),
+    MMAP_ENTRY(isDeftemplate, g_isDeftemplate),
+    MMAP_ENTRY(isFact, g_isFact),
+    MMAP_ENTRY(isInstance, g_isInstance),
+    MMAP_ENTRY(isDefmodule, g_isDefmodule),
+    MMAP_ENTRY(isDeffacts, g_isDeffacts),
+    MMAP_ENTRY(isDefrule, g_isDefrule),
+    MMAP_ENTRY(isActivation, g_isActivation),
+    MMAP_ENTRY(isDefglobal, g_isDefglobal),
+    MMAP_ENTRY(isDeffunction, g_isDeffunction),
+    MMAP_ENTRY(isDefgeneric, g_isDefgeneric),
+    MMAP_ENTRY(isDefmethod, g_isDefmethod),
+    MMAP_ENTRY(isDefclass, g_isDefclass),
+    MMAP_ENTRY(isDefinstances, g_isDefinstances),
+
+    /* -------------------------------------------------------------------- */
+
+    MMAP_ENTRY(setEnableEnvironmentFatalMessages, g_setEnableEnvironmentFatalMessages),
+    MMAP_ENTRY(getEnableEnvironmentFatalMessages, g_getEnableEnvironmentFatalMessages),
+
+    /* -------------------------------------------------------------------- */
+
+    MMAP_ENTRY(routerWrite, g_routerWrite),
+    MMAP_ENTRY(routerClear, g_routerClear),
+    MMAP_ENTRY(routerRead, g_routerRead),
+    MMAP_ENTRY(routerReadline, g_routerReadline),
+
+    /* -------------------------------------------------------------------- */
+
+    MMAP_ENTRY(addPythonFunction, f_addPythonFunction),
+    MMAP_ENTRY(removePythonFunction, f_removePythonFunction),
+    MMAP_ENTRY(clearPythonFunctions, f_clearPythonFunctions),
+    MMAP_ENTRY(setPrintExternalTraceback, f_setPrintExternalTraceback),
+    MMAP_ENTRY(getPrintExternalTraceback, f_getPrintExternalTraceback),
+
+    // ...
+
+    {NULL, NULL, 0, NULL},
+};
+
+
+/* initialization function */
+PYFUNC
+PyMODINIT_FUNC
+init_clips(void) {
+    PyObject *m = NULL, *d = NULL;
+#ifdef USE_NONASSERT_CLIPSGCLOCK
+    void *e = NULL;
+    LOPTR_ITEM ***hm = NULL;
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+    PREPARE_DEALLOC_ENV();
+
+    /* give the module a method map */
+    m = Py_InitModule3("_clips", g_methods, clips__doc__);
+    d = PyModule_GetDict(m);
+
+    /* possibly install the environment deallocator */
+    INSTALL_DEALLOC_ENV(m);
+
+    /* set the item version string */
+    PyDict_SetItemString(d, "__revision__",
+                         PyString_FromString(clips__revision__));
+
+    /* build the actual exception objects */
+    PyExc_ClipsError = PyErr_NewException("_clips.ClipsError", NULL, NULL);
+    PyDict_SetItemString(d, "ClipsError", PyExc_ClipsError);
+    
+    PyExc_ClipsMemoryError = PyErr_NewException(
+        "_clips.ClipsMemoryError", NULL, NULL);
+    PyDict_SetItemString(d, "ClipsMemoryError", PyExc_ClipsMemoryError);
+
+    /* setup ob_type for types defined here */
+    clips_EnvType.ob_type = &PyType_Type;
+    clips_DeftemplType.ob_type = &PyType_Type;
+    clips_FactType.ob_type = &PyType_Type;
+    clips_DefmoduleType.ob_type = &PyType_Type;
+    clips_DeffactsType.ob_type = &PyType_Type;
+    clips_ActivationType.ob_type = &PyType_Type;
+    clips_DefglobalType.ob_type = &PyType_Type;
+    clips_DeffunctionType.ob_type = &PyType_Type;
+    clips_DefgenericType.ob_type = &PyType_Type;
+    clips_DefmethodType.ob_type = &PyType_Type;
+    clips_DefclassType.ob_type = &PyType_Type;
+
+    buffer_Type.ob_type = &PyType_Type;
+
+    /* initialize the router system */
+    clips_Streams = (PyDictObject *)PyDict_New();
+    bufdict_Add("t", TRUE);
+    bufdict_Add("stdin", FALSE);
+    bufdict_Add("stdout", TRUE);
+    bufdict_Add("wprompt", TRUE);
+    bufdict_Add("wdialog", TRUE);
+    bufdict_Add("wdisplay", TRUE);
+    bufdict_Add("werror", TRUE);
+    bufdict_Add("wwarning", TRUE);
+    bufdict_Add("wtrace", TRUE);
+    bufdict_Add("temporary", TRUE);     /* used by the wrapper module */
+
+    /* adding clips_Streams to module dict will free it on finalization */
+    PyModule_AddObject(m,
+        "__PyCLIPS_$iRouterSystem__", (PyObject *)clips_Streams);
+
+    /* initialize dictionary of Python functions and mark for finalization */
+    clips_PythonFunctions = (PyDictObject *)PyDict_New();
+    PyModule_AddObject(m,
+        "__PyCLIPS_$iPythonFunctions__", (PyObject *)clips_PythonFunctions);
+
+    /* setup manifest constants */
+    ADD_MANIFEST_CONSTANT(d, SYMBOL);
+    ADD_MANIFEST_CONSTANT(d, STRING);
+    ADD_MANIFEST_CONSTANT(d, INTEGER);
+    ADD_MANIFEST_CONSTANT(d, FLOAT);
+    ADD_MANIFEST_CONSTANT(d, EXTERNAL_ADDRESS);
+    ADD_MANIFEST_CONSTANT(d, INSTANCE_NAME);
+    ADD_MANIFEST_CONSTANT(d, INSTANCE_ADDRESS);
+    ADD_MANIFEST_CONSTANT(d, FACT_ADDRESS);
+    ADD_MANIFEST_CONSTANT(d, MULTIFIELD);
+
+    ADD_MANIFEST_CONSTANT(d, LOCAL_SAVE);
+    ADD_MANIFEST_CONSTANT(d, VISIBLE_SAVE);
+
+    ADD_MANIFEST_CONSTANT(d, WHEN_DEFINED);
+    ADD_MANIFEST_CONSTANT(d, WHEN_ACTIVATED);
+    ADD_MANIFEST_CONSTANT(d, EVERY_CYCLE);
+
+    ADD_MANIFEST_CONSTANT(d, DEPTH_STRATEGY);
+    ADD_MANIFEST_CONSTANT(d, BREADTH_STRATEGY);
+    ADD_MANIFEST_CONSTANT(d, LEX_STRATEGY);
+    ADD_MANIFEST_CONSTANT(d, MEA_STRATEGY);
+    ADD_MANIFEST_CONSTANT(d, COMPLEXITY_STRATEGY);
+    ADD_MANIFEST_CONSTANT(d, SIMPLICITY_STRATEGY);
+    ADD_MANIFEST_CONSTANT(d, RANDOM_STRATEGY);
+
+    ADD_MANIFEST_CONSTANT(d, CONVENIENCE_MODE);
+    ADD_MANIFEST_CONSTANT(d, CONSERVATION_MODE);
+
+    ADD_MANIFEST_CONSTANT(d, CLIPS_MAJOR);
+    ADD_MANIFEST_CONSTANT(d, CLIPS_MINOR);
+
+    ADD_MANIFEST_CONSTANT(d, PYCLIPS_MAJOR);
+    ADD_MANIFEST_CONSTANT(d, PYCLIPS_MINOR);
+    ADD_MANIFEST_CONSTANT(d, PYCLIPS_PATCHLEVEL);
+    ADD_MANIFEST_CONSTANT(d, PYCLIPS_INCREMENTAL);
+
+    ADD_MANIFEST_CONSTANT(d, NO_DEFAULT);
+    ADD_MANIFEST_CONSTANT(d, STATIC_DEFAULT);
+    ADD_MANIFEST_CONSTANT(d, DYNAMIC_DEFAULT);
+
+    /* let us hope that no memory errors happen right here, because
+     *  memory handler has not been enabled; however the flag that
+     *  indicates that memory errors have been enabled is still not
+     *  set: a memory allocation failure here will thus cause the
+     *  Python interpreter to exit due to the CLIPS way of treating
+     *  the problem.
+     *  TODO: a "more elegant way" to notify the user.
+     */
+
+    /* we should initialize CLIPS environment once module is loaded */
+    InitializeEnvironment();
+
+#ifdef USE_NONASSERT_CLIPSGCLOCK
+    e = GetCurrentEnvironment();
+    AllocateEnvironmentData(e, STRAYFACTS_DATA, sizeof(LOPTR_ITEM ***), NULL);
+    /* STRAYFACTS_DATA will contain just a copy of the pointer to the map */
+    hm = (LOPTR_ITEM ***)GetEnvironmentData(e, STRAYFACTS_DATA);
+    *hm = clips_StrayFacts;     /* no real thin ice, it was allocated */
+#endif /* USE_NONASSERT_CLIPSGCLOCK */
+
+    /* add the Python router to the engine */
+    AddRouter("python", 0,
+              clips_queryFunction,
+              clips_printFunction,
+              clips_getcFunction,
+              clips_ungetcFunction,
+              clips_exitFunction);
+    ActivateRouter("python");
+
+}
+
+
+/* end */
diff --git a/clipsmodule.h b/clipsmodule.h
new file mode 100644
index 0000000..dd5b919
--- /dev/null
+++ b/clipsmodule.h
@@ -0,0 +1,119 @@
+/*
+ * clipsmodule.h
+ *
+ * common header file for CLIPS python module
+ * $Id: clipsmodule.h 340 2008-02-21 00:39:34Z Franz $
+ * (c) 2002-2008 - Francesco Garosi/JKS
+ */
+
+/* LICENSE INFORMATION
+
+# (c) 2002-2008 Francesco Garosi/JKS
+# The author's copyright is expressed through the following notice, thus
+# giving effective rights to copy and use this software to anyone, as shown
+# in the license text.
+#
+# NOTICE:
+#  This software is released under the terms of the GNU Lesser General Public
+#  license; a copy of the text has been released with this package (see file
+#  _license.py, where the license text also appears), and can be found on the
+#  GNU web site, at the following address:
+#
+#           http://www.gnu.org/copyleft/lesser.html
+#
+#  Please refer to the license text for any license information. This notice
+#  has to be considered part of the license, and should be kept on every copy
+#  integral or modified, of the source files. The removal of the reference to
+#  the license will be considered an infringement of the license itself.
+
+*/
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#ifndef _CLIPS_H_
+#include <clips.h>
+#include <prcdrfun.h>
+#include <strngfun.h>
+#include <factfun.h>
+#include "clips_or.h"
+#define _CLIPS_H_
+#endif
+
+#ifndef __PYTHON_H_CLIPS__
+#include <Python.h>
+#define __PYTHON_H_CLIPS__
+#endif
+
+#ifndef __SETJMP_H_CLIPS__
+#include <setjmp.h>
+#define __SETJMP_H_CLIPS__
+#endif
+
+#ifdef __cplusplus
+#define PYFUNC extern "C"
+#else
+#define PYFUNC
+#endif
+
+#if (CLIPS_MAJOR == 6 && CLIPS_MINOR < 23)
+#error "at least CLIPS v6.23 is required"
+#endif
+
+/* these are needed to define manifest constants */
+#if (CLIPS_MAJOR == 6 && CLIPS_MINOR < 24)
+#define NO_DEFAULT 0
+#define STATIC_DEFAULT  1
+#define DYNAMIC_DEFAULT 2
+#endif
+
+
+/* True/False symbols */
+#define CLIPS_TRUE_SYMBOL TrueSymbol()
+#define CLIPS_FALSE_SYMBOL FalseSymbol()
+#define ECLIPS_TRUE_SYMBOL(_e) EnvTrueSymbol(_e)
+#define ECLIPS_FALSE_SYMBOL(_e) EnvFalseSymbol(_e)
+
+
+/* configuration: initial and default values that could be modified */
+#define INITIAL_PPBUFFER_SIZE 8192      /* pretty print buffer size */
+#define INITIAL_MAX_ENVIRONMENTS 256    /* maximum number of environments */
+
+/* size of the hash table used to keep track of facts: should be prime */
+#define STRAY_FACTS_TABLE_SIZE 9973
+
+
+/* always inhibit CLIPS garbage collection except when it's forced */
+/* #define USE_CLIPSGCLOCK */
+
+/* lock CLIPS garbage collection when there are non-asserted facts around */
+#define USE_NONASSERT_CLIPSGCLOCK
+
+/* allow Clear() to reset PyCLIPS garbage collection counters */
+#define USE_CLEAR_RESETGCCOUNTERS
+
+/* use 'dummy' unaccessible system objects to force memory release at exit */
+#define USE_TEST_DEALLOC_ENV
+
+/* declare some variables as 'register' in hope to speed up */
+#define USE_REGISTER_VARIABLES
+
+
+/* ATTENTION:
+ * The following flags only have effect when the 'test' patch set is applied
+ * to the CLIPS source (this is enabled by default); otherwise even defining
+ * the following symbols does not impact the module functionality.
+ */
+
+/* use Python memory allocator in CLIPS too (affects performance) */
+#define USE_PYTHON_MEMMGR
+
+/* handle memory errors using setjmp/longjmp (affects performance) */
+#define USE_MEMORY_ERROR_HANDLER
+
+/* enable suppression of fatal errors written on stderr (stdout) */
+#define USE_FATAL_ERROR_INHIBITION
+
+
+/* end */
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index 56e7b37..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,18 +0,0 @@
-python-clips (1.0.7.348+clips-2) unstable; urgency=medium
-
-  * Team upload
-  * make the build reproducible (Thanks for the patch to Reiner Herrmann
-    <reiner at reiner-h.de>)
-    Closes: #843100
-  * debhelper 10
-  * d/watch: version=4
-  * cme fix dpkg-control
-
- -- Andreas Tille <tille at debian.org>  Wed, 23 Nov 2016 16:06:51 +0100
-
-python-clips (1.0.7.348+clips-1) unstable; urgency=low
-
-  * initial version (Closes: #577406)
-
- -- Thorsten Alteholz <debian at alteholz.de>  Mon, 08 Apr 2013 18:00:07 +0100
-
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index f599e28..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-10
diff --git a/debian/control b/debian/control
deleted file mode 100644
index 41942f7..0000000
--- a/debian/control
+++ /dev/null
@@ -1,23 +0,0 @@
-Source: python-clips
-Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
-Uploaders: Thorsten Alteholz <debian at alteholz.de>
-Section: python
-Priority: optional
-Build-Depends: debhelper (>= 10),
-               python-all-dev
-Standards-Version: 3.9.8
-Vcs-Browser: https://anonscm.debian.org/viewvc/debian-med/trunk/packages/python-clips/trunk/
-Vcs-Svn: svn://anonscm.debian.org/debian-med/trunk/packages/python-clips/trunk/
-Homepage: http://sourceforge.net/projects/pyclips/
-
-Package: python-clips
-Architecture: any
-Depends: ${shlibs:Depends},
-         ${misc:Depends},
-         ${python:Depends}
-Provides: ${python:Provides}
-Description: Python module to interface the CLIPS expert system shell library
- CLIPS is an expert system shell / inference engine written by NASA 
- (see Debian package clips).
- .
- pyclips are the Python bindings to that engine.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index c586313..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,64 +0,0 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: pyclips
-Source:  http://sourceforge.net/projects/pyclips/
-
-Files: *
-Copyright: 2002-2008 Francesco Garosi/JKS
-License: LGPL-2
-
-Files: CLIPSSrc.zip
-Copyright: 2006 Barry Cameron, Bebe Ly, Brian L. Donnell, 
-                Chris Culbert, Gary D. Riley
-License: CLIPS
-
-Files: debian/*
-Copyright: 2013 Thorsten Alteholz <debian at alteholz.de>
-License: GPL-2.0+
-
-License: GPL-2.0+
- This package is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- .
- This package is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
- .
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>
- .
- On Debian systems, the complete text of the GNU General
- Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
-
-License: LGPL-2
- On Debian systems, the complete text of the GNU Lesser General
- Public License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2".
-
-License: CLIPS
- CLIPS License Information
- .
- 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, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so.
- .
- 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 OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
- INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
- .
- CLIPS is released as public domain software and as such you are under no
- obligation to pay for its use. However, if you derive commercial or
- monetary benefit from use of the software or just want to show support,
- please consider making a voluntary payment based on the worth of the
- software to you as compensation for the time and effort required to
- develop and maintain CLIPS. Payments can be made online at
- http://order.kagi.com/?JKT.
diff --git a/debian/get-orig-source b/debian/get-orig-source
deleted file mode 100644
index f06bb52..0000000
--- a/debian/get-orig-source
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/bash
-
-# bail out upon error
-set -e
-
-PACKAGE=`dpkg-parsechangelog | awk '/^Source/ { print $2 }'`
-TARDIR=../tarballs
-mkdir -p $TARDIR
-
-VERSION=`uscan --rename --verbose --force-download |
-    grep "Newest version on remote site is .* local version is .*" |
-    head -n 1 |
-    sed "s/Newest version on remote site is \([a-z0-9.]\+\),.*/\1/"`
-
-mkdir -p $TARDIR
-cd $TARDIR
-
-UTAR="${PACKAGE}_${VERSION}.orig.tar.gz"
-mv ../${UTAR} .
-tar -xzf ${UTAR}
-
-mv pyclips ${PACKAGE}_${VERSION}+clips.orig # .orig is requested by Developers Reference 3.4.4 <C2><A7>6.7.8.2
-
-cd ${PACKAGE}_${VERSION}+clips.orig
-wget http://pyclips.sourceforge.net/files/CLIPSSrc.zip
-
-cd ..
-rm $UTAR
-
-BZIP2="--best" tar -cjf ${PACKAGE}_${VERSION}+clips.orig.tar.bz2 ${PACKAGE}_${VERSION}+clips.orig
-rm -rf ${PACKAGE}_${VERSION}+clips.orig
-
diff --git a/debian/patches/reproducible-build.patch b/debian/patches/reproducible-build.patch
deleted file mode 100644
index ae62f03..0000000
--- a/debian/patches/reproducible-build.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-Author: Reiner Herrmann <reiner at reiner-h.de>
-Description: Sort source files for deterministic linking order
-
---- a/setup.py
-+++ b/setup.py
-@@ -780,7 +780,7 @@
-     'userfunctions.c',
-     ]
- 
--all_clipssrc = glob(_p(ClipsLIB_dir, '*.c'))
-+all_clipssrc = sorted(glob(_p(ClipsLIB_dir, '*.c')))
- main_clipssrc = ['clipsmodule.c', 'clips_or.c']
- for x in all_clipssrc:
-     if os.path.basename(x) in TO_REMOVE:
diff --git a/debian/patches/series b/debian/patches/series
deleted file mode 100644
index 55077d0..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1 +0,0 @@
-reproducible-build.patch
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index 7459fc7..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/make -f
-
-# DH_VERBOSE := 1
-
-%:
-	dh $@ --with python2
-
-override_dh_clean:
-	dh_clean
-	rm -rf clipssrc
-	rm -f clips/_eclips_wrap.py
-	rm -f clips/_version.py
-
-override_dh_auto_install:
-	dh_auto_install
-	dh_installchangelogs README
-
-get-orig-source:
-	./debian/get-orig-source
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index 12b0140..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,2 +0,0 @@
-version=4
-http://sf.net/pyclips/pyclips-([\d.]+)\.tar\.gz
diff --git a/doc/appendix.tex b/doc/appendix.tex
new file mode 100644
index 0000000..9a97e02
--- /dev/null
+++ b/doc/appendix.tex
@@ -0,0 +1,731 @@
+% $Id: appendix.tex 346 2008-02-25 00:39:00Z Franz $
+\appendix
+
+\chapter{Usage Notes\label{pyclips-unotes}}
+
+\section{Environments\label{pyclips-unotes-env}}
+
+As seen in the detailed documentation, \pyclips{} also provides access
+to the \emph{environment} features of CLIPS, through the
+\class{Environment} class. \class{Environment} objects provide almost
+all functions normally available at the top level of \pyclips{}, that is
+importing \code{clips} into a Python script. \class{Environment} object
+methods having the same name of functions found at the top level of
+\pyclips{}, have the same effect of the corresponding function -- but
+restricted to the logical environment represented by the object
+itself\footnote{In fact, the Python submodule that implements the
+\class{Environment} class is generated automatically: the process can be
+examined by looking at the code in \file{setup.py} and
+\file{clips/_clips_wrap.py}.}. Normally in a true CLIPS session users would
+not use environments, so the concept of environment may, in many cases,
+not be useful.
+
+There are also functions (namely: \function{CurrentEnvironment()} and
+\function{Environment.SetCurrent()}) that allow the user to switch
+environment and to use top level functions and classes in any of the
+created environments. This is useful in cases where environments are used,
+because due to the double nature of CLIPS API (see \clipsapg{} about
+\emph{companion functions} for standard API), objects defined in
+environments have slightly different types than corresponding top level
+objects -- since these types are \emph{environment-aware}. However
+environment aware classes define exactly the same methods as the top
+level counterparts, so their logical use is the same.
+
+\begin{notice}
+Please note that the \function{CurrentEnvironment()} function returns
+a fully functional \class{Environment} object. However the system
+prevents\footnote{Raising an appropriate exception.} invasive access via
+\emph{environment-aware} functions to current \emph{environment}: user
+code should \emph{always} use functions defined at module level to access
+current \emph{environment}. The \class{Environment} methods become safe
+as soon as another \class{Environment} has become current -- and in this
+case its methods and properties will raise an error.
+\end{notice}
+
+\class{Environment}s are a limited resource: this is because it is
+impossible in \pyclips{} to destroy a created \class{Environment}.
+In order to reuse \class{Environment}s it may be useful to keep a
+reference to each of them for the whole \pyclips{} session. If there
+is an attempt to create more \class{Environment}s than allowed, an
+exception is raised.
+
+
+
+\section{Multiple Ways\label{pyclips-unotes-multiw}}
+
+There is more than one way to use the \pyclips{} module, since it exposes
+almost all the API functions of CLIPS, seen in fact as a library, to the
+Python environment.
+
+The module \pyclips{} provides some functions, that is \function{Build()}
+and \function{Eval()}, that let the user directly issue commands in the
+CLIPS subsystem from a Python program. In fact, the use of \function{Build()}
+allows definition of constructs in CLIPS\footnote{Note that the
+\function{Build()} function does not return any value or object, so you
+will have to call \function{Find\emph{Construct}()} to find entities created
+using the \function{Build()} function.}, and \function{Eval()} lets the user
+evaluate values or call code directly in the subsystem. So for instance
+rules can be built in \pyclips{} using
+
+\begin{verbatim}
+>>> import clips
+>>> clips.Build("""
+(defrule duck-rule "the Duck Rule"
+   (duck)
+   =>
+   (assert (quack)))
+""")
+>>> clips.PrintRules()
+MAIN:
+duck-rule
+\end{verbatim}
+
+and evaluate a sum using
+
+\begin{verbatim}
+>>> n = clips.Eval("(+ 5 2)")
+>>> print n
+7
+\end{verbatim}
+
+Also, the user is allowed to call functions that do not return a value
+using \function{Eval()}\footnote{There is a discussion about functions
+that only have \emph{side effects} in CLIPS, such as \code{printout}, in
+\clipstut{}, that is, the CLIPS tutorial.}, as in the following example:
+
+\begin{verbatim}
+>>> clips.Eval('(printout t "Hello, World!" crlf)')
+>>> print clips.StdoutStream.Read()
+Hello, World!
+\end{verbatim}
+
+There is another function, namely \function{SendCommand()}, that sends
+an entire CLIPS command (it has to be a full, correct command, otherwise
+\pyclips{} will issue an exception): as \function{Build()} it does not
+return any value or object\footnote{Some information about the command
+result can be retrieved reading the appropriate output streams.}.
+However this can be particularly useful when the user needs to implement
+an interactive CLIPS shell within an application built on \pyclips{}.
+Unless the application is mostly CLIPS oriented (if for instance Python
+is used just as a ``glue'' script language) probably the use of this
+function has to be discouraged, in favour of the code readability that
+-- at least for Python programmers -- is provided by the Python oriented
+interface.
+
+Using \function{SendCommand()} it becomes possible to write:
+
+\begin{verbatim}
+>>> import clips
+>>> clips.SendCommand("""
+(defrule duck-rule "the Duck Rule"
+   (duck)
+   =>
+   (assert (quack)))
+""")
+>>> clips.SendCommand("(assert (duck))")
+>>> clips.Run()
+>>> clips.PrintFacts()
+f-0     (duck)
+f-1     (quack)
+For a total of 2 facts.
+>>> clips.PrintRules()
+MAIN:
+duck-rule
+\end{verbatim}
+
+The most important caveat about \function{SendCommand()} is that CLIPS
+accepts some kinds of input which normally have to be considered
+incorrect, and \pyclips{} does neither return an error value, nor raise
+an exception: for instance, it is possible to pass a symbol to CLIPS to
+the command line as in
+
+\begin{verbatim}
+CLIPS> thing
+thing
+\end{verbatim}
+
+and in this case CLIPS ``evaluates'' the symbol, printing it to the
+console as a result of the evaluation. \pyclips{} does not automatically
+capture evaluation output, and just accepts a symbol (or other commands
+that can be evaluated) as input without any production:
+
+\begin{verbatim}
+>>> import clips
+>>> clips.SendCommand("thing")
+\end{verbatim}
+
+but, turning on the verbosity flag:
+
+\begin{verbatim}
+>>> clips.SendCommand("thing", True)
+>>> print clips.StdoutStream.Read()
+thing
+\end{verbatim}
+
+Of course, \pyclips{} complains if something incorrect is passed to the
+\function{SendCommand()} function and raises an exception as previously
+stated. However the exception is accompanied by a rather non-explanatory
+text. The \var{ErrorStream} object should be queried in this case in order
+to obtain some more information about the error:
+
+\begin{verbatim}
+>>> clips.SendCommand("(assert (duck)")	# no right bracket
+
+Traceback (most recent call last):
+  File "<pyshell#5>", line 1, in -toplevel-
+    clips.SendCommand("(assert (duck)")	# no right bracket
+  File ".../_clips_wrap.py", line 2575, in SendCommand
+    _c.sendCommand(s)
+ClipsError: C09: unable to understand argument
+>>> print clips.ErrorStream.Read()
+
+[PRNTUTIL2] Syntax Error:  Check appropriate syntax for RHS patterns.
+\end{verbatim}
+
+Obviously \function{SendCommand()} can lead to serious errors if not
+used with some kind of interaction.
+
+The point of this paragraph is that, for entity definition (evaluation
+can only be performed using the \function{Eval()} or \function{Call()}
+functions), the \pyclips{} module provides a full set of specific
+\function{Build\emph{Entity}()} functions which also return appropriate
+objects corresponding to specific entities. So, the task of building a
+\emph{rule} in CLIPS (in fact, a \class{Rule} object in Python) could
+preferably be performed directly using the \function{BuldRule()}
+function, that is:
+
+\begin{verbatim}
+>>> clips.Clear()
+>>> clips.Reset()
+>>> r0 = clips.BuildRule("duck-rule", "(duck)", "(assert (quack))",
+                         "the Duck Rule")
+>>> print r0.PPForm()
+(defrule MAIN::duck-rule "the Duck Rule"
+   (duck)
+   =>
+   (assert (quack)))
+
+>>> clips.PrintRules()
+MAIN:
+duck-rule
+\end{verbatim}
+
+thus with the same effect as with the \function{Build()} function, but
+obtaining immediately a reference to the rule entity in CLIPS as a Python
+object. Similar examples could be provided for the \function{SendCommand()}
+function, using the appropriate constructs or commands that can be used
+to achieve the same goals.
+
+This allows the user to choose between at least two programming styles in
+\pyclips{}: the former, more CLIPS oriented, relies heavily on the use of
+the \function{Build()}, \function{Eval()} and \function{SendCommand()}
+functions, and is probably more readable to CLIPS developers. The latter
+is somewhat closer to Python programming style, based on the creation of
+objects of a certain nature by calling specific Python functions. The
+advice is to avoid mixing the two styles unless necessary, since it can
+make the code quite difficult to understand.
+
+
+
+\section{Python Functions in CLIPS\label{pyclips-unotes-pyfuncs}}
+
+In \pyclips{} it is possible to execute Python functions from within
+CLIPS embedded constructs and statements. This allows the extension of
+the underlying inference engine with imperative functionalities, as well
+as the possibility to retrieve information from the Python layer
+asynchronously with respect to Python execution. Of course this
+possibility enables some enhancements of the CLIPS environment, but
+-- as a drawback -- it also opens the way to errors and misunderstandings.
+
+Usage of Python external functions is fairly simple: the user should
+register functions that will be called from within the CLIPS subsystem
+in \pyclips{} using the \function{RegisterPythonFunction()} toplevel
+function. If no alternate name for the function is specified, then the
+Python name will be used\footnote{An example of function registration
+has been provided in the introduction.}. If necessary, Python function
+names can be deregistered using \function{UnregisterPythonFunction()} and
+\function{ClearPythonFunctions()} utilities. Once a function is registered
+it can be called from within the CLIPS engine using the following syntax:
+
+\begin{verbatim}
+    (python-call <funcname> [arg1 [arg2 [ ... [argN]]]])
+\end{verbatim}
+
+and will return a value (this allows its use in assignments) to the CLIPS
+calling statement. In the call, \code{<funcname>} is a \emph{symbol}
+(using a string will result in an error) and the number and type of
+arguments depends on the actual Python function. When arguments are of
+wrong type or number, the called function fails. Using the previously
+illustrated \function{py_square} example, we have:
+
+\begin{verbatim}
+>>> clips.RegisterPythonFunction(py_square)
+>>> clips.SetExternalTraceback(True)	# print traceback on error
+>>> print clips.Eval("(python-call py_square 7)")
+49
+>>> print clips.Eval('(python-call py_square "a")')
+Traceback (most recent call last):
+  File ".../_clips_wrap.py", line 2702, in <lambda>
+    f = lambda *args: _extcall_retval(func(*tuple(map(_cl2py, list(args)))))
+  File "<pyshell#85>", line 2, in py_square
+TypeError: can't multiply sequence to non-int
+FALSE
+>>> print clips.Eval("(python-call py_square 7 7)")
+Traceback (most recent call last):
+  File ".../_clips_wrap.py", line 2702, in <lambda>
+    f = lambda *args: _extcall_retval(func(*tuple(map(_cl2py, list(args)))))
+TypeError: py_square() takes exactly 1 argument (2 given)
+FALSE
+\end{verbatim}
+
+It is important to know, in order to avoid errors, that the Python
+interpreter that executes functions from within CLIPS is exactly the
+same that calls the \pyclips{} function used to invoke the engine: this
+means, for example, that a Python function called in CLIPS is subject
+to change the state of the Python interpreter itself. Moreover, due
+to the nature of CLIPS external function call interface, Python functions
+called in CLIPS will never raise exceptions\footnote{Exceptions can
+arise \emph{during} the Python function execution, and can be caught
+inside the function code. However, for debugging purposes, there is the
+possibility to force \pyclips{} print a standard traceback whenever an
+error occurs in a Python function called by CLIPS.} in the Python calling
+layer.
+
+Here are some other issues and features about the nature of the external
+function call interface provided by \pyclips{}:
+
+\emph{Functions should be CLIPS-aware:} when CLIPS calls a Python external
+function with arguments, these are converted to values that Python can
+understand using the previously described \emph{wrapper classes}. Thus,
+for instance, if the Python function is given an integer argument, then
+an argument of type \class{Integer} (not \class{int}) will be passed as
+actual parameter. This means that in most cases \pyclips{} has to be
+imported by modules that define external Python functions.
+
+\emph{Actual parameters cannot be modified:} there is no way to pass values
+back to CLIPS by modifying actual parameters. The possibility to use
+\class{Multifield} parameters as lists should not deceive the user, as
+every modification performed on \class{Multifield}s that Python receives
+as parameters will be lost after function completion. A way to handle this
+is to treat parameters as \emph{immutable} values.
+
+\emph{External functions should always return a value:} functions always
+return a value in CLIPS, even in case of an error. This can be clearly
+seen in the following chunk of CLIPS code:
+
+\begin{verbatim}
+CLIPS> (div 1 0)
+[PRNTUTIL7] Attempt to divide by zero in div function.
+1
+\end{verbatim}
+
+where, although an error message is printed to the console, the value
+\constant{1} is returned by the system. In the same way, CLIPS expects
+Python external functions to return a value. \pyclips{} solves this issue
+by converting a return value of \constant{None} (which is the real return
+value for Python functions that simply \code{return}) into the symbol
+\code{nil}, that has a meaning similar to the one of \constant{None} for
+Python. Also, functions that raise uncaught exceptions will in fact return
+a value to the underlying CLIPS engine: in this case the returned value
+is the symbol \code{FALSE}, and an error message is routed to the error
+stream -- thus, it can be retrieved using \function{ErrorStream.Read()}.
+The following example imitates the \code{div} CLIPS example above:
+
+\begin{verbatim}
+>>> import clips
+>>> exceptor = lambda : 1 / 0
+>>> clips.RegisterPythonFunction(exceptor, 'exceptor')
+>>> clips.SetExternalTraceback(True)	# print traceback on error
+>>> clips.Eval('(python-call exceptor)')
+Traceback (most recent call last):
+  File ".../_clips_wrap.py", line 2702, in <lambda>
+    f = lambda *args: _extcall_retval(func(*tuple(map(_cl2py, list(args)))))
+  File "<pyshell#79>", line 1, in <lambda>
+ZeroDivisionError: integer division or modulo by zero
+<Symbol 'FALSE'>
+\end{verbatim}
+
+\emph{Return values must be understood by CLIPS:} only values that can
+be converted to CLIPS base types can be returned to the inference engine.
+This includes all values that can be converted to \pyclips{} \emph{wrapper
+classes}. In fact it can be considered a good practice to cast return
+values to \pyclips{} \emph{wrapper classes} when the main purpose of a
+function is to be called from within CLIPS.
+
+\emph{Python functions act as generic functions:} due to the nature of
+Python, functions are generally polymorphic:
+
+\begin{verbatim}
+>>> def addf(a, b):
+        return a + b
+>>> print addf("egg", "spam")
+eggspam
+>>> print addf(2, 4)
+6
+\end{verbatim}
+
+The intrinsic polymorphism of Python functions is kept within the CLIPS
+subsystem:
+
+\begin{verbatim}
+>>> import clips
+>>> clips.RegisterPythonFunction(addf)
+>>> print clips.Eval('(python-call addf "egg" "spam")')
+eggspam
+>>> print clips.Eval('(python-call addf 2 4)')
+6
+\end{verbatim}
+
+Thus Python functions act in a way that is similar to \code{generic}s.
+
+
+
+\chapter{The \module{clips._clips} Submodule\label{pyclips-llclips}}
+
+It has been said throughout the whole document that there are two
+different ``natures'' of \pyclips{}, called the \emph{high level module}
+and the \emph{low level module}. The former has been described in detail
+here, and is supposed to be the main interface to CLIPS. However, since
+all communication between Python and the CLIPS subsystem is implemented
+in the \emph{low level} part, some users might find it useful to access
+this interface instead of the \emph{higher level} one. It is not the
+intention of this manual to provide documentation for the \emph{low
+level} \module{clips._clips} interface, but only to give some indications
+to users who already have experience of the CLIPS C interface.
+
+Submodule \module{clips._clips} provides low-level classes that have the
+same names as their counterparts in CLIPS, such as \class{fact},
+\class{deftemplate} and so on. Also, \module{clips._clips} defines an
+\class{environment} class to refer to \emph{environment} addresses.
+
+Almost all functions described in \clipsapg{} are ported to Python,
+except for missing features described below: the name is the same as in
+the reference guide, except for the first letter that is not
+capitalized\footnote{There can be some exceptions: the most
+important one is the assertion function, since Python already has an
+\keyword{assert} keyword. This function is called \function{assertFact}
+instead.}. CLIPS ``top level'' functions have been ported to
+\module{clips._clips} as well as \emph{companion functions} that accept
+an \class{environment} instance as the first argument\footnote{When
+trying to show the \emph{documentation string} of these functions, the
+first argument is not described because their code has been generated
+automatically.}, whose name begins with \code{env_} followed by the same
+name as the corresponding top level function.
+
+\emph{Low level} functions are documented by themselves through
+\emph{documentation strings}, that describe purpose, arguments and return
+values. For instance, let's show the documentation of a function:
+
+\begin{verbatim}
+>>> import clips
+>>> cl = clips._clips
+>>> print cl.listDeftemplates.__doc__
+listDeftemplates(logicalname [, module])
+list deftemplates to output identified by logicalname
+arguments:
+  logicalname (str) - the logical name of output
+  module (module) - the module to inspect, all modules if omitted
+\end{verbatim}
+
+Most low level function documentation strings, i.e. the ones given
+for functions that are not trivially identifiable with the CLIPS API
+counterparts\footnote{Some functions have a documentation string that
+actually refers to the CLIPS API itself, explicitly containing the words
+``\emph{equivalent of C API}'' and the C function name: \clipsapg{} is
+especially useful in this case.}, have this form and describe in detail
+arguments and return values. Users who want to benefit of these
+functions, can display \emph{documentation strings} as a reference.
+
+The underlying engine is the same, there is no separation of environment
+between the two interfaces. Operations performed at \emph{lower level}
+are obviously reflected in the \emph{higher level} layer, as in the
+following example:
+
+\begin{verbatim}
+>>> clips.Clear()
+>>> cl.facts("stdout")
+>>> s = clips.StdoutStream.Read()
+>>> print s
+None
+>>> print cl.assertString.__doc__
+assertString(expr) -> fact
+assert a fact into the system fact list
+returns: a pointer to the asserted fact
+arguments:
+  expr (str) - string containing a list of primitive datatypes
+>>> f = cl.assertString("(duck)")
+>>> clips.PrintFacts()
+f-0     (duck)
+For a total of 1 fact.
+\end{verbatim}
+
+so the two interfaces can be used interchangeably.
+
+
+
+\chapter{Error Codes\label{pyclips-errors}}
+
+It has been discussed above, that some of the \pyclips{} functions can
+raise a CLIPS specific exception, namely \exception{ClipsError}. Some
+of the exceptions of this type (in fact, the ones raised by the
+underlying CLIPS engine and caught at the lower level), come with an
+error code in the accompanying text. A brief description of exceptions
+that arise at low level follows:
+
+\begin{tableii}{l|l}{code}{Code}{Description}
+	\lineii{P01}{An object could not be created, due to memory
+            issues}
+	\lineii{C01}{The engine could not create a system object}
+	\lineii{C02}{The referred object could not be found in
+            subsystem}
+	\lineii{C03}{An attempt was made to modify an unmodifiable
+            object}
+	\lineii{C04}{A file could not be opened}
+	\lineii{C05}{The current environment could not be retrieved}
+	\lineii{C06}{The engine was unable to return the required value}
+	\lineii{C07}{Parse error in the passed in CLIPS file}
+	\lineii{C08}{Syntax or parse error in the passed in CLIPS
+            expression}
+	\lineii{C09}{Syntax or parse error in the passed in argument}
+	\lineii{C10}{Expression could not be evaluated, maybe because of
+            syntax errors}
+	\lineii{C11}{An object could not be removed from the CLIPS
+            subsystem}
+	\lineii{C12}{A fact could not be asserted, maybe because of
+            missing \code{deftemplate}}
+	\lineii{C13}{Iteration beyond last element in a list}
+	\lineii{C14}{A CLIPS function has been called unsuccessfully}
+	\lineii{C15}{Attempt to modify an already asserted fact was made}
+	\lineii{C16}{Cannot destroy environment while it is current}
+	\lineii{C90}{Other errors: specific description given}
+	\lineii{C97}{The feature is present when a higher version of
+            CLIPS is used}
+	\lineii{C98}{An attempt was made to use an unimplemented feature
+            (see below)}
+	\lineii{C99}{Generic CLIPS error, last operation could not be
+            performed}
+	\lineii{C00}{Generic CLIPS error, no specific cause could be
+            reported}
+        \lineii{S01}{Attempt to access a fact that is no longer valid
+            or has been deleted}
+        \lineii{S02}{Attempt to access an instance that is no longer
+            valid or has been deleted}
+        \lineii{S03}{Clear operation on an environment has failed}
+        \lineii{S04}{Attempt to access an environment that has been
+            deleted}
+        \lineii{S05}{Attempt to operate on alias of current environment}
+        \lineii{S06}{Attempt to create more environments than allowed}
+        \lineii{S00}{Generic internal system error}
+        \lineii{R01}{The logical buffer (I/O Stream) has been misused}
+	\lineii{R02}{The logical buffer with given name could not be
+            found}
+	\lineii{R03}{Could not write to a read-only logical buffer}
+\end{tableii}
+
+These codes can be extracted from the exception description and used to
+determine errors -- for instance, in an \code{if ... elif ...} control
+statement. Some of these errors are caught by the \pyclips{} high-level
+layer and interpreted in different ways (e.g. the \code{C13} error is
+used to generate lists or to return \constant{None} after last element
+in a list).
+
+There are also some CLIPS specific exceptions that can be thrown at the
+higher level: they are identified by a code beginning with the letter
+\code{M}. A list of these exceptions follows, along with their
+description:
+
+\begin{tableii}{l|l}{code}{Code}{Description}
+        \lineii{M01}{A constructor could not create an object}
+        \lineii{M02}{An object could not be found in the CLIPS subsystem}
+        \lineii{M03}{An attempt was made to \function{pickle} an object}
+        \lineii{M99}{Wrong Python version, module could not initialize}
+\end{tableii}
+
+Finally, there is a particular error that occurs in case of \emph{fatal}
+memory allocation failures, which is identified by a particular
+exception, namely \exception{ClipsMemoryError}. This excepion is raised
+with the following code and has the following meaning:
+
+\begin{tableii}{l|l}{code}{Code}{Description}
+        \lineii{X01}{The CLIPS subsystem could not allocate memory}
+\end{tableii}
+
+In this case the calling program \emph{must} exit, as the underlying
+engine has reached an unstable state. An exception different from the
+standard \exception{ClipsError} has been provided in order to allow
+quick and effective countermeasures\footnote{Please note that in some
+cases, and depending on how the operating system treats memory
+allocation failures, the Python interpreter too could loose stability
+in case of memory shortage.}.
+
+
+
+\chapter{Multithreading\label{pyclips-threading}}
+
+The CLIPS engine is a separate subsystem, as stated many times before.
+In other words, it maintains a state independently from what happens in
+the Python interpreter. This also means that, since CLIPS was never
+conceived to be used as a multithreaded library, multiple threads should
+not try to access the engine concurrently. The Python interpreter, due
+to its nature, does not actually allow concurrent calls to the low-level
+module, so it is safe to create concurrent threads that interact with
+\pyclips{}.
+
+However this has the side effect that, during a time consuming task
+(such as calling \function{Run()} on a complex set of rules and facts)
+the calling thread may block the other ones.
+
+A partial solution to this, to allow multiple threads to switch more
+reactively, is to call \function{Run()} with the \var{limit} parameter,
+which specifies the number of rules to be fired at once. Of course this
+allows subsequent calls to the CLIPS engine to modify its state, and
+consequently enables execution paths that could be different from the
+ones that a full CLIPS \code{(run)} would normally cause. Obviously
+this only applies to the \function{Run()} function.
+
+The consideration also implies that multithreaded Python applications
+should take care of examining the engine state before interacting with
+it, especially when splitting \function{Run()} (which normally modifies
+the state) in multiple calls.
+
+
+
+\chapter{Missing Features\label{pyclips-missing}}
+
+Most of the CLIPS API is implemented in \pyclips{}. The \emph{lower
+level} interface (which directly maps CLIPS exposed functions as
+described in \clipsapg{}) can be accessed using the
+\module{clips._clips} submodule. Almost all the functions defined here
+have a counterpart in the CLIPS API, and a combined use of documentation
+strings and \clipsapg{} itself can allow you to directly manipulate the
+CLIPS subsystem as you would have done by embedding it in a C program.
+However, there are some functions that appear in \code{dir(clips._clips)}
+but, when called, issue an error:
+
+\begin{verbatim}
+>>> clips._clips.addClearFunction()
+Traceback (most recent call last):
+  File "<pyshell#46>", line 1, in ?
+    clips._clips.addClearFunction()
+ClipsError: C98: unimplemented feature/function
+\end{verbatim}
+
+and in fact, even their documentation string reports
+
+\begin{verbatim}
+>>> print clips._clips.addClearFunction.__doc__
+unimplemented feature/function
+\end{verbatim}
+
+even if the name of the function is defined and is a \emph{callable}.
+
+A list of such functions follows:
+
+\begin{tableii}{l|l}{code}{Function}{Type}
+	\lineii{addClearFunction}{execution hook}
+	\lineii{addPeriodicFunction}{execution hook}
+	\lineii{addResetFunction}{execution hook}
+	\lineii{removeClearFunction}{execution hook}
+	\lineii{removePeriodicFunction}{execution hook}
+	\lineii{removeResetFunction}{execution hook}
+	\lineii{addRunFunction}{execution hook}
+	\lineii{removeRunFunction}{execution hook}
+	\lineii{decrementFactCount}{reference count handler}
+	\lineii{incrementFactCount}{reference count handler}
+	\lineii{decrementInstanceCount}{reference count handler}
+	\lineii{incrementInstanceCount}{reference count handler}
+	\lineii{setOutOfMemoryFunction}{memory handler hook}
+	\lineii{addEnvironmentCleanupFunction}{execution hook}
+	\lineii{allocateEnvironmentData}{memory handler}
+	\lineii{deallocateEnvironmentData}{memory handler}
+	\lineii{destroyEnvironment}{environment destructor}
+	\lineii{getEnvironmentData}{memory handler}
+\end{tableii}
+
+The description of these functions is outside the scope of this guide,
+and can be found in \clipsapg{} of CLIPS. It is not likely that these
+functions will be implemented even in future versions of \pyclips{} since
+Python programmers are usually not interested in dealing with low level
+memory handling (which is the primary use of the memory oriented
+functions), and tasks like reference count handling are performed
+directly by Python itself (for Python objects which shadow CLIPS
+entities) and by the low level \pyclips{} submodule. Also, the functions
+referred to above as \emph{execution hooks} often have to deal with CLIPS
+internal structures at a very low level, so they would be of no use in a
+Python program.
+
+Other API functions, which are used internally by \pyclips{} (for
+instance the \function{InitializeEnvironment()} C function), are not
+implemented in the module.
+
+\begin{notice}
+Some of the features (either in current and possibly in further versions
+of \pyclips{}) may depend on the version of CLIPS that is used to compile
+the module. Using the most recent stable version of CLIPS is recommended
+in order to enable all \pyclips{} features. Features that are excluded
+from the module because of this reason will issue an exception, in which
+the exception text reports the following: \code{"C97: higher engine
+version required"}. Moreover, the CLIPS engine version may affect the
+behaviour of some functions. Please consider reading the documentation
+related to the used CLIPS version when a function does not behave as
+expected.
+\end{notice}
+
+
+\chapter{Installing \pyclips{}\label{pyclips-setup}}
+
+\section{Installation\label{pyclips-setup-installation}}
+
+To install \pyclips{} you should also download the full CLIPS source
+distribution. You will find a file called \file{CLIPSsrc.zip} at the
+CLIPS download location: you should choose to download this instead of
+the \UNIX{} compressed source, since the setup program itself performs
+the task of extracting the files to an appropriate directory with the
+correct line endings. The ZIP file format has been chosen in order to
+avoid using different extraction methods depending on the host operating
+system.
+
+\pyclips{} uses \module{distutils} or \module{setuptools} for its
+installation. So in all supported systems the module can be easily
+set up once the whole source has been extracted to a directory and
+the CLIPS source code has been put in the same place, by means of the
+following command:
+
+\begin{verbatim}
+# python setup.py install
+\end{verbatim}
+
+In fact recent versions of \pyclips{} will attempt to download the
+latest supported CLIPS source directly from the \pyclips{} web site
+if no CLIPS source package is found. Otherwise no attempt to connect
+to the Internet will be made. The \file{README} file provides more
+up-to-date and detailed information on the setup process.
+
+On \UNIX{}, if you have a system-wide Python distribution, your
+privileges for installation should be the same as the Python owner.
+
+The CLIPS library itself is compiled for a specific platform, since
+\file{setup.py} modifies the \file{setup.h} file in the CLIPS
+distribution. 
+
+\pyclips{} is known to build and pass the tests on \emph{Linux (x86 and
+x86_64)}\footnote{The x86_64 platforms requires some optional patches
+to be applied.}, \emph{Win32} (many flavours of it have been tested),
+\emph{Sun Solaris} with 32-bit gcc, \emph{FreeBSD}, \emph{Mac OS X} with
+\emph{Fink} and, using a customized build process, has been ported to the
+\emph{Sharp Zaurus (SA-1110)} platform.
+
+
+\section{Requirements\label{pyclips-setup-requirements}}
+
+\pyclips{} requires Python 2.4 or above to function: it uses decorators
+to check and enforce types where needed, and in some places it also uses
+modern aspects of the Python API.
+
+At least version 6.23 of CLIPS is required: it allows the definition and
+use of \emph{environments}, and the function and macro definitions are
+more conformant to the ones described in \clipsapg{}. Of course features
+present in CLIPS 6.24 are not available when using the previous CLIPS
+version, so if there is no particular reason to use it, please compile
+PyCLIPS with CLIPS 6.24, which also fixes some bugs.
+
diff --git a/doc/contents.tex b/doc/contents.tex
new file mode 100644
index 0000000..5cb2697
--- /dev/null
+++ b/doc/contents.tex
@@ -0,0 +1,702 @@
+% $Id: contents.tex 334 2008-01-12 04:10:30Z Franz $
+\chapter{Module Contents\label{pyclips-modulecontents}}
+
+This chapter gives a detailed description of top-level functions and
+constants in the \pyclips{} module. It's not intended to be a CLIPS
+reference: the official CLIPS Reference Guide still remains the main
+source of documentation for this. This Guide will often be referred to
+for information about the engine itself, and the user is expected to
+know the CLIPS language and structure sufficiently with respect to his
+goals.
+
+Although the \pyclips{} user is not supposed to know CLIPS API, it is
+advisable to have its reference at least at hand to sometimes understand
+\emph{how} \pyclips{} interacts with CLIPS itself. Besides the programmatic
+approach offered by \pyclips{} is vastly different to the C API -- with
+the occasional exception of the intrinsic logic.
+
+We will first describe the top level functions.
+
+\section{Top Level Functions and Constants\label{pyclips-toplevel}}
+
+\subsection{Constants\label{pyclips-tl-constants}}
+
+Several constants are provided in order to configure CLIPS environment
+or to instruct some functions to behave in particular ways.
+
+
+\subsubsection{Scope Save Constants}
+
+Constants to decide what to save in CLIPS dump files (see the
+\function{SaveInstances()}, \function{BSaveInstances()} and
+\function{SaveFacts()} functions).
+
+\begin{tableii}{l|l}{constant}{Constant}{Description}
+	\lineii{LOCAL_SAVE}{save objects having templates defined
+            in current \class{Module}}
+	\lineii{VISIBLE_SAVE}{save all objects visible to current
+            \class{Module}}
+\end{tableii}
+
+
+\subsubsection{Salience Evaluation Constants}
+
+Constants to tell the underlying engine when salience has to be
+evaluated (see the \var{EngineConfig.SalienceEvaluation} property).
+
+\begin{tableii}{l|l}{constant}{Constant}{Description}
+	\lineii{WHEN_DEFINED}{evaluate salience on rule definition
+            (the default)}
+	\lineii{WHEN_ACTIVATED}{evaluate salience on rule activation
+            (\emph{dynamic salience})}
+	\lineii{EVERY_CYCLE}{evaluate salience on every execution
+            cycle (\emph{dynamic salience})}
+\end{tableii}
+
+
+\subsubsection{Conflict Resolution Strategy Constants}
+
+Constants to specify the way the underlying engine should resolve
+conflicts among rules having the same salience (see the
+\var{EngineConfig.Strategy} property).
+
+\begin{tableii}{l|l}{constant}{Constant}{Description}
+	\lineii{DEPTH_STRATEGY}{newly activated rule comes first}
+	\lineii{BREADTH_STRATEGY}{newly activated rule comes last}
+	\lineii{LEX_STRATEGY}{strategy based on \emph{time tags}
+            applied to facts}
+	\lineii{MEA_STRATEGY}{strategy based on \emph{time tags}
+            applied to facts}
+	\lineii{COMPLEXITY_STRATEGY}{newly activated rule comes before
+            rules of lower \emph{specificity}}
+	\lineii{SIMPLICITY_STRATEGY}{newly activated rule comes before
+            rules of higher \emph{specificity}}
+	\lineii{RANDOM_STRATEGY}{assign place in agenda randomly}
+\end{tableii}
+
+In the table above, the term \emph{specificity} refers to the number
+of comparisons in the LHS of a rule.
+
+
+\subsubsection{Class Definition Default Mode Constants}
+
+Constants to specify default mode used for classes definition. Please
+refer to \clipsbpg{} for details about the usage of the two modes, as
+the meaning is quite complex and outside the scope of this manual
+(see the \var{EngineConfig.ClassDefaultsMode} property).
+
+\begin{tableii}{l|l}{constant}{Constant}{Description}
+	\lineii{CONVENIENCE_MODE}{set the default class mode to
+            \keyword{convenience}}
+	\lineii{CONSERVATION_MODE}{set the default class mode to
+            \keyword{conservation}}
+\end{tableii}
+
+
+\subsubsection{Message Handler Type Constants}
+
+Constants to define the execution time, the purpose and the behaviour of
+\emph{message handlers}: see function \function{BuildMessageHandler()}
+and the following members of the \class{Class} class:
+\function{AddMessageHandler()} and \function{FindMessageHandler()}.
+The following table summarizes the analogous one found in \clipsbpg{}.
+
+\begin{tableii}{l|l}{constant}{Constant}{Description}
+	\lineii{AROUND}{only to set up an environment for the message}
+	\lineii{AFTER}{to perform auxiliary work after the primary message}
+	\lineii{BEFORE}{to perform auxiliary work before the primary message}
+	\lineii{PRIMARY}{to perform most of the work for the message}
+\end{tableii}
+
+
+\subsubsection{Template Slot Default Type Constants}
+
+It's possible to inspect whether or not a \class{Template} slot has been
+defined to have a default value, and in case it is, if its default value
+is \emph{static} (that is, constant) or \emph{dynamically generated} (for
+instance, using a function like \code{gensym}). See the documentation of
+\class{Template} for more details.
+
+\begin{tableii}{l|l}{constant}{Constant}{Description}
+	\lineii{NO_DEFAULT}{the slot has no default value}
+	\lineii{STATIC_DEFAULT}{the default value is a constant}
+	\lineii{DYNAMIC_DEFAULT}{the default value is dynamically generated}
+\end{tableii}
+
+Notice that \constant{NO_DEFAULT} evaluates to \constant{False}, so it's
+legal to use the \function{Template.Slot.HasDefault()} function just to
+test the presence of a default value. Please also note that
+\constant{NO_DEFAULT} is only returned when the default value for a slot
+is set to \code{?NONE} as stated in the \clipsapg{}.
+
+
+\subsection{Functions\label{pyclips-tl-functions}}
+
+\begin{funcdesc}{AgendaChanged}{}
+test whether or not \code{Agenda} has changed since last call.
+\end{funcdesc}
+
+\begin{funcdesc}{Assert}{o}
+Assert a \class{Fact} (already created or from a string). This perhaps
+needs some explanation: CLIPS allows the creation of \code{fact}s based
+on \class{Template}s, and in \pyclips{} this is done by instancing a
+\code{Fact} with a \class{Template} argument. The resulting \class{Fact}
+slots can then be modified and the object can be used to make an
+assertion, either by using the \class{Fact} \function{Assert()}
+function or this version od \function{Assert()}.
+\end{funcdesc}
+
+\begin{funcdesc}{BLoad}{filename}
+Load the constructs from a binary file named \var{filename}. Binary
+files are not human-readable and contain all the construct information.
+\end{funcdesc}
+
+\begin{funcdesc}{BLoadInstances}{filename}
+Load \class{Instance}s from binary file named \var{filename}. Binary
+files are not human-readable and contain all the construct information.
+\end{funcdesc}
+
+\begin{funcdesc}{BSave}{filename}
+Save constructs to a binary file named \var{filename}.
+\end{funcdesc}
+
+\begin{funcdesc}{BSaveInstances}{filename \optional{, mode=\constant{LOCAL_SAVE}}}
+Save \class{Instance}s to binary file named \var{filename}. The
+\var{mode} parameter can be one of \constant{LOCAL_SAVE} (for all
+\class{Instance}s whose \class{Definstance}s are defined in current
+\class{Module}) or \constant{VISIBLE_SAVE} (for all \class{Instance}s
+visible to current \class{Module}).
+\end{funcdesc}
+
+\begin{funcdesc}{BatchStar}{filename}
+Execute commands stored in text file named as specified in \var{filename}.
+\end{funcdesc}
+
+\begin{funcdesc}{BrowseClasses}{name}
+Print the list of \class{Class}es that inherit from specified one.
+\end{funcdesc}
+
+\begin{funcdesc}{Build}{construct}
+Build construct given in argument as a string. The string must enclose
+a full construct in the CLIPS language.
+\end{funcdesc}
+
+\begin{funcdesc}{BuildClass}{name, text \optional{, comment}}
+Build a \class{Class} with specified name and body. \var{comment} is
+the optional comment to give to the object. This function is the only
+one that can be used to create \class{Class}es with multiple
+inheritance.
+\end{funcdesc}
+
+\begin{funcdesc}{BuildDeffacts}{name, text \optional{, comment}}
+Build a \class{Deffacts} object with specified name and body.
+\var{comment} is the optional comment to give to the object.
+\end{funcdesc}
+
+\begin{funcdesc}{BuildDefinstances}{name, text \optional{, comment}}
+Build a \class{Definstances} having specified name and body.
+\var{comment} is the optional comment to give to the object.
+\end{funcdesc}
+
+\begin{funcdesc}{BuildFunction}{name, args, text \optional{, comment}}
+Build a \class{Function} with specified name, arguments and body.
+\var{comment} is the optional comment to give to the object. \var{args}
+can be either a blank-separated string containing argument names, or
+a sequence of strings corresponding to argument names. Such argument
+names should be coherent to the ones used in the function body (that is,
+\var{text}). The argument list, if expressed as a string, should
+\emph{not} be surrounded by brackets. \var{None} can also be used as
+the argument list if the function has no arguments.
+\end{funcdesc}
+
+\begin{funcdesc}{BuildGeneric}{name, text \optional{, comment}}
+Build a \class{Generic} with specified name and body. \var{comment} is
+the optional comment to give to the object.
+\end{funcdesc}
+
+\begin{funcdesc}{BuildGlobal}{name, \optional{, value}}
+Build a \class{Global} variable with specified \var{name} and \var{value}.
+The \var{value} parameter can be of any of the types supported by CLIPS:
+it can be expressed as a Python value (with type defined in Python: the
+module will try to pass to CLIPS a value of an according type), but for
+types that normally do not exist in Python (such as \class{Symbol}s) an
+explicit conversion is necessary. If the \var{value} is omitted, then
+the module assigns \var{Nil} to the variable.
+\end{funcdesc}
+
+\begin{funcdesc}{BuildInstance}{name, defclass \optional{, overrides}}
+Build an \class{Instance} of given \class{Class} overriding specified
+\code{slots}. If no \code{slot} is specified to be overridden, then the
+\class{Instance} will assume default values.
+\end{funcdesc}
+
+\begin{methoddesc}{BuildMessageHandler}{name, class, args, text \optional{, type, comment}}
+Add a new \emph{message handler} to the supplied class, with specified
+name, body (the \var{text} argument) and argument list: this can be
+specified either as a sequence of variable names or as a single string
+of whitespace separated variable names. Variable names (expressed as
+strings) can also be \emph{wildcard parameters}, as specified in the
+\clipsbpg{}. The \var{type} parameter should be one of \var{AROUND},
+\var{AFTER}, \var{BEFORE}, \var{PRIMARY} defined at the module level:
+if omitted it will be considered as \var{PRIMARY}. The body must be
+enclosed in brackets, as it is in CLIPS syntax. The function returns
+the \emph{index} of the \emph{message handler} within the specified
+\class{Class}.
+\end{methoddesc}
+
+\begin{funcdesc}{BuildModule}{name \optional{, text, comment}}
+Build a \class{Module} with specified name and body. \var{comment} is
+the optional comment to give to the object. The current \class{Module}
+is set to the new one.
+\end{funcdesc}
+
+\begin{funcdesc}{BuildRule}{name, lhs, rhs \optional{, comment}}
+Build a \class{Rule} object with specified name and body. \var{comment}
+is the optional comment to give to the object. The \var{lhs} and
+\var{rhs} parameters correspond to the \emph{left-hand side} and
+\emph{right-hand side} of a \class{Rule}.
+\end{funcdesc}
+
+\begin{funcdesc}{BuildTemplate}{name, text \optional{, comment}}
+Build a \class{Template} object with specified name and body.
+\var{comment} is the optional comment to give to the object.
+\end{funcdesc}
+
+\begin{funcdesc}{Call}{func, args}
+Call a CLIPS internal \class{Function} with the given argument string.
+The \var{args} parameter, in its easiest form, can be a list of arguments
+separated by blank characters using CLIPS syntax. There are other forms
+that can be used, depending on how many arguments the called function
+requires: if it accepts a single argument, the caller can just specify
+the argument\footnote{It must be of a type compatible with CLIPS. If a
+string is supplied, however, it will be considered as a list of arguments
+separated by whitespace: in order to explicitly pass a string it has
+either to be converted or to be specified surrounded by double quotes.}
+possibly cast using one of the \emph{wrapper classes} described below. When
+the function accepts multiple arguments it is possible to specify them
+as a sequence of values (either a list or a tuple) of basic\footnote{Complex
+values, as \emph{multifield}, are not supported: CLIPS does not allow
+external calls with non-constant arguments and there is no possibility
+to build a \emph{multifield} in place without an explicit function call.}
+values. It is always preferable to convert these values using the
+\emph{wrapper classes} in order to avoid ambiguity, especially in case of
+string arguments.
+\end{funcdesc}
+
+\begin{funcdesc}{ClassList}{}
+Return the list of \class{Class} names.
+\end{funcdesc}
+
+\begin{funcdesc}{Clear}{}
+Clear current \class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{ClearPythonFunctions}{}
+Unregister all user defined Python functions from \pyclips{}.
+\end{funcdesc}
+
+\begin{funcdesc}{ClearFocusStack}{}
+Clear focus stack.
+\end{funcdesc}
+
+\begin{funcdesc}{CurrentEnvironment}{}
+Return an \class{Environment} object representing current CLIPS
+\emph{environment}. This is useful for switching between \emph{environment}s
+in a \pyclips{} session. Please note that almost all \emph{environment}
+operations are disallowed on the returned object until another
+\class{Environment} is selected as current: all operations on current
+\class{Environment} should be performed using the \emph{top level}
+module functions.
+\end{funcdesc}
+
+\begin{funcdesc}{CurrentModule}{}
+Return current module as a \class{Module} object.
+\end{funcdesc}
+
+\begin{funcdesc}{DeffactsList}{}
+Return a list of \class{Deffacts} names in current \class{Module}.
+\end{funcdesc}
+
+\begin{funcdesc}{DefinstancesList}{}
+Retrieve list of all \class{Definstances} names.
+\end{funcdesc}
+
+\begin{funcdesc}{Eval}{expr}
+Evaluate expression passed as argument. Expressions that only have
+\emph{side effects} (e.g. \code{printout} expressions) return
+\constant{None}.
+\end{funcdesc}
+
+\begin{funcdesc}{ExternalTracebackEnabled}{}
+Return \constant{True} if functions called from within CLIPS using the
+engine function \code{python-call} will print a standard traceback to
+\var{sys.stderr} on exceptions, \constant{False} otherwise. This function
+is retained for backwards compatibility only: please use the
+\var{ExternalTraceback} flag of the \var{DebugConfig} object to enable or
+disable this feature instead.
+\end{funcdesc}
+
+\begin{funcdesc}{FactList}{}
+Return list of \class{Fact}s in current \class{Module}.
+\end{funcdesc}
+
+\begin{funcdesc}{FactListChanged}{}
+Test whether \class{Fact} list is changed since last call.
+\end{funcdesc}
+
+\begin{funcdesc}{FindClass}{name}
+Find a \class{Class} by name.
+\end{funcdesc}
+
+\begin{funcdesc}{FindDeffacts}{name}
+Find a \class{Deffacts} by name.
+\end{funcdesc}
+
+\begin{funcdesc}{FindDefinstances}{name}
+Find a \class{Definstances} by name.
+\end{funcdesc}
+
+\begin{funcdesc}{FindFunction}{name}
+Find a \class{Function} by name.
+\end{funcdesc}
+
+\begin{funcdesc}{FindGeneric}{name}
+Find a \class{Generic} function by name.
+\end{funcdesc}
+
+\begin{funcdesc}{FindGlobal}{name}
+Find a \class{Global} variable by name.
+\end{funcdesc}
+
+\begin{funcdesc}{FindInstance}{name}
+Find an \class{Instance} in all \class{Module}s (including imported).
+\end{funcdesc}
+
+\begin{funcdesc}{FindInstanceLocal}{name}
+Find an \class{Instance} in non imported \class{Module}s.
+\end{funcdesc}
+
+\begin{funcdesc}{FindModule}{name}
+Find a \class{Module} in list by name.
+\end{funcdesc}
+
+\begin{funcdesc}{FindRule}{name}
+Find a \class{Rule} by name.
+\end{funcdesc}
+
+\begin{funcdesc}{FindTemplate}{name}
+Find a \class{Template} by name.
+\end{funcdesc}
+
+\begin{funcdesc}{FocusStack}{}
+Get list of \class{Module} names in focus stack.
+\end{funcdesc}
+
+\begin{funcdesc}{FunctionList}{}
+Return the list of \class{Function} names.
+\end{funcdesc}
+
+\begin{funcdesc}{GenericList}{}
+Return the list of \class{Generic} names.
+\end{funcdesc}
+
+\begin{funcdesc}{GlobalList}{}
+Return the list of \class{Global} variable names.
+\end{funcdesc}
+
+\begin{funcdesc}{GlobalsChanged}{}
+Test whether or not \class{Global} variables have changed since last
+call.
+\end{funcdesc}
+
+\begin{funcdesc}{InitialActivation}{}
+Return first \class{\class{Activation}} object in current CLIPS
+\class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{InitialClass}{}
+Return first \class{Class} in current CLIPS \class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{InitialDeffacts}{}
+Return first \class{Deffacts} in current CLIPS \class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{InitialDefinstances}{}
+Return first \class{Definstances} in current CLIPS \class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{InitialFact}{}
+Return first \class{Fact} in current CLIPS \class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{InitialFunction}{}
+Return first \class{Function} in current CLIPS \class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{InitialGeneric}{}
+Return first \class{Generic} in current CLIPS \class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{InitialGlobal}{}
+Return first \class{Global} variable in current CLIPS
+\class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{InitialInstance}{}
+Return first \class{Instance} in current CLIPS \class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{InitialModule}{}
+Return first \class{Module} in current CLIPS \class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{InitialRule}{}
+Return first \class{Rule} in current CLIPS \class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{InitialTemplate}{}
+Return first \class{Template} in current CLIPS \class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{InstancesChanged}{}
+Test if \class{Instance}s have changed since last call.
+\end{funcdesc}
+
+\begin{funcdesc}{Load}{filename}
+Load constructs from the specified file named \var{filename}.
+\end{funcdesc}
+
+\begin{funcdesc}{LoadFacts}{filename}
+Load \class{Fact}s from the specified file named \var{filename}.
+\end{funcdesc}
+
+\begin{funcdesc}{LoadFactsFromString}{s}
+Load \class{Fact}s from the specified string.
+\end{funcdesc}
+
+\begin{funcdesc}{LoadInstances}{filename}
+Load \class{Instance}s from file named \var{filename}.
+\end{funcdesc}
+
+\begin{funcdesc}{LoadInstancesFromString}{s}
+Load \class{Instance}s from the specified string.
+\end{funcdesc}
+
+\begin{funcdesc}{MessageHandlerList}{}
+Return list of \class{MessageHandler} constructs.
+\end{funcdesc}
+
+\begin{funcdesc}{MethodList}{}
+Return the list of all methods.
+\end{funcdesc}
+
+\begin{funcdesc}{ModuleList}{}
+Return the list of \class{Module} names.
+\end{funcdesc}
+
+\begin{funcdesc}{PopFocus}{}
+Pop focus.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintAgenda}{}
+Print \class{Rule}s in \code{Agenda} to standard output.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintBreakpoints}{}
+Print a list of all breakpoints to standard output.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintClasses}{}
+Print a list of all \class{Class}es to standard output.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintDeffacts}{}
+Print a list of all \class{Deffacts} to standard output.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintDefinstances}{}
+Print a list of all \class{Definstances} to standard output.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintFacts}{}
+Print \class{Fact}s to standard output.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintFocusStack}{}
+Print focus stack to standard output.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintFunctions}{}
+Print a list of all \class{Function}s to standard output.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintGenerics}{}
+Print list of \class{Generic} functions to standard output.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintGlobals}{}
+print a list of \class{Global} variables to standard output
+\end{funcdesc}
+
+\begin{funcdesc}{PrintInstances}{\optional{class}}
+Print a list of \class{Instance}s to standard output. If the \var{class}
+argument is omitted, all \class{Instance}s in the subsystem will be
+shown. The \var{class} parameter can be a \class{Class} object or a
+string containing a \class{Class} name.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintMessageHandlers}{}
+Print a list of all \class{MessageHandler}s.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintModules}{}
+Print a list of \class{Module}s to standard output.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintRules}{}
+Print a list of \class{Rule}s to standard output.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintSubclassInstances}{\optional{class}}
+Print subclass \class{Instance}s to standard output for the
+\class{Class} specified. If the \var{class} argument is omitted, all
+instances in the subsystem will be shown. The \var{class} parameter can
+be a string containing a \class{Class} name or a \class{Class} object.
+\end{funcdesc}
+
+\begin{funcdesc}{PrintTemplates}{}
+Print \class{Template} names to standard output.
+\end{funcdesc}
+
+\begin{funcdesc}{RefreshAgenda}{}
+Refresh \code{Agenda} \class{Rule}s for current \class{Module}.
+\end{funcdesc}
+
+\begin{funcdesc}{RegisterPythonFunction}{callable \optional{, name}}
+Register the function \function{callable} for use within CLIPS via the
+engine function \code{python-call}. If the parameter \var{name} of type
+\class{str} is not given, then the \var{__name__} attribute of the
+first argument will be used. \var{name} is the name that will be used
+in CLIPS to refer to the function. See appendix for a more detailed
+explanation.
+\end{funcdesc}
+
+\begin{funcdesc}{ReorderAgenda}{}
+Reorder \code{Agenda} \class{Rule}s for current \class{Module}.
+\end{funcdesc}
+
+\begin{funcdesc}{Reset}{}
+Reset current \class{Environment}.
+\end{funcdesc}
+
+\begin{funcdesc}{RestoreInstancesFromString}{s}
+Restore \class{Instance}s from the specified string.
+\end{funcdesc}
+
+\begin{funcdesc}{RuleList}{}
+Return a list of \class{Rule} names in current \class{Module}.
+\end{funcdesc}
+
+\begin{funcdesc}{Run}{\optional{limit}}
+Execute \class{Rule}s up to \var{limit} (which is an \class{int} if
+given). If \var{limit} is omitted, then no limitation is assumed and the
+program runs countinuously until all rules are executed. The function
+returns the number of rules that have been fired\footnote{This means,
+for instance, that continuously using this function and checking whether
+or not the result is less than the specified limit can give more control
+over the running CLIPS subprogram, eventually giving the ability to
+actively check for the end of the program.}.
+\end{funcdesc}
+
+\begin{funcdesc}{Save}{filename}
+Save constructs to the file specified by \var{filename}. The constructs are
+saved in text (human readable) form.
+\end{funcdesc}
+
+\begin{funcdesc}{SaveFacts}{filename \optional{, mode=\constant{LOCAL_SAVE}}}
+Save current \class{Fact}s to file specified by \var{filename}. The
+\var{mode} parameter can be one of \constant{LOCAL_SAVE} (for all
+\class{Fact}s whose \class{Template}s are defined in current
+\class{Module}) or \constant{VISIBLE_SAVE} (for all \class{Fact}s
+visible to current \class{Module}).
+\end{funcdesc}
+
+\begin{funcdesc}{SaveInstances}{filename \optional{, mode=\constant{LOCAL_SAVE}}}
+Save \class{Instance}s to file specified by \var{filename}. The
+\var{mode} parameter can be one of \constant{LOCAL_SAVE} (for all
+\class{Instance}s whose \class{Definstance}s are defined in current
+\class{Module}) or \constant{VISIBLE_SAVE} (for all \class{Instance}s
+visible to current \class{Module}).
+\end{funcdesc}
+
+\begin{funcdesc}{SendCommand}{cmd \optional{, verbose=\constant{False}}}
+Send a command to the underlying CLIPS engine, as if it was typed at the
+console in an interactive CLIPS session. This command could actually be
+useful when embedding a CLIPS shell in a Python program. Please note that
+other input than commands, in such a case, should be entered using the
+\var{StdinStream} input stream. If \var{verbose} is set to \constant{True}
+the possible\footnote{Except for the CLIPS printing functions, as for
+instance \code{printout}, that issue an output even when the flag is not
+set.} command output is sent to the appropriate output stream.
+\end{funcdesc}
+
+\begin{funcdesc}{SetExternalTraceback}{\optional{enabled=\constant{True}}}
+Allow or disallow functions called from within the CLIPS engine using
+\code{python-call} to print a standard traceback to \var{sys.stderr} in
+case an exception occurs. Please note that this does not mean that a
+real exception arises, as there is no possibility to catch Python
+exceptions in CLIPS code. In such case all failing Python functions will
+return the symbol \code{FALSE} to CLIPS\footnote{This is not always an
+error condition because a function can intentionally return boolean
+values to CLIPS. However the CLIPS engine will report an error message
+which can be read from the error stream.}. This behaviour is initially
+set to \constant{False}, as it is useful only for debugging purposes.
+This function is retained for backwards compatibility only: please use the
+\var{ExternalTraceback} flag of the \var{DebugConfig} object to enable or
+disable this feature instead.
+\end{funcdesc}
+
+\begin{funcdesc}{ShowGlobals}{}
+Print list of \class{Global} variables and their values to standard
+output (the \function{PrintGlobals()} functions only prints out
+\class{Global} variable names).
+\end{funcdesc}
+
+\begin{funcdesc}{TemplateList}{}
+Return a list of \class{Template} names.
+\end{funcdesc}
+
+\begin{funcdesc}{UnregisterPythonFunction}{name}
+Remove the function referred as \var{name} within the CLIPS engine from
+the set of functions that can be called via \code{python-call} calls.
+\end{funcdesc}
+
+
+Among other exception types, arising in cases that can also occur in
+Python, the \pyclips{} module can raise exceptions specific to CLIPS
+identified by the following:
+
+\begin{excdesc}{ClipsError}
+Exception raised when an operation fails in the CLIPS subsystem: normally
+it occurs when CLIPS finds an error, when an iteration is over or when an
+invalid value is passed to CLIPS. This exception is accompanied by
+explanatory text preceded by an alphanumeric code that can be used
+to programmatically identify the error.
+\end{excdesc}
+
+\begin{excdesc}{ClipsMemoryError}
+Severe memory error raised when the CLIPS subsystem is unable to allocate
+the needed memory. In normal circumstances, when an error of this type
+occurs, the CLIPS system has become inconsistent and the only way to
+recover is exiting. This exception is raised only in order to allow a
+developer to notify the user of the impossibility to continue.
+\end{excdesc}
+
+
+\begin{seealso}
+\sclipsapg{}
+\sclipsbpg{}
+\end{seealso}
+
+
diff --git a/doc/copyright.tex b/doc/copyright.tex
new file mode 100644
index 0000000..e06d880
--- /dev/null
+++ b/doc/copyright.tex
@@ -0,0 +1,6 @@
+% $Id: copyright.tex 342 2008-02-22 01:17:23Z Franz $
+Copyright \copyright{} 2002-2008 Francesco Garosi/JKS.
+All rights reserved.
+
+See the end of this document for complete license and permissions
+information.
diff --git a/doc/defs.tex b/doc/defs.tex
new file mode 100644
index 0000000..f0bb8a3
--- /dev/null
+++ b/doc/defs.tex
@@ -0,0 +1,24 @@
+% some definitions used troughout the documentation
+% $Id: defs.tex 99 2004-07-13 21:01:38Z Franz $
+
+% all references to the PyCLIPS module should use this macro
+\newcommand{\pyclips}{\module{PyCLIPS}}
+
+
+% references to the APG, BPG and Tutorial should use these macros
+\newcommand{\clipsapg}{\emph{Clips Reference Guide Vol. II:
+Advanced Programming Guide}}
+\newcommand{\sclipsapg}{\seetitle{Clips Reference Guide Vol.
+II: Advanced Programming Guide}{contains detailed information
+about CLIPS API and internal structures}}
+
+\newcommand{\clipsbpg}{\emph{Clips Reference Guide Vol. I:
+Basic Programming Guide}}
+\newcommand{\sclipsbpg}{\seetitle{Clips Reference Guide Vol.
+I: Basic Programming Guide}{the main reference for the CLIPS
+language}}
+
+\newcommand{\clipstut}{\emph{Clips User's Guide}}
+\newcommand{\sclipstut}{\seetitle{Clips User's Guide}{the
+official tutorial for the CLIPS language}}
+
diff --git a/doc/intro.tex b/doc/intro.tex
new file mode 100644
index 0000000..239700c
--- /dev/null
+++ b/doc/intro.tex
@@ -0,0 +1,537 @@
+% $Id: intro.tex 346 2008-02-25 00:39:00Z Franz $
+\chapter{Introduction\label{introduction}}
+
+\section{Overview\label{pyclips-overview}}
+
+This module aims to embed a fully functional CLIPS engine in Python, and
+to give to the developer a more Python-compliant interface to CLIPS
+without cutting down on functionalities. In fact CLIPS is compiled into
+the module in its entirety, and most API functions are bound to Python
+methods. However the direct bindings to the CLIPS library (implemented
+as the \module{_clips} submodule) are not described here: each function
+is described by an appropriate documentation string, and accessible by
+means of the \function{help()} function or through the \program{pydoc}
+tool. Each direct binding maps to an API provided function. For a
+detailed reference\footnote{The order of parameters is changed sometimes,
+in order to allow a more intuitive use of default parameters in the
+Python interface: however the meaning of each parameter is described
+in the function documentation string, and it should not be difficult
+for the programmer to correctly understand the relationship between a
+module function and the corresponding CLIPS API.} for these functions
+see \clipsapg{}, available for download at the CLIPS website.
+
+\pyclips{} is also capable of generating CLIPS text and binary files:
+this allows the user to interact with sessions of the CLIPS system
+itself.
+
+An important thing to know, is that \pyclips{} implements CLIPS as a
+separated\footnote{This has an impact on the way the module can be used,
+as the engine is only set up once when the module is \code{import}ed the
+first time.} engine: in the CLIPS module implementation, CLIPS
+``lives'' in its own memory space, allocates its own objects. The module
+only provides a way to send information and commands to this engine
+and to retrieve results from it.
+
+
+\subsection{Structure\label{pyclips-ov-structure}}
+
+\pyclips{} is organized in a package providing several classes and
+top-level functions. Also, the module provides some objects that are
+already instanced and give access to some of the CLIPS internal
+functions and structures, including debug status and engine I/O.
+
+CLIPS is accessible through these classes and functions, that send
+appropriate commands to the underlying engine and retrieve the
+available information. Many of the CLIPS classes, constructs and
+objects are shadowed by Python classes and objects. However, whereas
+\pyclips{} classes provide a comfortable way to create objects that
+reference the actual engine objects, there is no one-to-one
+mapping between the two memory spaces: for instance, when a Python
+object is deleted (via the \keyword{del} command), the corresponding
+CLIPS object will still remain alive in the CLIPS memory space. An
+appropriate command is necessary to remove the object from the
+underlying engine, and this is provided by the module interface.
+
+
+\subsection{Interactive Usage\label{pyclips-ov-interactive}}
+
+The \pyclips{} package can also be used interactively, since it can
+inspect an underlying CLIPS session and give some of the output that
+CLIPS usually provides when used as an interactive shell.
+
+A simple interactive session with \pyclips{} follows:
+
+\begin{verbatim}
+>>> import clips
+>>> clips.Reset()
+>>> clips.Assert("(duck)")
+<Fact 'f-1': fact object at 0x00DE4AE0>
+>>> clips.BuildRule("duck-rule", "(duck)", "(assert (quack))", "the Duck Rule")
+<Rule 'duck-rule': defrule object at 0x00DA7E00>
+>>> clips.PrintRules()
+MAIN:
+duck-rule
+>>> clips.PrintAgenda()
+MAIN:
+   0      duck-rule: f-1
+For a total of 1 activation.
+>>> clips.PrintFacts()
+f-0     (initial-fact)
+f-1     (duck)
+For a total of 2 facts.
+>>> clips.Run()
+>>> clips.PrintFacts()
+f-0     (initial-fact)
+f-1     (duck)
+f-2     (quack)
+For a total of 3 facts.
+\end{verbatim}
+
+Users of the CLIPS interactive shell will find the \pyclips{} output
+quite familiar. In fact the \function{Print\emph{<object>}()} functions
+are provided for interactive use, and retrieve their output directly from
+the underlying CLIPS engine I/O subsystem, in order to resemble an
+interactive CLIPS session. Other functions are present to retrieve
+object names, values and the so called \emph{pretty-print forms} for
+programmatic use.
+
+
+\section{Implementation Structure\label{pyclips-implstructure}}
+
+This section describes the guidelines and considerations that lead
+to this CLIPS interface implementation. For the developers which
+normally use CLIPS as a development environment or expert systems
+shell, the architecture of the \pyclips{} module will look a little
+bit different, and in some ways could also seem confusing.
+
+The main topics covered by these sections are the \emph{Implementation
+of Constructs as Classes}, the \emph{Implementation of CLIPS I/O
+Subsystem}, the \emph{Configuration and Debug Objects}, the
+\emph{Coexistence of Global and Environment-Aware Engines} and the
+\emph{Conventions used for Naming} which explains the rules that
+helped choose the current naming scheme for classes, functions and
+objects implemented in \pyclips{}.
+
+
+\subsection{Implementation of Constructs as Classes\label{pyclips-ov-casc}}
+
+CLIPS users know that this shell offers several constructs to populate
+the system memory. These constructs are not described here, since a
+detailed explaination of the CLIPS language can be found in the
+official CLIPS documentation. These constructs, many of which have
+their particular syntax, create ``objects'' (not necessarily in the
+sense of OOP\footnote{In fact, the word \emph{object} is used here
+to indicate an item that takes part in a program. For instance, one
+such object can be a \class{Rule}: it is not a proper OO object,
+but something that in imperative languages would act as a control
+structure.}, although some of these can be \class{Instance}s of
+\class{Class}es) in the subsystem memory.
+
+The choice of implementing most of these constructs as classes gives
+to \pyclips{} a more organic structure. Most of the construct classes
+share similarities which make the interface structure simpler and the
+access to CLIPS objects more systematic.
+
+Most constructs are implemented as \emph{factory functions} which
+return instances of Python classes. These Python instances (that
+shadow the corresponding CLIPS objects), on their turn, have methods
+and properties which operate directly on the objects they map in the
+CLIPS subsystem. Methods and properties provide both access and
+\emph{send messages} to these objects.
+
+An example of this follows:
+
+\begin{verbatim}
+>>> import clips
+>>> f0 = clips.Assert("(duck)")
+>>> print f0
+f-0
+>>> print f0.Exists()
+True
+>>> f0.Retract()
+>>> print f0.Exists()
+False
+\end{verbatim}
+
+In the above example, a fact (\code{(duck)}) is asserted and then
+retracted. The assertion is done by means of a module-level function
+(\function{Assert()}) and the fact is retracted using a method of the
+shadow object (\var{f0}). A verification on the CLIPS \code{fact} object,
+using the Python \class{Fact} instance\footnote{It should be clear
+that terminology differs semantically from Python system to the CLIPS
+system: while OOP, to which terms used in Python are coherent, uses
+the words \emph{method}, \emph{instance} and so on with a particular
+meaning (to which Python developers are familiar), CLIPS terminology
+often differs from OOP, sometimes only slightly but at other times more
+substantially. The reader should note that throughout this manual
+each term is used -- as far as possible -- with the meaning that it
+assumes in its specific environment. In this case, the word
+\emph{instance} represents the instance of a Python \keyword{class},
+and is not referred to an entity in CLIPS.} \var{f0}'s method
+\function{Exists()}, shows that after invoking the \function{Retract()}
+method of \var{f0} the \code{fact} object does no longer exists in the
+CLIPS subsystem, thus it has been actually retracted.
+
+As stated previously, this does not remove the Python object
+(a \class{Fact} instance) from the namespace pertinent to Python itself:
+as it can be seen from the code snip shown above, \code{f0} is still a
+functional instance, and can be queried about the existence of the
+corresponding object in CLIPS.
+
+Objects in the CLIPS operating space can be referenced by more than a
+Python object (or even not be referenced at all, if CLIPS creation does
+not correspond to a Python assignment), as demonstrated by the following
+code:
+
+\begin{verbatim}
+>>> clips.Reset()
+>>> f1 = clips.Assert("(duck)")
+>>> clips.Assert("(quack)")
+<Fact 'f-2': fact object at 0x00DE8420>
+>>> f1
+<Fact 'f-1': fact object at 0x00DE3020>
+>>> fl = clips.FactList()
+>>> f1b = fl[1]
+>>> f1b
+<Fact 'f-1': fact object at 0x00E08C40>
+\end{verbatim}
+
+Both \var{f1} and \var{f1b} refer to the same object in CLIPS namespace,
+but their address is different: in fact they are two different Python
+objects (equality test fails) but correspond to the same \code{fact} in
+CLIPS.
+
+\begin{seealso}
+\sclipsbpg{}
+\end{seealso}
+
+
+\subsection{Implementation of CLIPS I/O Subsystem\label{pyclips-ov-io}}
+
+The CLIPS shell interacts with the user answering to typed in commands
+with some informational output. An interactive CLIPS session will show
+this:
+
+\begin{verbatim}
+CLIPS> (reset)
+CLIPS> (watch activations)
+CLIPS> (defrule duck-rule "the Duck Rule"
+   (duck)
+=>
+   (assert (quack)))
+CLIPS> (assert (duck))
+==> Activation 0      duck-rule: f-1
+<Fact-1>
+CLIPS> (run)
+CLIPS> (facts)
+f-0     (initial-fact)
+f-1     (duck)
+f-2     (quack)
+For a total of 3 facts.
+\end{verbatim}
+
+Each time a \code{fact} is asserted, CLIPS outputs a string containing
+its index, and since we decided to show some debug output about
+activations, CLIPS produces a line as soon as \code{duck} is asserted,
+since \code{duck-rule} would be activated by this. Although in an
+interactive session all of the output would go to the terminal, CLIPS
+logically considers the ``streams'' for different output types as
+separated: in fact, debug output (the one generated by the \code{watch}
+command) goes to a special stream called \code{wtrace}. In this special
+case, for instance, the debug output can be captured by \pyclips{}
+through a special stream-like Python object, which provides a
+\function{Read()} function\footnote{Note that \function{Read()} is
+capitalized: this is because the stream-like objects do not really act
+as ``files'' as many objects which can be read in Python do. So it
+becomes impossible to use these \pyclips{} objects where a file-like
+object is to be used.}. Comparing the behaviour of two interactive
+sessions, the former in the CLIPS subsystem and the latter in Python,
+will help to understand the close relationship between CLIPS I/O and
+\pyclips{} stream objects. CLIPS will interact with the user as
+follows:
+
+\begin{verbatim}
+CLIPS> (defrule sayhello
+   (hello)
+=>
+   (printout t "hello, world!" crlf))
+CLIPS> (assert (hello))
+==> Activation 0      sayhello: f-1
+<Fact-1>
+CLIPS> (run)
+hello, world!
+\end{verbatim}
+
+And the Python counterpart follows:
+
+\begin{verbatim}
+>>> import clips
+>>> clips.DebugConfig.ActivationsWatched = True
+>>> r0 = clips.BuildRule("sayhello", "(hello)",
+                         '(printout stdout "hello, world!" crlf)')
+>>> print r0.PPForm()
+(defrule MAIN::sayhello
+   (hello)
+   =>
+   (printout stdout "hello, world!" crlf))
+
+>>> clips.Assert("(hello)")
+<Fact 'f-0': fact object at 0x00DE81C0>
+>>> t = clips.TraceStream.Read()
+>>> print t
+==> Activation 0      sayhello: f-0
+>>> clips.Run()
+>>> t = clips.StdoutStream.Read()
+>>> print t
+hello, world!
+\end{verbatim}
+
+The I/O access objects can be used both in interactive and unattended
+sessions. In this case, they can be useful to retrieve periodical
+information about CLIPS internal status, since most of the output
+provided can be easily interpreted in a programmatic way. Also, there
+is one more stream called \var{StdinStream} (which has a
+\function{Write()} method) that might be useful to send input to the
+CLIPS engine when some ``user interaction'' is required\footnote{This only
+happens actually when CLIPS invokes the \code{read} or \code{readline}
+functions.}.
+
+There is no way to create other instances of these streams: the
+high-level module hides the class used to build these objects. This
+is because the I/O streams have to be considered like ``physical
+devices'' whose use is reserved to the engine to report trace and
+debug information as well as user requested output.
+
+These I/O streams will be described later in the detail, since each
+one can be used to report about a specific task.
+
+\note{The streams have to be explicitly read: there is no way to
+receive a notification from CLIPS that some output has been written.
+In other words, the \pyclips{} engine is not \emph{event driven} in
+its interaction with Python.}
+
+
+\subsection{Configuration and Debug Objects\label{pyclips-ov-cado}}
+
+As well as I/O streams, there are two other objects directly provided
+by \pyclips{}. These objects provide access to the CLIPS engine global
+configuration. Many aspects of the CLIPS engine, that in the command
+line environment would be configured using particular commands, are
+accessible via the \var{EngineConfig} (global engine configuration)
+object and the \var{DebugConfig} (global debug and trace configuration)
+object. For example, we can take the code snip shown above:
+
+\begin{verbatim}
+>>> clips.DebugConfig.ActivationsWatched = True
+\end{verbatim}
+(...)
+\begin{verbatim}
+>>> t = clips.TraceStream.Read()
+>>> print t
+==> Activation 0      sayhello: f-0
+\end{verbatim}
+
+The \code{clips.DebugConfig.ActivationsWatched = True} line tells to the
+underlying subsystem that debug information about \emph{rule activations}
+has to be written to the proper stream (the stream dedicated to debug
+output in CLIPS is called \code{wtrace} and is accessible in \pyclips{}
+through the \var{TraceStream} object).
+
+As it has been said for the I/O streams, these objects cannot be instanced
+by the user: access to these objects affects global (or at least
+\emph{environmental}, we will see the difference later) configuration,
+so it would be of no meaning for the user to create more, possibly
+confusing, instances of such objects.
+
+
+\subsection{Coexistence of Global and Environment-Aware Engines\label{pyclips-ov-env}}
+
+As of version 6.20, CLIPS API offers the possibility to have several
+\emph{environments} in which to operate. We can consider environments as
+separate engines that only share the operating mode, in other words
+``the code''. \pyclips{} also implements environments by means of a special
+\class{Environment} class. This class implements all the features
+provided by the top level methods and classes. The \class{Environment}
+class reimplements all classes provided by \pyclips{}, but -- although
+their behaviour is quite similar -- methods of classes provided by
+\class{Environment} only affect the CLIPS environment represented by the
+\class{Environment} instance itself.
+
+There is normally no need to use environments. However, access to them
+is provided for CLIPS ``gurus'' who want to have more than one engine
+working at the same time. The end user of \pyclips{} will see no real
+difference between a call to a function and its environmental counterpart
+(defined as \emph{companion function} in the official CLIPS documentation),
+apart from being called as a member function of an \class{Environment}
+object.
+
+A simple example will be explanatory:
+
+\begin{verbatim}
+>>> clips.Clear()
+>>> clips.Reset()
+>>> e0 = clips.Environment()
+>>> e1 = clips.Environment()
+>>> e0.Assert("(duck)")
+<Fact 'f-0': fact object at 0x00E7D960>
+>>> e1.Assert("(quack)")
+<Fact 'f-0': fact object at 0x00E82220>
+>>> e0.PrintFacts()
+f-0     (duck)
+For a total of 1 fact.
+>>> e1.PrintFacts()
+f-0     (quack)
+For a total of 1 fact.
+\end{verbatim}
+
+
+\subsection{Using External Functions in CLIPS\label{pyclips-ov-extfuncs}}
+
+\pyclips{} gives the ability to users to call Python code from within
+the CLIPS subsystem. Virtually every function defined in Python can be
+called from CLIPS code using the special CLIPS function \code{python-call}.
+However, since CLIPS has different basic types than Python, in most cases
+it would be useful for modules that implement function to be called in
+the CLIPS engine to import the \pyclips{} module themselves, in order to
+be aware of the structures that CLIPS uses.
+
+Functions have to be registered in \pyclips{} in order to be available
+to the underlying engine, and the registration process can dynamically
+occur at any moment.
+
+A simple example follows:
+
+\begin{verbatim}
+>>> import clips
+>>> def py_square(x):
+        return x * x
+>>> clips.RegisterPythonFunction(py_square)
+>>> print clips.Eval("(python-call py_square 7)")
+49
+>>> print clips.Eval("(python-call py_square 0.7)")
+0.49
+\end{verbatim}
+
+A more detailed description of the features provided by \code{python-call}
+can be found in the appendices.
+
+
+\subsection{Conventions Used for Naming\label{pyclips-ov-names}}
+
+In \pyclips{}, the simple convention that is used is that all valuable
+content exposed has a name beginning with a capital letter. Names
+beginning with a single underscore have normally no meaning for the
+\pyclips{} user. Functions, class names and objects use mixed capitals
+(as in Java), and \emph{manifest constants} (names used in \emph{lieu}
+of explicit values to pass instructions to CLIPS functions or
+properties) are all capitalized, as is usual for the C language.
+
+CLIPS users will perhaps be confused because often the constructs in
+CLIPS are expressed by keywords containing a \code{def} prefix. The
+choice was made in \pyclips{} to drop this prefix in many cases: the use
+of this prefix has a strong logic in the CLIPS language, because in this
+way the developer knows that a \emph{construct} is used, that is, a
+\emph{definition} is made. The keyword used to instance this definition,
+both encapsulates the meaning of \code{def}inition itself, and also
+the type of construct that is being defined (e.g. \code{def}ine a
+\code{rule} is \code{defrule}), thus avoiding making constructs more
+difficult by means of two separate keywords. In \pyclips{}, since the
+definition happens at class declaration and the instantiation of classes
+shadows a construct definition when it has already been performed, it
+seemed unnecessary to keep the prefix: in fact, to follow the above
+example, it does not seem correct to refer to a rule within the CLIPS
+subsystem as a ``\class{Defrule}'' object, hence it is simply referred
+to as a \class{Rule}.
+
+
+\subsection{Pickling Errors\label{pyclips-ov-pickle}}
+
+Python objects cannot be pickled or unpickled. This is because, since
+pickling an object would save a reference to a CLIPS entity -- which is
+useless across different \pyclips{} sessions -- the unpickling process
+would feed the underlying engine in an unpredictable way, or at least
+would reference memory locations corresponding to previous CLIPS entities
+without the engine having them allocated.
+
+One better way to achieve a similar goal is to use the \function{Save()}
+or \function{BSave()} (and related \function{Load()} or \function{BLoad()})
+to save the engine\footnote{The mentioned functions are also \emph{members}
+of the \class{Environment} class, in which case the \class{Environment}
+status is saved.} status in its entirety.
+
+If a single entity is needed, its \emph{pretty-print form} can be used
+in most cases to recreate it using the \function{Build()} functions.
+
+
+\section{Other Usage Modes\label{pyclips-ov-otheruses}}
+
+It is also interesting that, by using some particular functions and the
+provided I/O subsystem, even ``pure'' CLIPS programs can be executed by
+\pyclips{}, and while the simple output from CLIPS can be read to obtain
+feedback, the possibility of inspecting the internal CLIPS subsystem
+state remains.
+
+The following example, taken from the CLIPS website\footnote{In fact
+the file has been slightly reformatted for typesetting reasons.},
+illustrates this: first we take a full CLIPS program, saved as
+\file{zebra.clp}, and reported below:
+
+\verbatiminput{zebra.clp}
+
+then we execute all commands (using the \function{BatchStar()} function)
+in the current \class{Environment} of an interactive \pyclips{} session:
+
+\begin{verbatim}
+>>> clips.BatchStar("zebra.clp")
+>>> clips.Reset()
+>>> clips.Run()
+>>> s = clips.StdoutStream.Read()
+>>> print s
+There are five houses, each of a different color, inhabited by men of
+different nationalities, with different pets, drinks, and cigarettes.
+
+The Englishman lives in the red house.  The Spaniard owns the dog.
+The ivory house is immediately to the left of the green house, where
+the coffee drinker lives.  The milk drinker lives in the middle house.
+The man who smokes Old Golds also keeps snails.  The Ukrainian drinks
+tea.  The Norwegian resides in the first house on the left.  The
+Chesterfields smoker lives next door to the fox owner.  The Lucky
+Strike smoker drinks orange juice.  The Japanese smokes Parliaments.
+The horse owner lives next to the Kools smoker, whose house is yellow.
+The Norwegian lives next to the blue house.
+
+Now, who drinks water?  And who owns the zebra?
+
+HOUSE | Nationality | Color  | Pet    | Drink        | Smokes
+--------------------------------------------------------------------
+  1   | norwegian   | yellow | fox    | water        | kools
+  2   | ukrainian   | blue   | horse  | tea          | chesterfields
+  3   | englishman  | red    | snails | milk         | old-golds
+  4   | spaniard    | ivory  | dog    | orange-juice | lucky-strikes
+  5   | japanese    | green  | zebra  | coffee       | parliaments
+
+>>> clips.PrintFacts()
+f-0     (initial-fact)
+f-26    (avh (a smokes) (v parliaments) (h 1))
+f-27    (avh (a smokes) (v parliaments) (h 2))
+f-28    (avh (a smokes) (v parliaments) (h 3))
+\end{verbatim}
+
+[... a long list of facts ...]
+
+\begin{verbatim}
+f-150   (avh (a color) (v red) (h 5))
+For a total of 126 facts.
+>>> li = clips.FactList()
+>>> for x in li:
+...	if str(x) == 'f-52':
+...		f52 = x
+>>> f52
+<Fact 'f-52': fact object at 0x00E6AA10>
+>>> print f52.PPForm()
+f-52    (avh (a drink) (v tea) (h 2))
+\end{verbatim}
+
+You can just copy the program above to a file, say \file{zebra.clp} as
+in the example, and follow the same steps to experiment with \pyclips{}
+objects and with the CLIPS subsystem.
diff --git a/doc/license.tex b/doc/license.tex
new file mode 100644
index 0000000..830fad1
--- /dev/null
+++ b/doc/license.tex
@@ -0,0 +1,14 @@
+% $Id: license.tex 174 2004-10-16 12:43:58Z Franz $
+\chapter{License Information\label{pyclips-license}}
+
+The following is the license text, which you can obtain by issuing a
+
+\begin{verbatim}
+>>> import clips
+>>> print clips.license
+\end{verbatim}
+
+at the Python prompt once the \pyclips{} module has been installed.
+
+\verbatiminput{license.txt}
+
diff --git a/doc/license.txt b/doc/license.txt
new file mode 100644
index 0000000..a27df33
--- /dev/null
+++ b/doc/license.txt
@@ -0,0 +1,356 @@
+===========================================================================
+License Information (LGPL)
+===========================================================================
+
+(c) 2002-2008 Francesco Garosi/JKS
+The author's copyright is expressed through the following notice, thus
+giving effective rights to copy and use this software to anyone, as shown
+in the license text.
+
+NOTICE:
+This software is released under the terms of the GNU Lesser General Public
+license; a copy of the text has been released with this package (see file
+_license.py, where the license text also appears), and can be found on the
+GNU web site, at the following address:
+
+           http://www.gnu.org/copyleft/lesser.html
+
+Please refer to the license text for any license information. This notice
+has to be considered part of the license, and should be kept on every copy,
+integral or modified, of the source files. The removal of the reference to
+the license will be considered an infringement of the license itself.
+
+Portions of the code provided with this package may have been released
+under different license terms: in this case it is expressed in the source
+code piece itself. Parts of this source package (eg. the entire CLIPS
+source distribution) are provided under possibly different license terms,
+and different restrictions may apply. These source files are provided as
+the original author(s) packaged them, thus all license information is
+supplied.
+
+If you received the package in binary form, please consult the original
+CLIPS license, which you can find at the CLIPS web site:
+
+                http://clipsrules.sourceforge.net
+
+for the licensing terms regarding use of the CLIPS library.
+
+===========================================================================
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+0. This License Agreement applies to any software library or other program
+which contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Lesser General
+Public License (also called "this License"). Each licensee is addressed as
+"you".
+
+A "library" means a collection of software functions and/or data prepared
+so as to be conveniently linked with application programs (which use some
+of those functions and data) to form executables.
+
+The "Library", below, refers to any such software library or work which has
+been distributed under these terms. A "work based on the Library" means
+either the Library or any derivative work under copyright law: that is to
+say, a work containing the Library or a portion of it, either verbatim or
+with modifications and/or translated straightforwardly into another
+language. (Hereinafter, translation is included without limitation in the
+term "modification".)
+
+"Source code" for a work means the preferred form of the work for making
+modifications to it. For a library, complete source code means all the
+source code for all modules it contains, plus any associated interface
+definition files, plus the scripts used to control compilation and
+installation of the library.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of running a
+program using the Library is not restricted, and output from such a program
+is covered only if its contents constitute a work based on the Library
+(independent of the use of the Library in a tool for writing it). Whether
+that is true depends on what the Library does and what the program that
+uses the Library does.
+
+1. You may copy and distribute verbatim copies of the Library's complete
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the notices
+that refer to this License and to the absence of any warranty; and
+distribute a copy of this License along with the Library.
+
+You may charge a fee for the physical act of transferring a copy, and you
+may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Library or any portion of it,
+thus forming a work based on the Library, and copy and distribute such
+modifications or work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+
+a) The modified work must itself be a software library.
+b) You must cause the files modified to carry prominent notices stating
+   that you changed the files and the date of any change.
+c) You must cause the whole of the work to be licensed at no charge to all
+   third parties under the terms of this License.
+d) If a facility in the modified Library refers to a function or a table of
+   data to be supplied by an application program that uses the facility,
+   other than as an argument passed when the facility is invoked, then you
+   must make a good faith effort to ensure that, in the event an application
+   does not supply such function or table, the facility still operates, and
+   performs whatever part of its purpose remains meaningful.
+
+(For example, a function in a library to compute square roots has a purpose
+that is entirely well-defined independent of the application. Therefore,
+Subsection 2d requires that any application-supplied function or table used
+by this function must be optional: if the application does not supply it,
+the square root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Library, and can be
+reasonably considered independent and separate works in themselves, then
+this License, and its terms, do not apply to those sections when you
+distribute them as separate works. But when you distribute the same sections
+as part of a whole which is a work based on the Library, the distribution
+of the whole must be on the terms of this License, whose permissions for
+other licensees extend to the entire whole, and thus to each and every part
+regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise
+the right to control the distribution of derivative or collective works
+based on the Library.
+
+In addition, mere aggregation of another work not based on the Library with
+the Library (or with a work based on the Library) on a volume of a storage
+or distribution medium does not bring the other work under the scope of
+this License.
+
+3. You may opt to apply the terms of the ordinary GNU General Public License
+instead of this License to a given copy of the Library. To do this, you
+must alter all the notices that refer to this License, so that they refer
+to the ordinary GNU General Public License, version 2, instead of to this
+License. (If a newer version than version 2 of the ordinary GNU General
+Public License has appeared, then you can specify that version instead if
+you wish.) Do not make any other change in these notices.
+
+Once this change is made in a given copy, it is irreversible for that copy,
+so the ordinary GNU General Public License applies to all subsequent copies
+and derivative works made from that copy.
+
+This option is useful when you wish to copy part of the code of the Library
+into a program that is not a library.
+
+4. You may copy and distribute the Library (or a portion or derivative of
+it, under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you accompany it with the complete
+corresponding machine-readable source code, which must be distributed under
+the terms of Sections 1 and 2 above on a medium customarily used for
+software interchange.
+
+If distribution of object code is made by offering access to copy from a
+designated place, then offering equivalent access to copy the source code
+from the same place satisfies the requirement to distribute the source
+code, even though third parties are not compelled to copy the source along
+with the object code.
+
+5. A program that contains no derivative of any portion of the Library, but
+is designed to work with the Library by being compiled or linked with it,
+is called a "work that uses the Library". Such a work, in isolation, is not
+a derivative work of the Library, and therefore falls outside the scope of
+this License.
+
+However, linking a "work that uses the Library" with the Library creates an
+executable that is a derivative of the Library (because it contains portions
+of the Library), rather than a "work that uses the library". The executable
+is therefore covered by this License.Section 6 states terms for distribution
+of such executables.
+
+When a "work that uses the Library" uses material from a header file that
+is part of the Library, the object code for the work may be a derivative
+work of the Library even though the source code is not. Whether this is
+true is especially significant if the work can be linked without the
+Library, or if the work is itself a library. The threshold for this to be
+true is not precisely defined by law.
+
+If such an object file uses only numerical parameters, data structure
+layouts and accessors, and small macros and small inline functions (ten
+lines or less in length), then the use of the object file is unrestricted,
+regardless of whether it is legally a derivative work. (Executables
+containing this object code plus portions of the Library will still fall
+under Section 6.)
+
+Otherwise, if the work is a derivative of the Library, you may distribute
+the object code for the work under the terms of Section 6. Any executables
+containing that work also fall under Section 6, whether or not they are
+linked directly with the Library itself.
+
+6. As an exception to the Sections above, you may also combine or link a
+"work that uses the Library" with the Library to produce a work containing
+portions of the Library, and distribute that work under terms of your
+choice, provided that the terms permit modification of the work for the
+customer's own use and reverse engineering for debugging such modifications.
+
+You must give prominent notice with each copy of the work that the Library
+is used in it and that the Library and its use are covered by this License.
+You must supply a copy of this License.If the work during execution displays
+copyright notices, you must include the copyright notice for the Library
+among them, as well as a reference directing the user to the copy of this
+License. Also, you must do one of these things:
+
+
+a) Accompany the work with the complete corresponding machine-readable
+   source code for the Library including whatever changes were used in the
+   work (which must be distributed under Sections 1 and 2 above); and, if
+   the work is an executable linked with the Library, with the complete
+   machine-readable "work that uses the Library", as object code and/or
+   source code, so that the user can modify the Library and then relink to
+   produce a modified executable containing the modified Library. (It is
+   understood that the user who changes the contents of definitions files
+   in the Library will not necessarily be able to recompile the application
+   to use the modified definitions.)
+b) Use a suitable shared library mechanism for linking with the Library. A
+   suitable mechanism is one that (1) uses at run time a copy of the library
+   already present on the user's computer system, rather than copying
+   library functions into the executable, and (2) will operate properly
+   with a modified version of the library, if the user installs one, as
+   long as the modified version is interface-compatible with the version
+   that the work was made with.
+c) Accompany the work with a written offer, valid for at least three years,
+   to give the same user the materials specified in Subsection 6a, above,
+   for a charge no more than the cost of performing this distribution.
+d) If distribution of the work is made by offering access to copy from a
+   designated place, offer equivalent access to copy the above specified
+   materials from the same place.
+e) Verify that the user has already received a copy of these materials or
+   that you have already sent this user a copy.
+
+For an executable, the required form of the "work that uses the Library"
+must include any data and utility programs needed for reproducing the
+executable from it. However, as a special exception, the materials to be
+distributed need not include anything that is normally distributed (in
+either source or binary form) with the major components (compiler, kernel,
+and so on) of the operating system on which the executable runs, unless
+that component itself accompanies the executable.
+
+It may happen that this requirement contradicts the license restrictions of
+other proprietary libraries that do not normally accompany the operating
+system. Such a contradiction means you cannot use both them and the Library
+together in an executable that you distribute.
+
+7. You may place library facilities that are a work based on the Library
+side-by-side in a single library together with other library facilities not
+covered by this License, and distribute such a combined library, provided
+that the separate distribution of the work based on the Library and of the
+other library facilities is otherwise permitted, and provided that you do
+these two things:
+
+
+a) Accompany the combined library with a copy of the same work based on the
+   Library, uncombined with any other library facilities. This must be
+   distributed under the terms of the Sections above.
+b) Give prominent notice with the combined library of the fact that part of
+   it is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+8. You may not copy, modify, sublicense, link with, or distribute the
+Library except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense, link with, or distribute the Library
+is void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+9. You are not required to accept this License, since you have not signed
+it. However, nothing else grants you permission to modify or distribute the
+Library or its derivative works. These actions are prohibited by law if you
+do not accept this License. Therefore, by modifying or distributing the
+Library (or any work based on the Library), you indicate your acceptance of
+this License to do so, and all its terms and conditions for copying,
+distributing or modifying the Library or works based on it.
+
+10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the original
+licensor to copy, distribute, link with or modify the Library subject to
+these terms and conditions. You may not impose any further restrictions on
+the recipients' exercise of the rights granted herein. You are not
+responsible for enforcing compliance by third parties with this License.
+
+11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot distribute so
+as to satisfy simultaneously your obligations under this License and any
+other pertinent obligations, then as a consequence you may not distribute
+the Library at all. For example, if a patent license would not permit
+royalty-free redistribution of the Library by all those who receive copies
+directly or indirectly through you, then the only way you could satisfy
+both it and this License would be to refrain entirely from distribution of
+the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents
+or other property right claims or to contest validity of any such claims;
+this section has the sole purpose of protecting the integrity of the free
+software distribution system which is implemented by public license
+practices. Many people have made generous contributions to the wide range
+of software distributed through that system in reliance on consistent
+application of that system; it is up to the author/donor to decide if he or
+she is willing to distribute software through any other system and a
+licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+12. If the distribution and/or use of the Library is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Library under this License may add an
+explicit geographical distribution limitation excluding those countries, so
+that distribution is permitted only in or among countries not thus excluded.
+In such case, this License incorporates the limitation as if written in the
+body of this License.
+
+13. The Free Software Foundation may publish revised and/or new versions of
+the Lesser General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Library does not specify a license version
+number, you may choose any version ever published by the Free Software
+Foundation.
+
+14. If you wish to incorporate parts of the Library into other free programs
+whose distribution conditions are incompatible with these, write to the
+author to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO
+THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY
+PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+CORRECTION.
+
+16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER
+SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
\ No newline at end of file
diff --git a/doc/objects.tex b/doc/objects.tex
new file mode 100644
index 0000000..361400a
--- /dev/null
+++ b/doc/objects.tex
@@ -0,0 +1,1837 @@
+% $Id: objects.tex 347 2008-02-25 00:53:43Z Franz $
+\chapter{Classes and Objects\label{pyclips-objects}}
+
+As previously stated in the introduction, \pyclips{} provides classes and
+objects to access CLIPS ``\emph{entities}''. It could be preferable to
+refer to counterparts ``living'' in the CLIPS subsystem as \emph{entities}
+than as \emph{objects}, because it is common practice in OOP to give
+the name of ``\emph{objects}'' to class instances: since CLIPS has its
+own object oriented structure (in fact there are \emph{classes} in
+CLIPS, and therefore also \emph{instances} of these), calling these
+structures simply \emph{objects} may generate confusion.
+
+Entities in CLIPS are generated by \emph{constructs}, one for each type
+of entity. In Python, the common way to create something is to instance
+an \code{object} for a certain \keyword{class}. So it seemed straightforward
+to make a class for each of these entities, and to substitute the constructs
+used in CLIPS to create entities with \emph{factory functions}. These
+functions are defined at module level, and have names of the type
+\function{Build\emph{Entity}()} where \function{\emph{Entity}} is the
+type of entity that has to be created. The only exception for this are
+\class{Fact} objects, which are created in several ways from
+\class{Template}s or \function{Assert}ions.
+
+There is another way to create entities in the CLIPS subsystem, that is
+directly using the \function{Build()} function with a full CLIPS
+construct as string argument. However, this function does not return
+anything to the caller, so the created entity has to be sought after
+creation to obtain a reference.
+
+The \function{Build\emph{Entity}()} functions and the \function{Assert()}
+function return objects of proper types (whose detailed list is given
+below) which shadow the corresponding entities in the CLIPS space.
+
+\note{Many objects in \pyclips{} have common features\footnote{The
+current \pyclips{} implementation still does not make use of inheritance,
+although it's likely that a future release will do.}, such as a
+\emph{factory function} as stated above, or methods returning their name
+or their so-called \emph{pretty-print form}: in the following detailed
+documentation only the first occurrence of a feature will be described
+thoroughly.}
+
+
+
+\section{Wrapper Classes\label{pyclips-cl-wrapper}}
+
+There are some simple classes that deserve a special mention in the
+\pyclips{} module, used to represent in Python namespace the basic types
+in CLIPS. These \emph{wrappers} are used to differentiate values that
+CLIPS returns from other values that live in the Python space.
+However these classes are equivalent to their Python counterparts, and
+there is no need to pass objects converted to these classes to the module
+functions. Here is a list containing the class names and their
+equivalents in Python:
+
+\begin{tableiii}{l|l|l}{class}{Class}{Type}{Python Equivalent}
+	\lineiii{Integer}{\var{ClipsIntegerType}}{\class{int}}
+	\lineiii{Float}{\var{ClipsFloatType}}{\class{float}}
+	\lineiii{String}{\var{ClipsStringType}}{\class{str}}
+	\lineiii{Symbol}{\var{ClipsSymbolType}}{\class{str}}
+	\lineiii{InstanceName}{\var{ClipsInstanceNameType}}{\class{str}}
+	\lineiii{Multifield}{\var{ClipsMultifieldType}}{\class{list}}
+\end{tableiii}
+
+A special object named \var{Nil} is defined, and is equivalent to
+\code{Symbol('nil')} in comparisons and slot assignments. It is provided
+to make code more readable in such situations. It has to be noticed that
+also \var{Nil} evaluates to \var{False} in boolean tests: this also
+yields for the explicit \code{Symbol('nil')} and \code{Symbol('FALSE')}
+definitions\footnote{In this \class{Symbol} is different from \class{str}
+as only the empty string evaluates to false in Python. However, it seemed
+closer to the assumption that symbols in CLIPS are not to be considered
+as ``\emph{literals}'' (they are more similar to implicitly defined
+variables) to implement such behaviour, that can be reverted with an
+explicit conversion to \class{str}.}.
+
+
+\section{Template\label{pyclips-cl-Template}}
+
+\class{Template}s are used to build \class{Fact} objects, that is, they
+provide a systematic way to construct \class{Fact}s sharing a common
+pattern, and the only way to define \class{Fact}s that have named
+\class{Slots} (the equivalent of record \emph{fields} or \emph{structure
+members} in other programming languages).
+
+\begin{classdesc*}{Template}
+
+This represents a copy of a \code{deftemplate} construct in the CLIPS
+subsystem, and not a true \code{deftemplate} entity. More than one
+\class{Template} object in Python can refer to the same
+\code{deftemplate} entity in the CLIPS subsystem.
+
+\begin{methoddesc}{BuildFact}{}
+Build a \class{Fact} object using this \class{Template} without
+asserting it. The created \class{Fact} \var{Slots} can be modified and
+the \class{Fact} asserted using its \function{Assert} method.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Deletable}
+Read-only property to verify if this \class{Template} can be deleted
+from the CLIPS subsystem.
+\end{memberdesc}
+
+\begin{methoddesc}{InitialFact}{}
+Return initial \class{Fact} in list created using this \class{Template}.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Module}
+Read-only property to retrieve the CLIPS name of the \class{Module}
+where the \class{Template} is defined.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Name}
+Read-only property returning the name in CLIPS of this \class{Template}.
+The name identifies this entity in the CLIPS subsystem, and has nothing
+to do with the name given to the corresponding object in Python.
+\end{memberdesc}
+
+\begin{methoddesc}{Next}{}
+Return next\footnote{CLIPS stores its objects (or entities) in ordered
+lists, so it makes sense to ``iterate'' over these lists. However this
+implementation of \pyclips{} does not implement \emph{iterators} (as
+known in Python) on these classes: a way to do this is currently under
+examination.} \class{Template} in the list of all \class{Template}s.
+\var{None} is returned at the end of the list.
+\end{methoddesc}
+
+\begin{methoddesc}{NextFact}{fact}
+Return next \class{Fact} in list created using this \class{Template},
+using the supplied \var{fact} as offset.
+\end{methoddesc}
+
+\begin{methoddesc}{PPForm}{}
+Return the \emph{pretty-print form} of this \class{Template}.
+\emph{Pretty-print forms} are often the code necessary to build a
+construct in CLIPS, formatted in a way that makes it quite readable.
+The result of the \function{PPForm()} method can be used as the argument
+for the \function{Build()} top level function to rebuild the construct
+once the \class{Environment} has been cleared\footnote{Actually
+\emph{pretty-print forms} use fixed size buffers to build the representing
+string: when such a form is too complex, the default buffer size of 8192
+bytes can be insufficient. In this case the \emph{PPBufferSize} property
+of the \emph{Memory} object can be used to allow the creation of properly
+sized buffers.}.
+\end{methoddesc}
+
+\begin{methoddesc}{Remove}{}
+Remove the entity corresponding to this \class{Template} from the CLIPS
+subsystem. This does not remove the corresponding Python object that has
+instead to be deleted via the \keyword{del} statement or garbage
+collected.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Slots}
+\class{Deftemplate} \code{slots} information. This is itself an
+object, having many methods, and deserves a special explaination.
+\begin{methoddesc}{AllowedValues}{name}
+Return a list of allowed values for \code{slot} specified by \var{name}.
+\end{methoddesc}
+\begin{methoddesc}{Cardinality}{name}
+Return \emph{cardinality} for \code{slot} specified by \var{name}.
+\end{methoddesc}
+\begin{methoddesc}{DefaultValue}{name}
+Return \emph{cardinality} for \code{slot} specified by \var{name}.
+\end{methoddesc}
+\begin{methoddesc}{Exists}{name}
+Return \constant{True} if \code{slot} specified by \var{name} exists,
+\constant{False} otherwise.
+\end{methoddesc}
+\begin{methoddesc}{HasDefault}{name}
+Return one of the following values: \constant{NO_DEFAULT} if the
+default value is set to \code{?NONE}, \constant{STATIC_DEFAULT} when
+the default value is static and \constant{DYNAMIC_DEFAULT} when it
+is dynamically generated (eg. \code{gensym}).
+\end{methoddesc}
+\begin{methoddesc}{IsMultifileld}{name}
+Return \constant{True} if \code{slot} specified by \var{name} is
+a \code{Multifield} value, \constant{False} otherwise.
+\end{methoddesc}
+\begin{methoddesc}{IsSinglefield}{name}
+Return \constant{True} if \code{slot} specified by \var{name} is
+a single field value, \constant{False} otherwise.
+\end{methoddesc}
+\begin{methoddesc}{Names}{}
+Return the list of \code{slot} names.
+\end{methoddesc}
+\begin{methoddesc}{Range}{name}
+Return \emph{numerical range information} for \code{slot} specified by
+\var{name}.
+\end{methoddesc}
+\begin{methoddesc}{Types}{name}
+Return names of \emph{primitive types} for \code{slot} specified by
+\var{name}.
+\end{methoddesc}
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Watch}
+Read-only property to verify if this \class{Template} is being watched.
+\end{memberdesc}
+
+The name of this entity in CLIPS is also returned by the string coercion
+function. The \emph{factory function} for \class{Template}s is
+\function{BuildTemplate()}, which has been discussed above.
+
+\end{classdesc*}
+
+
+
+\section{Fact\label{pyclips-cl-Fact}}
+
+\class{Fact}s are one of the main entities in CLIPS, since it is
+whether a \class{Fact} exists or not of that drives the subsystem in
+the decision to fire or not certain \class{Rule}s. \class{Fact}s, as
+seen above, can be created in several ways, that is either by directly
+asserting sentences in string form, or by building them first from
+\class{Template}s and then asserting them.
+
+
+\begin{classdesc*}{Fact}
+
+This represents a copy of a fact definition in the CLIPS subsystem, and
+not a true fact entity. More than one Fact objects in Python can refer to
+the same fact entity in the CLIPS subsystem. Many CLIPS functions return
+a \class{Fact} object, but most \class{Fact} objects obtained from CLIPS
+are \emph{read-only}\footnote{Actually, the main rule is that if a
+\class{Fact} has been \function{Assert}ed then it is read-only. Note that
+all \emph{shadow representations} of CLIPS asserted \code{fact} entities
+are read-only.}. Read-only \class{Fact}s cannot be reasserted or modified
+in \var{Slots}, and are provided for ``informational'' purposes only.
+
+The argument can be a string with the same format of the
+\function{Assert()} function seen in the previous chapter: in this case
+the fact is created and asserted. Otherwise the argument can be a
+\class{Template} object, and in this case the resulting \class{Fact} can
+be modified and then asserted via the \function{Assert()} member
+function.
+
+\begin{methoddesc}{Assert}{}
+Assert this \class{Fact}. Only \class{Fact}s that have been constructed
+from \class{Template}s can be \function{Assert}ed using this method:
+read-only \class{Fact}s can only be inspected with the other
+methods/properties.
+\end{methoddesc}
+
+\begin{methoddesc}{AssignSlotDefaults}{}
+Assign default values to \var{Slots} of this \class{Fact}.
+\end{methoddesc}
+
+\begin{methoddesc}{CleanPPForm}{}
+Return only the second part of this \class{Fact}s \emph{pretty-print form}
+-- which can be used to build the \class{Fact} itself as described above.
+\end{methoddesc}
+
+\begin{memberdesc}{Exists}{}
+Is \constant{True} if this \class{Fact} has been asserted (and never
+retracted), \constant{False} otherwise.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{ImpliedSlots}
+The list of all \emph{implied} \var{Slots} for this \class{Fact}.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Index}
+Read-only property returning the index in CLIPS of this \class{Fact}. As
+for other entities the \var{Name} is a unique identifier, as is the
+\var{Index} for \class{Fact}s.
+\end{memberdesc}
+
+\begin{methoddesc}{Next}{}
+Return next \class{Fact} in the list of all \class{Fact}s. This list is
+not based on \class{Module}s, but global to the CLIPS subsystem.
+\end{methoddesc}
+
+\begin{methoddesc}{PPForm}{}
+Return the \emph{pretty-print form} of this \class{Fact}. In this case,
+only the second part of the returned string (the one between parentheses)
+can be used to build the \class{Fact} via the \function{Assert()}
+function\footnote{This is also not always true: as said before, there is
+no way to \function{Assert} \class{Fact}s that have named slots using a
+string if there is not a \code{deftemplate} for this kind of
+\class{Fact}. However, once a \class{Template} with the specified slots
+has been created, this becomes possible.}.
+\end{methoddesc}
+
+\begin{methoddesc}{PPrint}{\optional{ignoredefaults}}
+Print the \class{Fact} to the standard output. When \var{ignoredefaults}
+is set to \constant{True} (the default), slots containing the default
+values are omitted.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Relation}
+Return only the name of the \emph{relation} that identifies this
+\class{Fact}\footnote{The authors of CLIPS call a \emph{relation} the first
+field of the \class{Fact} itself, although it is not needed to actually
+represent a real relationship.} as a \class{Symbol}.
+\end{memberdesc}
+
+\begin{methoddesc}{Retract}{}
+Retract this \class{Fact}: in other words, remove the corresponding
+entity from the CLIPS subsystem. As in \function{Remove()} seen above,
+this does not delete the corresponding Python object. \var{None} is
+returned at the end of the list.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Slots}
+Dictionary of \class{Fact} \var{Slots}. This member \emph{behaves} like
+a \class{dict}, but is not related to such objects. In fact, the values
+of \code{slots} are accessible using a \class{dict}-like syntax (square
+brackets), but not all the members of \class{dict} are implemented.
+\end{memberdesc}
+
+Please note that \class{Fact}s have slightly different methods than
+classes representing other entities in CLIPS: an instance of \class{Fact}
+is created using the module-level \function{Assert()} function, and
+removed using the \function{Retract()} member function: this syntax,
+closer to the original CLIPS form, was seen as the preferred method instead
+of using a name such as \function{BuildFact()} for creation and a
+\function{Remove()} member because of the particular nature of \class{Fact}
+related to other types of entity.
+
+Here is an example of usage of \class{Fact} and \class{Template} objects:
+
+\begin{verbatim}
+>>> import clips
+>>> clips.Reset()
+>>> t0 = clips.BuildTemplate("person", """
+    (slot name (type STRING))
+    (slot age (type INTEGER))
+""", "template for a person")
+>>> print t0.PPForm()
+(deftemplate MAIN::person "template for a person"
+   (slot name (type STRING))
+   (slot age (type INTEGER)))
+
+>>> f1 = clips.Fact(t0)
+>>> f1_slotkeys = f1.Slots.keys()
+>>> print f1_slotkeys
+<Multifield [<Symbol 'name'>, <Symbol 'age'>]>
+>>> f1.Slots['name'] = "Grace"
+>>> f1.Slots['age'] = 24
+>>> print f1.PPForm()
+f-0     (person (name "Grace") (age 24))
+>>> clips.PrintFacts()
+f-0     (initial-fact)
+>>> f1.Assert()
+<Fact 'f-1': fact object at 0x00E0CB10>
+>>> print f1.Exists()
+True
+>>> clips.PrintFacts()
+f-0     (initial-fact)
+f-1     (person (name "Grace") (age 24))
+For a total of 2 facts.
+>>> f1.Retract()
+>>> print f1.Exists()
+False
+>>> clips.PrintFacts()
+f-0     (initial-fact)
+For a total of 1 fact.
+\end{verbatim}
+
+Please note that slot names are implemented as \class{Symbol}s, and the
+list of \var{Slots} is returned as a \class{Multifield}. Also note that
+the \class{Fact} \var{f1}, that has been constructed from a
+\class{Template} (and not yet \function{Assert}ed) object and then
+modified using the \var{Slots} property, can be \function{Assert}ed while
+other \class{Fact}s built from construct strings cannot.
+
+\end{classdesc*}
+
+
+
+\section{Deffacts\label{pyclips-cl-Deffacts}}
+
+A \class{Deffacts} is used to modify the ``initial structure'' of a CLIPS
+environment, by allowing some \class{Fact}s to be \function{Assert}ed by
+default each time the \function{Reset()} function is called.
+
+\begin{classdesc*}{Deffacts}
+
+This represents a copy of a \code{deffacts} construct in the CLIPS
+subsystem, and not a true \code{deffacts} entity. More than one
+\class{Deffacts} object in Python can refer to the same \code{deffacts}
+entity in the CLIPS subsystem.
+
+\begin{memberdesc}[property]{Deletable}
+Read-only property to verify if this \class{Deffacts} can be deleted.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Module}
+Read-only property to retrieve the CLIPS name of the \class{Module}
+where the \class{Deffacts} is defined.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Name}
+Read-only property returning the name in CLIPS of this \class{Deffacts}.
+\end{memberdesc}
+
+\begin{methoddesc}{Next}{}
+Return next \class{Deffacts} in the list of all \class{Deffacts}.
+\var{None} is returned at the end of the list.
+\end{methoddesc}
+
+\begin{methoddesc}{PPForm}{}
+Return the \emph{pretty-print form} of this \class{Deffacts}.
+\end{methoddesc}
+
+\begin{methoddesc}{Remove}{}
+Remove the entity corresponding to this \class{Deffacts} from the CLIPS
+subsystem.
+\end{methoddesc}
+
+The name of this entity in CLIPS is also returned by the string coercion
+function. The \emph{factory function} for \class{Deffacts} is
+\function{BuildDeffacts()}, which has been discussed above.
+
+\end{classdesc*}
+
+
+
+\section{Rule\label{pyclips-cl-Rule}}
+
+The construct defines rules to be activated and then \emph{fired} whenever
+particular conditions are met. This construct is in fact the counterpart
+of the \code{defrule} construct in CLIPS. Normally conditions that fire
+\class{Rule}s are \class{Fact}s \function{Assert}ed during a session.
+
+\begin{classdesc*}{Rule}
+
+This represents a copy of a \code{defrule} construct in the CLIPS
+subsystem, and not a true \code{defrule} entity. More than one
+\class{Rule} object in Python can refer to the same \code{defrule}
+entity in the CLIPS subsystem.
+
+\begin{memberdesc}[property]{Breakpoint}
+Set or remove a breakpoint from this \class{Rule}.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Deletable}
+Read-only property to verify if this \class{Rule} can be deleted.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Module}
+Read-only property to retrieve the CLIPS name of the \class{Module}
+where the \class{Rule} is defined.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Name}
+Read-only property returning the name in CLIPS of this \class{Rule}.
+\end{memberdesc}
+
+\begin{methoddesc}{Next}{}
+Return next \class{Rule} in the list of all \class{Rule}s. \var{None} is
+returned at the end of the list.
+\end{methoddesc}
+
+\begin{methoddesc}{PPForm}{}
+Return the \emph{pretty-print form} of this \class{Rule}.
+\end{methoddesc}
+
+\begin{methoddesc}{PrintMatches}{}
+Print partial matches of this \class{Rule} to standard output.
+\end{methoddesc}
+
+\begin{methoddesc}{Refresh}{}
+Refresh this \class{Rule}.
+\end{methoddesc}
+
+\begin{methoddesc}{Remove}{}
+Remove the entity corresponding to this \class{Rule} from the CLIPS
+subsystem.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{WatchActivations}
+Set or reset debugging of \emph{activations} for this \class{Rule}.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{WatchFirings}
+Set or reset debugging of \emph{firings} for this \class{Rule}.
+\end{memberdesc}
+
+The name of this entity in CLIPS is also returned by the string coercion
+function. The \emph{factory function} for \class{Rule}s is
+\function{BuildRule()}, which has been discussed above.
+
+\end{classdesc*}
+
+An example -- derived from the ones present in the standard CLIPS
+documentation -- may be useful here:
+
+\begin{verbatim}
+>>> clips.Reset()
+>>> r1 = clips.BuildRule("duck-rule", "(duck)",
+                         "(assert (quack))", "The Duck rule")
+>>> print r1.PPForm()
+(defrule MAIN::duck-rule "The Duck rule"
+   (duck)
+   =>
+   (assert (quack)))
+
+>>> clips.PrintFacts()
+f-0     (initial-fact)
+For a total of 1 fact.
+>>> clips.PrintRules()
+MAIN:
+duck-rule
+>>> f1 = clips.Assert("(duck)")
+>>> clips.PrintAgenda()
+MAIN:
+   0      duck-rule: f-1
+For a total of 1 activation.
+>>> clips.PrintFacts()
+f-0     (initial-fact)
+f-1     (duck)
+For a total of 2 facts.
+>>> clips.Run()
+>>> clips.PrintFacts()
+f-0     (initial-fact)
+f-1     (duck)
+f-2     (quack)
+For a total of 3 facts.
+\end{verbatim}
+
+
+
+\section{Activation\label{pyclips-cl-Activation}}
+
+\class{Rule} \class{Activation}s are only returned by the CLIPS
+subsystem, and cannot be created -- thus there is no \emph{factory
+function} for these objects. CLIPS provides \class{Activation} objects
+to keep the program flow under control.
+
+\begin{classdesc*}{Activation}
+
+This represents a copy of an \code{activation} object in the CLIPS
+subsystem, and not a true \code{activation} entity. More than one
+\class{Activation} object in Python can refer to the same
+\code{activation} entity in the CLIPS subsystem.
+
+
+\begin{memberdesc}[property]{Name}
+Retrieve \class{Activation} name.
+\end{memberdesc}
+
+\begin{methoddesc}{Next}{}
+Return next \class{Activation} in the list of all \class{Activation}s.
+\var{None} is returned at the end of the list.
+\end{methoddesc}
+
+\begin{methoddesc}{PPForm}{}
+Return the \emph{pretty-print form} of \class{Activation}.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Salience}
+Retrieve \class{Activation} \emph{salience}\footnote{\emph{Salience} is
+a value that represents the \emph{priority} of a \code{rule} in CLIPS.}.
+\end{memberdesc}
+
+\begin{methoddesc}{Remove}{}
+Remove this \class{Activation} from CLIPS.
+\end{methoddesc}
+
+The name of this entity in CLIPS is also returned by the string coercion
+function.
+
+\end{classdesc*}
+
+
+
+\section{Global\label{pyclips-cl-Global}}
+
+\class{Global} objects represent \emph{global variables} in CLIPS, which
+are normally built using the \code{defglobal} construct. To define a new
+\class{Global} variable the \function{BuildGlobal()} function must be
+used, which returns a new object.
+
+\begin{classdesc*}{Global}
+
+A \class{Global} object represents a copy of a \code{defglobal} construct
+in the CLIPS subsystem, and not a true \code{defglobal} entity. More
+than one \class{Global} object in Python can refer to the same
+\code{defglobal} entity in the CLIPS subsystem.
+
+\begin{memberdesc}[property]{Deletable}
+Verify if this \class{Global} can be deleted.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Module}
+Read-only property to retrieve the CLIPS name of the \class{Module}
+where the \class{Global} is defined.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Name}
+Retrieve \class{Global} name. The returned value is a \class{Symbol}
+containing the name of the global variable in the CLIPS subsystem.
+\end{memberdesc}
+
+\begin{methoddesc}{Next}{}
+Return next \class{Global} in the list of all global variables. \var{None}
+is returned at the end of the list.
+\end{methoddesc}
+
+\begin{methoddesc}{PPForm}{}
+Return the \emph{pretty-print} form of \class{Global}.
+\end{methoddesc}
+
+\begin{methoddesc}{Remove}{}
+Remove this \class{Global} from CLIPS subsystem.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Value}
+Set or retrieve \class{Global} value. The returned value can be of many
+types, depending on the type of value contained in the corresponding
+CLIPS global variable.
+\end{memberdesc}
+
+\begin{methoddesc}{ValueForm}{}
+Return a ``\emph{printed}'' form of \class{Global} value. The
+\emph{printed} form is the one that would be used in CLIPS to represent
+the variable itself.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Watch}
+Set or retrieve \class{Global} debug status.
+\end{memberdesc}
+
+Some examples follow to show the use of \class{Global} objects:
+
+\begin{verbatim}
+>>> g_x = clips.BuildGlobal("x", 15)
+\end{verbatim}
+
+This is equivalent to the CLIPS declaration:
+
+\begin{verbatim}
+CLIPS> (defglobal ?*x* = 15)
+\end{verbatim}
+
+Some of the \class{Global} methods are illustrated here:
+
+\begin{verbatim}
+>>> g_x
+<Global 'x': defglobal object at 0x00E09960>
+>>> print g_x
+x
+>>> g_x.Value
+<Integer 15>
+>>> print g_x.Value
+15
+>>> print g_x.ValueForm()
+?*x* = 15
+\end{verbatim}
+
+The name of this entity in CLIPS is also returned by the string coercion
+function.
+
+\end{classdesc*}
+
+
+
+\section{Function\label{pyclips-cl-Function}}
+
+Objects of this type represent newly defined \emph{functions}
+(usually via the CLIPS \code{deffunction} construct) in the CLIPS
+subsystem. In fact the \function{BuildFunction()} function described
+above, which returns a \class{Function} object, corresponds to the
+\code{deffunction} construct.
+
+\begin{classdesc*}{Function}
+
+This represents a copy of a \code{deffunction} construct in the CLIPS
+subsystem, and not a true \code{deffunction} entity. More than one
+\class{Function} object in Python can refer to the same
+\code{deffunction} entity in the CLIPS subsystem.
+
+\begin{methoddesc}{Call}{\optional{*args}}
+Call this \class{Function} with the given arguments, if any. If one only
+argument is passed and it is a \class{str}, then it is considered a
+``list of whitespace separated arguments\footnote{See the syntax for
+the toplevel function with the same name.}'' and follows the CLIPS
+syntax: in order to pass a single string it has to be explicitly cast
+to the \class{String} \emph{wrapper class}. Conversion to \emph{wrapper
+classes} is however recommended for all passed arguments.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Deletable}
+Verify if this \class{Function} can be deleted.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Module}
+Read-only property to retrieve the CLIPS name of the \class{Module}
+where the \class{Function} is defined.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Name}
+Retrieve \class{Function} name.
+\end{memberdesc}
+
+\begin{methoddesc}{Next}{}
+Return next \class{Function} in the list of all CLIPS functions. \var{None}
+is returned at the end of the list.
+\end{methoddesc}
+
+\begin{methoddesc}{PPForm}{}
+Return the \emph{pretty-print form} of \class{Function}.
+\end{methoddesc}
+
+\begin{methoddesc}{Remove}{}
+Remove this \class{Function}.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Watch}
+Set or retrieve \class{Function} debug status.
+\end{memberdesc}
+
+The name of this entity in CLIPS is also returned by the string coercion
+function.
+
+\note{Objects of this class are \emph{callable} themselves using the
+syntax \code{object([arg1 [, ... [argN]])}, where the arguments follow
+the same rules as in the \function{Call} method.}
+
+\end{classdesc*}
+
+
+
+\section{Generic\label{pyclips-cl-Generic}}
+
+\class{Generic}s (in CLIPS called \emph{generic functions}) are similar
+to \class{Function}s, but they add \emph{generic programming} capabilities
+to the CLIPS system. Python programmers will find them similar to Python
+functions, since \emph{overloading} is possible within the corresponding
+construct.
+
+Each different implementation (for different argument sets) of a
+\emph{generic function} is called a \code{Method}, and the \class{Generic}
+class provides several ways to inspect the various \code{Method}s.
+\code{Method}s are identified by an \emph{index}.
+
+\begin{classdesc*}{Generic}
+
+This represents a copy of a \code{defgeneric} construct in the CLIPS
+subsystem, and not a true \code{defgeneric} entity. More than one
+\class{Generic} objects in Python can refer to the same
+\code{defgeneric} entity in the CLIPS subsystem.
+
+\begin{methoddesc}{AddMethod}{restrictions, actions\optional{, midx\optional{, comment}}}
+Add a \code{Method} to this \class{Generic}. The structure of this
+function resembles the one of the \function{Build<entity>()} functions:
+in fact this method of \class{Generic} actually implements the
+\code{defmethod} construct which is present in CLIPS. For proper
+documentation of this construct, see the CLIPS reference: the
+\var{restrictions} parameter (which represents the \code{Method}
+\emph{parameter restrictions}) must be expressed \emph{without}
+parentheses; the \var{actions} parameter must be expressed as in the
+\code{defmethod} construct, that is with all the necessary parentheses
+pairs. \var{midx} is the \code{Method} index when it has to be forced
+(optionally). The example below should be explanatory. \var{restrictions}
+can also be expressed as a sequence of tuples, in each of which the
+first element is the argument name (with its proper prefix) as a string
+and the following ones are the actual restrictions, either in string form
+or as CLIPS primitive types -- which can be specified using \pyclips{}
+\emph{wrapper classes} types, see above.
+\end{methoddesc}
+
+\begin{methoddesc}{Call}{\optional{*args}}
+Call this \class{Generic} with the given arguments, if any. If one only
+argument is passed and it is a \class{str}, then it is considered a
+``list of whitespace separated arguments'' and follows the CLIPS
+syntax: in order to pass a single string it has to be explicitly cast
+to the \class{String} \emph{wrapper class}. Conversion to \emph{wrapper
+classes} is however recommended for all passed arguments.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Deletable}
+Verify if this \class{Generic} can be deleted.
+\end{memberdesc}
+
+\begin{methoddesc}{InitialMethod}{}
+Return the index of first \code{Method} in this \class{Generic}.
+\end{methoddesc}
+
+\begin{methoddesc}{MethodDeletable}{midx}
+Test whether or not specified \code{Method} can be deleted from this
+\class{Generic}.
+\end{methoddesc}
+
+\begin{methoddesc}{MethodDescription}{midx}
+Return the synopsis of specified \code{Method} \emph{restrictions}.
+\end{methoddesc}
+
+\begin{methoddesc}{MethodList}{}
+Return the list of \code{Method} indices for this \class{Generic}.
+\end{methoddesc}
+
+\begin{methoddesc}{MethodPPForm}{midx}
+Return the \emph{pretty-print form} of specified \code{Method}.
+\end{methoddesc}
+
+\begin{methoddesc}{MethodRestrictions}{midx}
+Return the \emph{restrictions} of specified \code{Method} in this
+\class{Generic} object: the \var{midx} parameter must be an
+\class{Integer} or \class{int} indicating the \code{Method} index.
+\end{methoddesc}
+
+\begin{methoddesc}{MethodWatched}{midx}
+Test whether or not specified \code{Method} is being watched.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Module}
+Read-only property to retrieve the CLIPS name of the \class{Module}
+where the \class{Generic} is defined.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Name}
+Retrieve \class{Generic} name.
+\end{memberdesc}
+
+\begin{methoddesc}{NextMethod}{midx}
+Return the index of next \code{Method} in this \class{Generic} given
+the start index as an \class{Integer} or \class{int}.
+\end{methoddesc}
+
+\begin{methoddesc}{PPForm}{}
+Return the \emph{pretty-print form} of \class{Generic}.
+\end{methoddesc}
+
+\begin{methoddesc}{PrintMethods}{}
+Print out \code{Method} list for this \class{Generic}.
+\end{methoddesc}
+
+\begin{methoddesc}{Remove}{}
+Remove this \class{Generic}.
+\end{methoddesc}
+
+\begin{methoddesc}{RemoveMethod}{midx}
+Remove specified \code{Method} from this \class{Generic}.
+\end{methoddesc}
+
+\begin{methoddesc}{UnwatchMethod}{midx}
+Deactivate watch on specified \code{Method}.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Watch}
+Set or retrieve \class{Generic} debug status.
+\end{memberdesc}
+
+\begin{methoddesc}{WatchMethod}{midx}
+Activate watch on specified \code{Method}.
+\end{methoddesc}
+
+The name of this entity in CLIPS is also returned by the string coercion
+function. The \emph{factory function} for \class{Generic}s is
+\function{BuildGeneric()}, which has been discussed above.
+
+\note{Objects of this class are \emph{callable} themselves using the
+syntax \code{object([arg1 [, ... [argN]])}, where the arguments follow
+the same rules as in the \function{Call} method.}
+
+An example for this class follows.
+
+\begin{verbatim}
+>>> import clips
+>>> addf = clips.BuildGeneric("my-addf", "my generic add function")
+>>> addf.AddMethod("(?a STRING)(?b STRING)", "(str-cat ?a ?b)")
+>>> addf.AddMethod("(?a INTEGER)(?b INTEGER)", "(+ ?a ?b)")
+>>> addf.PrintMethods()
+my-addf #1  (STRING) (STRING)
+my-addf #2  (INTEGER) (INTEGER)
+For a total of 2 methods.
+>>> print addf.MethodPPForm(1)
+(defmethod MAIN::my-addf
+   ((?a STRING)
+    (?b STRING))
+   (str-cat ?a ?b))
+
+>>> print addf.PPForm()
+(defgeneric MAIN::my-addf "my generic add function")
+
+>>> print clips.Eval('(my-addf 5 13)')
+18
+>>> print clips.Eval('(my-addf "hello,"(my-addf " " "world!"))')
+hello, world!
+>>> print clips.Eval('(my-addf "hello" 13)')
+Traceback (most recent call last):
+  File "<pyshell#14>", line 1, in ?
+    print clips.Eval('(my-addf "hello" 13)')
+  File ".../_clips_wrap.py", line 2472, in Eval
+    return _cl2py(_c.eval(expr))
+ClipsError: C10: unable to evaluate expression
+>>> s = clips.ErrorStream.Read()
+>>> print s
+[GENRCEXE1] No applicable methods for my-addf.
+\end{verbatim}
+
+\end{classdesc*}
+
+Please note how the \emph{error stream} (\var{ErrorStream}) can be used
+to retrieve a more explanatory text for the error. The \emph{error
+stream} can be very useful during interactive debugging \pyclips{}
+sessions to fix errors.
+
+
+
+\section{Class\label{pyclips-cl-Class}}
+
+\class{Class} objects are \code{class} definition constructs, the most
+important feature of the \emph{COOL}\footnote{Acronym for CLIPS
+Object-Oriented Language.} sublanguage of CLIPS. As in other OOP
+environments, \code{class}es represent in CLIPS new data types (often
+resulting from aggregation of simpler data types) which have particular ways
+of being handled. Normally, as in Python, these particular ways are called
+\emph{methods}\footnote{Note that the term \code{Method} has been used
+for function overloading in the definition of \class{Generic}
+functions.}, while in CLIPS they are called \emph{message handlers},
+since to apply a method to a CLIPS object (in fact, the \class{Instance}
+of a \class{Class} in \pyclips{}) a \emph{message} has to be sent to that
+object.
+
+\begin{classdesc*}{Class}
+
+This represents a copy of a \code{defclass} construct in the CLIPS
+subsystem, and not a true \code{defclass} entity. More than one
+\class{Class} object in Python can refer to the same \code{defclass}
+entity in the CLIPS subsystem.
+
+\begin{memberdesc}[property]{Abstract}
+Verify if this \class{Class} is \emph{abstract} or not.
+\end{memberdesc}
+
+\begin{methoddesc}{AddMessageHandler}{name, args, text \optional{, type, comment}}
+Add a new \emph{message handler} to this class, with specified name,
+body (the \var{text} argument) and argument list: this can be
+specified either as a sequence of variable names or as a single string
+of whitespace separated variable names. Variable names (expressed as
+strings) can also be \emph{wildcard parameters}, as specified in the
+\clipsbpg{}. The \var{type} parameter should be one of \var{AROUND},
+\var{AFTER}, \var{BEFORE}, \var{PRIMARY} defined at the module level:
+if omitted it will be considered as \var{PRIMARY}. The body must be
+enclosed in brackets, as it is in CLIPS syntax. The function returns
+the \emph{index} of the \emph{message handler} within this \class{Class}.
+\end{methoddesc}
+
+\begin{methoddesc}{AllMessageHandlerList}{}
+Return the list of \code{MessageHandler} constructs of this \class{Class}
+including the ones that have been inherited from the superclass.
+\end{methoddesc}
+
+\begin{methoddesc}{BuildInstance}{name, \optional{overrides}}
+Build an \class{Instance} of this \class{Class} with the supplied name
+and overriding specified \code{slots}. If no \code{slot} is specified
+to be overridden, then the \class{Instance} will assume default values.
+\end{methoddesc}
+
+\begin{methoddesc}{BuildSubclass}{name, text \optional{, comment}}
+Build a subclass of this \class{Class} with specified name and body.
+\var{comment} is the optional comment to give to the object.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Deletable}
+Verify if this \class{Class} can be deleted.
+\end{memberdesc}
+
+\begin{methoddesc}{Description}{}
+Return a summary of \class{Class} description.
+\end{methoddesc}
+
+\begin{methoddesc}{InitialInstance}{}
+Return initial \class{Instance} of this \class{Class}. It raises an
+error if the \class{Class} has no subclass \class{Instance}s.
+\end{methoddesc}
+
+\begin{methoddesc}{InitialSubclassInstance}{}
+Return initial instance of this \class{Class} including its subclasses. It
+raises an error if the \class{Class} has no subclass \class{Instance}s.
+\end{methoddesc}
+
+\begin{methoddesc}{IsSubclassOf}{o}
+Test whether this \class{Class} is a subclass of specified \class{Class}.
+\end{methoddesc}
+
+\begin{methoddesc}{IsSuperclassOf}{o}
+Test whether this \class{Class} is a superclass of specified
+\class{Class}.
+\end{methoddesc}
+
+\begin{methoddesc}{MessageHandlerDeletable}{index}
+Return true if specified \code{MessageHandler} can be deleted.
+\end{methoddesc}
+
+\begin{methoddesc}{MessageHandlerIndex}{name \optional{, htype}}
+Find the specified \code{MessageHandler}, given its \var{name} and type
+(as the parameter \var{htype}). If type is omitted, it is considered to
+be \var{PRIMARY}.
+\end{methoddesc}
+
+\begin{methoddesc}{MessageHandlerName}{index}
+Return the name of specified \code{MessageHandler}.
+\end{methoddesc}
+
+\begin{methoddesc}{MessageHandlerList}{}
+Return the list of \code{MessageHandler} constructs for this
+\class{Class}.
+\end{methoddesc}
+
+\begin{methoddesc}{MessageHandlerPPForm}{index}
+Return the \emph{pretty-print form} of \code{MessageHandler}.
+\end{methoddesc}
+
+\begin{methoddesc}{MessageHandlerType}{index}
+Return the type of the \code{MessageHandler} specified by the provided
+\var{index}.
+\end{methoddesc}
+
+\begin{methoddesc}{MessageHandlerWatched}{index}
+Return watch status of specified \code{MessageHandler}.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Module}
+Read-only property to retrieve the CLIPS name of the \class{Module}
+where the \class{Class} is defined.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Name}
+Retrieve \class{Class} name.
+\end{memberdesc}
+
+\begin{methoddesc}{Next}{}
+Return next \class{Class} in the list of all CLIPS \code{classes}.
+\var{None} is returned at the end of the list.
+\end{methoddesc}
+
+\begin{methoddesc}{NextInstance}{instance}
+Return next \class{Instance} of this \class{Class}. Returns \var{None} if
+there are no \class{Instance}s left.
+\end{methoddesc}
+
+\begin{methoddesc}{NextMessageHandlerIndex}{index}
+Return index of next \code{MessageHandler} with respect to the specified
+one.
+\end{methoddesc}
+
+\begin{methoddesc}{NextSubclassInstance}{instance}
+Return next instance of this \class{Class}, including subclasses. Returns
+\var{None} if there are no \class{Instance}s left.
+\end{methoddesc}
+
+\begin{methoddesc}{PPForm}{}
+Return the \emph{pretty-print form} of \class{Class}.
+\end{methoddesc}
+
+\begin{methoddesc}{PreviewSend}{msgname}
+Print list of \code{MessageHandler}s suitable for specified message.
+\end{methoddesc}
+
+\begin{methoddesc}{PrintAllMessageHandlers}{}
+Print the list of all \code{MessageHandler}s for this \class{Class}
+including the ones that have been inherited from the superclass.
+\end{methoddesc}
+
+\begin{methoddesc}{PrintMessageHandlers}{}
+Print the list of \code{MessageHandler}s for this \class{Class}.
+\end{methoddesc}
+
+\begin{methoddesc}{RawInstance}{name}
+Create an empty \class{Instance} of this \class{Class} with specified
+name.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Reactive}
+Verify if this \class{Class} is \emph{reactive} or not.
+\end{memberdesc}
+
+\begin{methoddesc}{Remove}{}
+Remove this \class{Class}.
+\end{methoddesc}
+
+\begin{methoddesc}{RemoveMessageHandler}{index}
+Remove \code{MessageHandler} specified by the provided \var{index}.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Slots}
+\class{Class} \code{slots} information. This is itself an object, having
+many methods, and deserves a special explaination.
+\begin{methoddesc}{AllowedClasses}{name}
+Return a list of allowed class names for \code{slot} specified by
+\var{name}.
+\end{methoddesc}
+\begin{methoddesc}{AllowedValues}{name}
+Return a list of allowed values for \code{slot} specified by \var{name}.
+\end{methoddesc}
+\begin{methoddesc}{Cardinality}{name}
+Return \emph{cardinality} for \code{slot} specified by \var{name}.
+\end{methoddesc}
+\begin{methoddesc}{DefaultValue}{name}
+Return the default value for \code{slot} specified by \var{name}.
+\end{methoddesc}
+\begin{methoddesc}{Exists}{name}
+Return \constant{True} if \code{slot} specified by \var{name} exists,
+\constant{False} otherwise.
+\end{methoddesc}
+\begin{methoddesc}{ExistsDefined}{name}
+Return \constant{True} if \code{slot} specified by \var{name} is defined
+in this \class{Class}, \constant{False} otherwise.
+\end{methoddesc}
+\begin{methoddesc}{Facets}{name}
+Return \emph{facet names} for \code{slot} specified by \var{name}.
+\end{methoddesc}
+\begin{methoddesc}{HasDirectAccess}{name}
+Return \constant{True} if \code{slot} specified by \var{name} is directly
+accessible, \constant{False} otherwise.
+\end{methoddesc}
+\begin{methoddesc}{IsInitable}{name}
+Return \constant{True} if \code{slot} specified by \var{name} is
+\emph{initializable}, \constant{False} otherwise.
+\end{methoddesc}
+\begin{methoddesc}{IsPublic}{name}
+Return \constant{True} if \code{slot} specified by \var{name} is
+\emph{public}, \constant{False} otherwise.
+\end{methoddesc}
+\begin{methoddesc}{IsWritable}{name}
+Return \constant{True} if \code{slot} specified by \var{name} is
+\emph{writable}, \constant{False} otherwise.
+\end{methoddesc}
+\begin{methoddesc}{Names}{}
+Return the list of \code{slot} names.
+\end{methoddesc}
+\begin{methoddesc}{NamesDefined}{}
+Return the list of \code{slot} names explicitly defined in this
+\class{Class}.
+\end{methoddesc}
+\begin{methoddesc}{Range}{name}
+Return \emph{numerical range information} for \code{slot} specified by
+\var{name}.
+\end{methoddesc}
+\begin{methoddesc}{Sources}{name}
+Return \emph{source class names} for \code{slot} specified by \var{name}.
+\end{methoddesc}
+\begin{methoddesc}{Types}{name}
+Return names of \emph{primitive types} for \code{slot} specified by
+\var{name}.
+\end{methoddesc}
+\end{memberdesc}
+
+\begin{methoddesc}{Subclasses}{}
+Return the names of subclasses of this \class{Class}.
+\end{methoddesc}
+
+\begin{methoddesc}{Superclasses}{}
+Return the names of superclasses of this \class{Class}.
+\end{methoddesc}
+
+\begin{methoddesc}{UnwatchMessageHandler}{index}
+Turn off debug for specified \code{MessageHandler}.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{WatchInstances}
+Set or retrieve debug status for this \class{Class} \class{Instance}s.
+\end{memberdesc}
+
+\begin{methoddesc}{WatchMessageHandler}{index}
+Turn on debug for specified \code{MessageHandler}.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{WatchSlots}
+Set or retrieve \code{Slot} debug status.
+\end{memberdesc}
+
+The name of this entity in CLIPS is also returned by the string coercion
+function. The \emph{factory function} for \class{Class}es is
+\function{BuildClass()}, which has been discussed above.
+
+\end{classdesc*}
+
+
+
+\section{Instance\label{pyclips-cl-Instance}}
+
+\class{Instance} objects represent \emph{class instances} (that is,
+\emph{objects} in the OOP paradigm) that live in the CLIPS subsystem.
+Messages can be sent to those objects and values can be set and retrieved
+for the \emph{slots} defined in the related \emph{class}, where the
+meaning of \code{slot} has been described in the section above.
+
+\begin{classdesc*}{Instance}
+
+This represents a copy of an \code{instance} object in the CLIPS
+subsystem, and not a true \code{instance} entity. More than one
+\class{Instance} object in Python can refer to the same \code{instance}
+entity in the CLIPS subsystem.
+
+\begin{memberdesc}[property]{Class}
+Retrieve the \class{Class} of this \class{Instance}: this property
+actually refers to a \class{Class} object, so all of its methods are
+available.
+\end{memberdesc}
+
+\begin{methoddesc}{DirectRemove}{}
+Directly remove this \class{Instance}, without sending a message.
+\end{methoddesc}
+
+\begin{methoddesc}{GetSlot}{slotname}
+Retrieve the value of \code{Slot} specified as argument. The synonym
+\function{SlotValue} is retained for readability and compatibility.
+Please notice that these functions are provided in order to be more
+coherent with the behaviour of CLIPS API, as CLIPS C interface users
+know that a function like \function{GetSlot} usually bypasses message
+passing, thus accessing \code{slots} directly. The possibilities
+offered by \function{GetSlot} are also accessible using the \var{Slots}
+property described below.
+\end{methoddesc}
+
+\begin{methoddesc}{IsValid}{}
+Determine if this \class{Instance} is still valid.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Name}
+Retrieve the \class{Instance} name.
+\end{memberdesc}
+
+\begin{methoddesc}{Next}{}
+Return next \class{Instance} in the list of all CLIPS \code{instances}.
+It returns \var{None} if there are no \class{Instance}s left.
+\end{methoddesc}
+
+\begin{methoddesc}{PPForm}{}
+Return the \emph{pretty-print form} of \class{Instance}.
+\end{methoddesc}
+
+\begin{methoddesc}{PutSlot}{slotname, value}
+Set the value of specified \code{slot}. The \var{value} parameter should
+contain a value of the correct type, if necessary cast to one of the
+\emph{wrapper classes} described above if the type could be ambiguous.
+The synonym \function{SetSlotValue} is provided for readability and
+compatibility. What has been said about \function{GetSlot} also yields
+for the hereby described function, as the possibilities offered by
+\function{PutSlot} are also accessible using the \var{Slots} property
+described below.
+\end{methoddesc}
+
+\begin{methoddesc}{Remove}{}
+Remove this \class{Instance} (passing a message).
+\end{methoddesc}
+
+\begin{methoddesc}{Send}{msg \optional{, args}}
+Send the provided \emph{message} with the given arguments to
+\class{Instance}. The \var{args} parameter (that is, \emph{message
+arguments}), should be a string containing a list of arguments
+separated by whitespace, a tuple containing the desired arguments or a
+value of a basic type. Also in the second case the tuple elements have
+to be of basic types. The function returns a value depending on the
+passed message.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{Slots}
+Dictionary of \class{Instance} \code{slots}. This member \emph{behaves}
+like a \class{dict}, but is not related to such objects. In fact, the
+values of \code{slots} are accessible using a \class{dict}-like syntax
+(square brackets), but not all the members of \class{dict} are
+implemented. The functionality of \function{PutSlot} and
+\function{GetSlot} is superseded by this property.
+\end{memberdesc}
+
+The name of this entity in CLIPS is also returned by the string coercion
+function. The \emph{factory function} for \class{Instance}s is
+\function{BuildInstance()}, which has been discussed above.
+
+Here is an example of usage of \class{Instance} and \class{Class} objects:
+
+\begin{verbatim}
+>>> import clips
+>>> clips.Build("""(defclass TEST1
+    (is-a USER)
+    (slot ts1 (type INSTANCE-NAME))
+    (multislot ts2))""")
+>>> c = clips.FindClass("TEST1")
+>>> print c.PPForm()
+(defclass MAIN::TEST1
+   (is-a USER)
+   (slot ts1
+      (type INSTANCE-NAME))
+   (multislot ts2))
+
+>>> clips.Reset()
+>>> i = clips.BuildInstance("test1", c)
+>>> i.Slots['ts2'] = clips.Multifield(['hi', 'there'])
+>>> i.Slots['ts1'] = i.Name
+>>> print i.PPForm()
+[test1] of TEST1 (ts1 [test1]) (ts2 "hi" "there")
+\end{verbatim}
+
+\end{classdesc*}
+
+
+
+\section{Definstances\label{pyclips-cl-Definstances}}
+
+As there are \code{deffacts} for \code{fact} objects, \code{instances}
+are supported in CLIPS by the \code{definstances} construct: it allows
+certain default \class{Instance}s to be created each time a
+\function{Reset()} is issued. In \pyclips{} this construct is provided
+via the \class{Definstances} class.
+
+\begin{classdesc*}{Definstances}
+
+This represents a copy of the \code{definstances} construct in the CLIPS
+subsystem, and not a true \code{definstances} entity. More than one
+\class{Definstances} object in Python can refer to the same
+\code{definstances} entity in the CLIPS subsystem.
+
+\begin{memberdesc}[property]{Deletable}
+Verify if this \class{Definstances} can be deleted.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Module}
+Read-only property to retrieve the CLIPS name of the \class{Module}
+where the \class{Definstances} is defined.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Name}
+Retrieve \class{Definstances} name.
+\end{memberdesc}
+
+\begin{methoddesc}{Next}{}
+Return next \class{Definstances} in the list of all CLIPS
+\code{definstances}. \var{None} is returned at the end of the list.
+\end{methoddesc}
+
+\begin{methoddesc}{PPForm}{}
+Return the \emph{pretty-print form} of this \class{Definstances} object.
+\end{methoddesc}
+
+\begin{methoddesc}{Remove}{}
+Delete this \class{Definstances} object from CLIPS subsystem.
+\end{methoddesc}
+
+The name of this entity in CLIPS is also returned by the string coercion
+function. The \emph{factory function} for \class{Definstances} is
+\function{BuildDefinstances()}, which has been discussed above.
+
+\end{classdesc*}
+
+
+
+\section{Module\label{pyclips-cl-Module}}
+
+\class{Module}s are a way, in CLIPS, to organize constructs, facts and
+objects. There is a big difference between \emph{modules} and
+\emph{environments}\footnote{Besides the discussion above, also notice
+that in a ``pure'' CLIPS session there is no concept of \emph{environment}
+at all: the use of environment is reserved to those who embed CLIPS in
+another program, such as \pyclips{} users.}: one should think of a
+\class{Module} as a \emph{group} of definitions and objects, which can
+interoperate with entities that are defined in other \class{Module}s. The
+\class{Module} class provides methods, similar to the ones defined at top
+level, to directly create entities as part of the \class{Module} itself,
+as well as methods to examine \class{Module} contents. Also,
+\class{Module} objects have methods that instruct the related CLIPS
+\code{module} to become \emph{current}, so that certain operations can
+be performed without specifying the \code{module} to which they have to
+be applied.
+
+\begin{classdesc*}{Module}
+
+This represents a copy of a \code{defmodule} construct in the CLIPS
+subsystem, and not a true \code{defmodule} entity. More than one
+\class{Module} object in Python can refer to the same \code{defmodule}
+entity in the CLIPS subsystem.
+
+\begin{memberdesc}[property]{Name}
+Return the name of this \class{Module}.
+\end{memberdesc}
+
+\begin{methoddesc}{Next}{}
+Return next \class{Module} in the list of all CLIPS \code{modules}.
+\var{None} is returned at the end of the list.
+\end{methoddesc}
+
+\begin{methoddesc}{PPForm}{}
+Return the \emph{pretty-print form} of this \class{Module}.
+\end{methoddesc}
+
+\begin{methoddesc}{SetCurrent}{}
+Make the \code{module} that this object refers the current \class{Module}.
+\end{methoddesc}
+
+\begin{methoddesc}{SetFocus}{}
+Set focus to this \class{Module}.
+\end{methoddesc}
+
+For the following methods:
+\begin{verbatim}
+TemplateList(), FactList(), DeffactsList(), ClassList(), DefinstancesList(),
+GenericList(), FunctionList(), GlobalList(), BuildTemplate(),
+BuildDeffacts(), BuildClass(), BuildDefinstances(), BuildGeneric(),
+BuildFunction(), BuildGlobal(), BuildRule(), BuildInstance(),
+PrintTemplates(), PrintDeffacts(), PrintRules(), PrintClasses(),
+PrintInstances(), PrintSubclassInstances(), PrintDefinstances(),
+PrintGenerics(), PrintFunctions(), PrintGlobals(), ShowGlobals(),
+PrintAgenda(), PrintBreakpoints(), ReorderAgenda(), RefreshAgenda()
+\end{verbatim}
+
+please refer to the corresponding function defined at module level,
+keeping in mind that these methods perform the same task but within the
+\class{Module} where they are executed.
+
+The name of this entity in CLIPS is also returned by the string coercion
+function. The \emph{factory function} for \class{Module}s is
+\function{BuildModule()}, which has been discussed above.
+
+\end{classdesc*}
+
+
+
+\section{Environment\label{pyclips-cl-Environment}}
+
+This class represents an \emph{environment}, and implements almost all
+the module level functions and classes. The only objects appearing at
+\pyclips{} level and \emph{not} at \class{Environment} level are the
+CLIPS I/O subsystem \emph{streams}, which are shared with the rest of
+the CLIPS engine.
+
+\class{Environment} objects are not a feature of CLIPS sessions (as
+stated above), thus there is no way to identify them in CLIPS using
+a \emph{symbol}. So \class{Environment} objects do not have a \var{Name}
+property. Instead, CLIPS provides a way to identify an
+\emph{environment} through an integer called \emph{index}.
+
+\begin{classdesc*}{Environment}
+
+Please refer to top level functions, variables and classes for
+information on contents of \class{Environment} objects. The extra
+methods and properties follow below.
+
+\begin{memberdesc}[property]{Index}
+Retrieve the \emph{index} identifying this \class{Environment}
+internally in CLIPS.
+\end{memberdesc}
+
+\begin{methoddesc}{SetCurrent}{}
+Make the \emph{environment} that this object refers the current
+\class{Environment}.
+\end{methoddesc}
+
+Further explanations about \class{Environment} objects can be found
+in the appendices.
+
+\end{classdesc*}
+
+
+
+\section{Status and Configuration Objects\label{pyclips-cl-statusconf}}
+
+As seen in the introduction, there are a couple of objects that can be
+accessed to configure the underlying CLIPS engine and to retrieve its
+status. These are the \var{EngineConfig} and \var{DebugConfig} objects.
+The reason why configuration and status functions have been grouped in
+these objects is only cosmetic: in fact there is no counterpart of
+\var{EngineConfig} and \var{DebugConfig} in CLIPS. It was seen as convenient
+to group configuration and debug functions in two main objects and to
+make them accessible mainly as \emph{properties} in Python, instead of
+populating the module namespace with too many \emph{get/set} functions.
+
+There is also an object, called \var{Memory}, which gives information
+about memory utilization and allow the user to attempt to free memory
+used by the CLIPS engine and no longer needed.
+
+A description of what the above objects (which can not be instanced by
+the user of \pyclips{}\footnote{Besides removal of class definitions, a
+\emph{singleton}-styled implementation mechanism prevents the user from
+creating further instances of the objects.}) actually expose follows.
+
+
+\subsection{Engine Configuration\label{pyclips-cl-statusconf-engine}}
+
+The \var{EngineConfig} object allows the configuration of some features
+of the underlying CLIPS engine. Here are the properies provided by
+\var{EngineConfig}:
+
+\begin{memberdesc}[property]{AutoFloatDividend}
+Reflects the behaviour of CLIPS \code{get/set-auto-float-dividend}. When
+\constant{True} the dividend is always considered to be a floating point
+number within divisions.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{ClassDefaultsMode}
+Reflects the behaviour of CLIPS \code{get/set-class-defaults-mode}.
+Possible values of this flag are \constant{CONVENIENCE_MODE} and
+\constant{CONSERVATION_MODE}. See \clipsapg{} for details.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{DynamicConstraintChecking}
+Reflects the behaviour of CLIPS \code{get/set-dynamic-constraint-checking}.
+When \constant{True}, \emph{function calls} and \emph{constructs} are
+checked against constraint violations.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{FactDuplication}
+Reflects the behaviour of CLIPS \code{get/set-fact-duplication}. When
+\constant{True}, \code{facts} can be reasserted when they have already
+been asserted\footnote{This does not change the behaviour of the
+\class{Fact} class, which prohibits reassertion anyway. However,
+\code{facts} that would be asserted through firing of rules and would
+generate duplications will not raise an error when this behaviour is
+set.}.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{IncrementalReset}
+Reflects the behaviour of CLIPS \code{get/set-incremental-reset}. When
+\constant{True} newly defined \code{rules} are updated according to
+current \code{facts}, otherwise new \code{rules} will only be updated by
+\code{facts} defined after their construction.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{ResetGlobals}
+Reflects the behaviour of CLIPS \code{get/set-reset-globals}. When
+\constant{True} the \class{Global} variables are reset to their initial
+value after a call to \function{Reset()}.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{SalienceEvaluation}
+Reflects the behaviour of CLIPS \code{get/set-salience-evaluation}. Can
+be one of \constant{WHEN_DEFINED}, \constant{WHEN_ACTIVATED},
+\constant{EVERY_CYCLE}. See the previous chapter and \clipsapg{} for
+more information.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{SequenceOperatorRecognition}
+Reflects the behaviour of CLIPS
+\code{get/set-sequence-operator-recognition}. When \constant{False},
+\class{Multifield} values in function calls are treated as a single
+argument.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{StaticConstraintChecking}
+Reflects the behaviour of CLIPS \code{get/set-static-constraint-checking}.
+When \constant{True}, \emph{slot values} are checked against constraint
+violations.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Strategy}
+Reflects \code{get/set-strategy} behaviour. Can be any of the following
+values: \constant{RANDOM_STRATEGY}, \constant{LEX_STRATEGY},
+\constant{MEA_STRATEGY}, \constant{COMPLEXITY_STRATEGY},
+\constant{SIMPLICITY_STRATEGY}, \constant{BREADTH_STRATEGY} or
+\constant{DEPTH_STRATEGY}. See the previous chapter and \clipsapg{} for
+more information.
+\end{memberdesc}
+
+
+\subsection{Debug Settings\label{pyclips-cl-statusconf-debug}}
+
+The \var{DebugConfig} object provides access to the debugging and trace
+features of CLIPS. During a CLIPS interactive session debug and trace
+messages are printed on the system console (which maps the \code{wtrace}
+I/O \emph{router}). Users of the trace systems will have to poll the
+\var{TraceStream} to read the generated messages.
+
+In CLIPS, the process of enabling trace features on some class of
+entities is called \emph{to watch} such a class; this naming convention
+is reflected in \pyclips{}. Note that specific objects can be
+\emph{watched}: many classes have their own \var{Watch} property to
+enable or disable debugging on a particular object.
+
+Also, CLIPS provides a facility to log all debug information to physical
+files: this is called \emph{to dribble} on a file. \emph{Dribbling} is
+possible from \var{DebugConfig} via the appropriate methods.
+
+The names of methods and properties provided by this object are quite
+similar to the corresponding commands in CLIPS, so more information
+about debugging features can be found in \clipsbpg{}.
+
+\begin{memberdesc}[property]{ActivationsWatched}
+Flag to enable or disable trace of \class{Rule} activations and
+deactivations.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{CompilationsWatched}
+Flag to enable or disable trace of construct definition progress.
+\end{memberdesc}
+
+\begin{methoddesc}{DribbleActive}{}
+Tell whether or not \emph{dribble} is active.
+\end{methoddesc}
+
+\begin{methoddesc}{DribbleOff}{}
+Turn off \emph{dribble} and close the \emph{dribble} file.
+\end{methoddesc}
+
+\begin{methoddesc}{DribbleOn}{fn}
+Enable \emph{dribble} on the file identified by provided filename
+\var{fn}.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{ExternalTraceback}
+Flag to enable or disable printing traceback messages to Python
+\var{sys.stderr} if an error occurs when the CLIPS engine calls a
+Python function. Please note that the error is not propagated to the
+Python interpreter. See the appendices for a more detailed explaination.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{FactsWatched}
+Flag to enable or disable trace of \class{Fact} assertions and
+retractions.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{FunctionsWatched}
+Flag to enable or disable trace of start and finish of \class{Functions}.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{GenericFunctionsWatched}
+Flag to enable or disable trace of start and finish of \class{Generic}
+functions.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{GlobalsWatched}
+Flag to enable or disable trace of assignments to \class{Global}
+variables.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{MethodsWatched}
+Flag to enable or disable trace of start and finish of \code{Methods}
+within \class{Generic} functions.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{MessageHandlersWatched}
+Flag to enable or disable trace of start and finish of
+\code{MessageHandlers}.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{MessagesWatched}
+Flag to enable or disable trace of start and finish of \emph{messages}.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{RulesWatched}
+Flag to enable or disable trace of \class{Rule} firings.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{SlotsWatched}
+Flag to enable or disable trace of changes to \class{Instance}
+\code{Slots}.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{StatisticsWatched}
+Flag to enable or disable reports about timings, number of \code{facts}
+and \code{instances}, and other information after \function{Run()} has
+been performed.
+\end{memberdesc}
+
+\begin{methoddesc}{UnwatchAll}{}
+Turn off \emph{watch} for all items above.
+\end{methoddesc}
+
+\begin{methoddesc}{WatchAll}{}
+\emph{Watch} all items above.
+\end{methoddesc}
+
+\note{Other CLIPS I/O streams besides \var{TraceStream} can be involved
+in the trace process: please refer to the CLIPS guides for details.}
+
+
+\subsection{Memory Operations\label{pyclips-cl-statusconf-memory}}
+
+This object provides access to the memory management utilities of the
+underlying CLIPS engine. As said above, it allows the reporting of memory
+usage and the attempt to free memory that is used not for computational
+purposes. Also, a property of this object affects the engine behaviour
+about whether or not to cache some information. Here is what the object
+exposes:
+
+\begin{memberdesc}[property]{Conserve}
+When set to \constant{True}, the engine does not cache \emph{pretty-print
+forms} to memory, thus being more conservative.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{EnvironmentErrorsEnabled}
+When set to \constant{True}, the engine is enabled to directly write
+fatal environment errors to the console (\constant{stderr}). This kind
+of messages is in most of the cases printed when the program exits, so
+it can be annoying. The behaviour is disabled by default.
+\end{memberdesc}
+
+\begin{methoddesc}{Free}{}
+Attempt to free as much memory as possible of the one used by the
+underlying CLIPS engine for previous computations.
+\end{methoddesc}
+
+\begin{memberdesc}[property]{PPBufferSize}
+Report the size (in bytes) of the buffers used by \pyclips{} to return
+\emph{pretty-print forms} or similar values. By default this is set to
+8192, but the user can modify it using values greater than or equal to
+256. Greater values than the default can be useful when such forms are
+used to reconstruct CLIPS entities and definitions are so complex that
+the default buffer size is insufficient.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Requests}
+Read-only property reporting the number of memory request made by the
+engine to the operating system since \pyclips{} has been initialized.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{Used}
+Read-only property reporting the amount, in kilobytes, of memory used by
+the underlying CLIPS engine.
+\end{memberdesc}
+
+\begin{memberdesc}[property]{NumberOfEnvironments}
+Read-only property reporting the number of currently allocated
+\class{Environment}s.
+\end{memberdesc}
+
+
+\section{I/O Streams\label{pyclips-cl-iostreams}}
+
+In order to be more embeddable, CLIPS defines a clear way to redirect its
+messages to locations where they can be easily retrieved. CLIPS users can
+access these locations for reading or writing by specifying them as
+\emph{logical names} (namely \code{stdin}, \code{stdout}, \code{wtrace},
+\code{werror}, \code{wwarning}, \code{wdialog}, \code{wdisplay},
+\code{wprompt})\footnote{CLIPS also defines \code{t} as a \emph{logical
+name}: as stated in \clipsapg{} this indicates \code{stdin} in functions
+that read text and \code{stdout} in function that print out. In
+\pyclips{}, for all functions that print out to \code{t} the user must
+read from \emph{StdoutStream}.}. \pyclips{} creates some special unique
+objects\footnote{\pyclips{} in fact defines one more I/O stream, called
+\code{temporary}, which is used internally to retrieve output from CLIPS
+that shouldn't go anywhere else. \pyclips{} users however are not supposed
+to interact with this object.}, called \emph{I/O streams} throughout this
+document, to allow the user to read messages provided by the underlying
+engine. Most of these objects have only one method, called \function{Read()},
+that consumes CLIPS output and returns it as a string: this string contains
+all output since a previous call or module initialization. The only exception
+is \var{StdinStream} whose single method is \function{Write()} and it
+accepts a string\footnote{The current implementation converts the
+argument to a string, so other types can be accepted.} as parameter. As
+CLIPS writes line-by-line, the string resulting from a call to
+\function{Read()} can contain newline characters, often indicating
+subsequent messages.
+
+Here is a list of the \emph{I/O streams} provided by \pyclips{}, along
+with a brief description of each.
+
+\begin{tableii}{l|l}{var}{Stream}{Description}
+	\lineii{StdoutStream}{where information is usually printed out
+            (eg. via \code{(printout t ...)})}
+	\lineii{TraceStream}{where trace information (see \emph{watch})
+            goes}
+	\lineii{ErrorStream}{where CLIPS error messages are written in
+            readable form}
+	\lineii{WarningStream}{where CLIPS warning messages are written
+            in readable form}
+	\lineii{DialogStream}{where CLIPS informational messages are
+            written in readable form}
+	\lineii{DisplayStream}{where CLIPS displays information (eg.
+            the output of the \code{(facts)} command)}
+	\lineii{PromptStream}{where the CLIPS prompt (normally
+            \code{CLIPS>}) is sent}
+	\lineii{StdinStream}{where information is usually read by CLIPS
+            (eg. via \code{(readline)})}
+\end{tableii}
+
+Some of the provided \emph{I/O streams} are actually not so relevant for
+\pyclips{} programmers: for instance, it is of little use to read the
+contents of \var{PromptStream} and \var{DisplayStream}. In the latter
+case, in fact, there are other inspection functions that provide the
+same information in a more structured way than text. However they are
+available to provide a closer representation of the programming interface
+and allow CLIPS programmers to verify if the output of \emph{CLIPS-oriented}
+calls (see the paragraph about \function{Build()} and \function{Eval()}
+in the appendices) really do what they are expected to.
+
+
+
+\section{Predefined \class{Class}es\label{pyclips-cl-stockclasses}}
+
+\pyclips{} defines\footnote{At the module level only: defining these
+objects at the \emph{environment} level could cause aliasing current
+CLIPS enviroment. On the other hand, if these objects were implemented in
+a way that checked for aliasing, access to the actual entities would be
+surely slower only favouring compactness of user code.}, some \class{Class}
+objects, that is the ones that are present in CLIPS itself by default. They
+are defined in order to provide a compact access to CLIPS ``stock'' classes:
+most of these objects are of little or no use generally (although they
+can be handy when testing for class specification or generalization), but
+at least one (\var{USER_CLASS}) can be used to make code more readable.
+
+Namely, these \class{Class}es are:
+
+\begin{tableii}{l|l}{var}{Python Name}{CLIPS defclass}
+	\lineii{FLOAT_CLASS}{FLOAT}
+	\lineii{INTEGER_CLASS}{INTEGER}
+	\lineii{SYMBOL_CLASS}{SYMBOL}
+	\lineii{STRING_CLASS}{STRING}
+	\lineii{MULTIFIELD_CLASS}{MULTIFIELD}
+	\lineii{EXTERNAL_ADDRESS_CLASS}{EXTERNAL-ADDRESS}
+	\lineii{FACT_ADDRESS_CLASS}{FACT-ADDRESS}
+	\lineii{INSTANCE_ADDRESS_CLASS}{INSTANCE-ADDRESS}
+	\lineii{INSTANCE_NAME_CLASS}{INSTANCE-NAME}
+	\lineii{OBJECT_CLASS}{OBJECT}
+	\lineii{PRIMITIVE_CLASS}{PRIMITIVE}
+	\lineii{NUMBER_CLASS}{NUMBER}
+	\lineii{LEXEME_CLASS}{LEXEME}
+	\lineii{ADDRESS_CLASS}{ADDRESS}
+	\lineii{INSTANCE_CLASS}{INSTANCE}
+	\lineii{INITIAL_OBJECT_CLASS}{INITIAL-OBJECT}
+	\lineii{USER_CLASS}{USER}
+\end{tableii}
+
+The following code, shows how to use the ``traditional''
+\function{BuildClass()} factory function and how to directly subclass one
+of the predefined \class{Class} object. In the latter case, probably, the
+action of subclassing is expressed in a more clear way:
+
+\begin{verbatim}
+>>> import clips
+>>> C = clips.BuildClass("C", "(is-a USER)(slot s)")
+>>> print C.PPForm()
+(defclass MAIN::C
+   (is-a USER)
+   (slot s))
+
+>>> D = clips.USER_CLASS.BuildSubclass("D", "(slot s)")
+>>> print D.PPForm()
+(defclass MAIN::D
+   (is-a USER)
+   (slot s))
+\end{verbatim}
+
+Although it actually does not save typing (the statement is slightly
+longer), the second form can be used to produce more readable Python code.
+
+\note{These objects are actually useful \emph{only} when the package is
+fully imported, that is using the \code{import clips} form: importing
+the symbols at global level (in the form \code{from clips import *}) does
+in fact create some namespace problems. Since in the latter case the names
+that represent stock classes are only references to the ones defined at
+module level, \pyclips{} cannot change them when the actual classes are
+relocated in the CLIPS memory space, for instance when \function{Clear}
+is called.}
diff --git a/doc/pyclips.tex b/doc/pyclips.tex
new file mode 100644
index 0000000..0e7ed5d
--- /dev/null
+++ b/doc/pyclips.tex
@@ -0,0 +1,71 @@
+% $Id: pyclips.tex 342 2008-02-22 01:17:23Z Franz $
+\documentclass{manual}
+
+\input{defs}
+
+\title{\pyclips{} Manual}
+
+\author{Francesco Garosi}
+
+% Please at least include a long-lived email address;
+% the rest is at your discretion.
+\authoraddress{
+    E-mail: \email{franz -dot- g -at- tin -dot- it}
+}
+
+% do not mess with the 2 lines below, they are written by make dist
+\release{1.0}
+\date{Feb 22, 2008}
+
+\makeindex
+
+\begin{document}
+
+\maketitle
+
+% This makes the contents accessible from the front page of the HTML.
+\ifhtml
+\chapter*{Front Matter\label{front}}
+\fi
+
+\input{copyright}
+
+\begin{abstract}
+
+\noindent
+This manual documents the high-level interface to the CLIPS system
+provided by the \pyclips{} module. This module allows the creation of a
+fully-functional CLIPS environment in a Python session, thus providing
+access to a well-known expert systems shell programmatically.
+
+\pyclips{} incorporates most of the API bindings documented in the
+\clipsapg{} (freely downloadable from the CLIPS web site, see below) and
+embeds these bindings in an Object Oriented layer, incorporating most
+CLIPS constructs into Python classes. Instances of these classes allow
+access to the status and functionality of the corresponding CLIPS objects.
+
+\end{abstract}
+
+\note{This manual is not intended to be a documentation of CLIPS itself.
+CLIPS is extensively documented in several manuals, which are available on
+the CLIPS website (see below). A comprehensive tutorial for CLIPS can also
+be downloaded. A reasonable knowledge of the CLIPS system is necessary
+to understand and use this module.}
+
+\begin{seealso}
+  \seetitle[http://www.python.org/]
+	{Python Language Web Site}{for information on the Python language}
+  \seetitle[http://www.ghg.net/clips/CLIPS.html]
+	{CLIPS system web site}{for information on the CLIPS system}
+\end{seealso}
+
+\tableofcontents
+
+\input{intro}		% Introduction
+\input{contents}	% Module Contents
+\input{objects}		% Provided Objects
+\input{appendix}        % Appendix and Notes
+
+\input{license}	        % License Information
+
+\end{document}
diff --git a/doc/zebra.clp b/doc/zebra.clp
new file mode 100644
index 0000000..3684d4a
--- /dev/null
+++ b/doc/zebra.clp
@@ -0,0 +1,210 @@
+;;;======================================================
+;;;   Who Drinks Water? And Who owns the Zebra?
+;;;     
+;;;     Another puzzle problem in which there are five 
+;;;     houses, each of a different color, inhabited by 
+;;;     men of different nationalities, with different 
+;;;     pets, drinks, and cigarettes. Given the initial
+;;;     set of conditions, it must be determined which
+;;;     attributes are assigned to each man.
+;;;
+;;;     CLIPS Version 6.0 Example
+;;;
+;;;     To execute, merely load, reset and run.
+;;;======================================================
+
+(deftemplate avh (field a) (field v) (field h))
+
+(defrule find-solution
+  ; The Englishman lives in the red house.
+
+(avh (a nationality) (v englishman) (h ?n1))
+  (avh (a color) (v red) (h ?c1&?n1))
+
+; The Spaniard owns the dog.
+
+  (avh (a nationality) (v spaniard) (h ?n2&~?n1))
+  (avh (a pet) (v dog) (h ?p1&?n2))
+
+; The ivory house is immediately to the left of the green house,
+  ; where the coffee drinker lives.
+
+  (avh (a color) (v ivory) (h ?c2&~?c1))
+  (avh (a color) (v green) (h ?c3&~?c2&~?c1&=(+ ?c2 1)))
+  (avh (a drink) (v coffee) (h ?d1&?c3))
+
+; The milk drinker lives in the middle house.
+
+  (avh (a drink) (v milk) (h ?d2&~?d1&3))
+
+; The man who smokes Old Golds also keeps snails.
+
+  (avh (a smokes) (v old-golds) (h ?s1))
+  (avh (a pet) (v snails) (h ?p2&~?p1&?s1))
+
+; The Ukrainian drinks tea.
+
+  (avh (a nationality) (v ukrainian) (h ?n3&~?n2&~?n1))
+  (avh (a drink) (v tea) (h ?d3&~?d2&~?d1&?n3))
+
+; The Norwegian resides in the first house on the left.
+
+  (avh (a nationality) (v norwegian) (h ?n4&~?n3&~?n2&~?n1&1))
+
+; Chesterfields smoker lives next door to the fox owner.
+
+  (avh (a smokes) (v chesterfields) (h ?s2&~?s1))
+  (avh (a pet) (v fox)
+    (h ?p3&~?p2&~?p1&:(or (= ?s2 (- ?p3 1)) (= ?s2 (+ ?p3 1)))))
+
+; The Lucky Strike smoker drinks orange juice.
+
+  (avh (a smokes) (v lucky-strikes) (h ?s3&~?s2&~?s1))
+  (avh (a drink) (v orange-juice) (h ?d4&~?d3&~?d2&~?d1&?s3)) 
+
+; The Japanese smokes Parliaments
+
+  (avh (a nationality) (v japanese) (h ?n5&~?n4&~?n3&~?n2&~?n1))
+  (avh (a smokes) (v parliaments) (h ?s4&~?s3&~?s2&~?s1&?n5))
+
+; The horse owner lives next to the Kools smoker, 
+  ; whose house is yellow.
+
+  (avh (a pet) (v horse) (h ?p4&~?p3&~?p2&~?p1))
+  (avh (a smokes) (v kools)
+    (h ?s5&~?s4&~?s3&~?s2&~?s1&:(or (= ?p4 (- ?s5 1)) (= ?p4 (+ ?s5 1)))))
+  (avh (a color) (v yellow) (h ?c4&~?c3&~?c2&~?c1&?s5))
+
+; The Norwegian lives next to the blue house.
+
+  (avh (a color) (v blue)
+    (h ?c5&~?c4&~?c3&~?c2&~?c1&:(or (= ?c5 (- ?n4 1)) (= ?c5 (+ ?n4 1)))))
+
+; Who drinks water?  And Who owns the zebra?
+
+  (avh (a drink) (v water) (h ?d5&~?d4&~?d3&~?d2&~?d1))
+  (avh (a pet) (v zebra) (h ?p5&~?p4&~?p3&~?p2&~?p1))
+
+=> 
+  (assert (solution nationality englishman ?n1)
+          (solution color red ?c1)
+          (solution nationality spaniard ?n2)
+          (solution pet dog ?p1)
+          (solution color ivory ?c2)
+          (solution color green ?c3)
+          (solution drink coffee ?d1)
+          (solution drink milk ?d2) 
+          (solution smokes old-golds ?s1)
+          (solution pet snails ?p2)
+          (solution nationality ukrainian ?n3)
+          (solution drink tea ?d3)
+          (solution nationality norwegian ?n4)
+          (solution smokes chesterfields ?s2)
+          (solution pet fox ?p3)
+          (solution smokes lucky-strikes ?s3)
+          (solution drink orange-juice ?d4) 
+          (solution nationality japanese ?n5)
+          (solution smokes parliaments ?s4)
+          (solution pet horse ?p4) 
+          (solution smokes kools ?s5)
+          (solution color yellow ?c4)
+          (solution color blue ?c5)
+          (solution drink water ?d5)
+          (solution pet zebra ?p5))
+  )
+
+(defrule print-solution
+  ?f1 <- (solution nationality ?n1 1)
+  ?f2 <- (solution color ?c1 1)
+  ?f3 <- (solution pet ?p1 1)
+  ?f4 <- (solution drink ?d1 1)
+  ?f5 <- (solution smokes ?s1 1)
+  ?f6 <- (solution nationality ?n2 2)
+  ?f7 <- (solution color ?c2 2)
+  ?f8 <- (solution pet ?p2 2)
+  ?f9 <- (solution drink ?d2 2)
+  ?f10 <- (solution smokes ?s2 2)
+  ?f11 <- (solution nationality ?n3 3)
+  ?f12 <- (solution color ?c3 3)
+  ?f13 <- (solution pet ?p3 3)
+  ?f14 <- (solution drink ?d3 3)
+  ?f15 <- (solution smokes ?s3 3)
+  ?f16 <- (solution nationality ?n4 4)
+  ?f17 <- (solution color ?c4 4)
+  ?f18 <- (solution pet ?p4 4)
+  ?f19 <- (solution drink ?d4 4)
+  ?f20 <- (solution smokes ?s4 4)
+  ?f21 <- (solution nationality ?n5 5)
+  ?f22 <- (solution color ?c5 5)
+  ?f23 <- (solution pet ?p5 5)
+  ?f24 <- (solution drink ?d5 5)
+  ?f25 <- (solution smokes ?s5 5)
+  =>
+ (retract ?f1 ?f2 ?f3 ?f4 ?f5 ?f6 ?f7 ?f8 ?f9 ?f10 ?f11 ?f12 ?f13 ?f14
+          ?f15 ?f16 ?f17 ?f18 ?f19 ?f20 ?f21 ?f22 ?f23 ?f24 ?f25)
+
+(format t "HOUSE | %-11s | %-6s | %-6s | %-12s | %-13s%n" 
+           Nationality Color Pet Drink Smokes)
+ (format t "---------------------------------------------------------------%n")
+ (format t "  1   | %-11s | %-6s | %-6s | %-12s | %-13s%n" ?n1 ?c1 ?p1 ?d1 ?s1)
+ (format t "  2   | %-11s | %-6s | %-6s | %-12s | %-13s%n" ?n2 ?c2 ?p2 ?d2 ?s2)
+ (format t "  3   | %-11s | %-6s | %-6s | %-12s | %-13s%n" ?n3 ?c3 ?p3 ?d3 ?s3)
+ (format t "  4   | %-11s | %-6s | %-6s | %-12s | %-13s%n" ?n4 ?c4 ?p4 ?d4 ?s4)
+ (format t "  5   | %-11s | %-6s | %-6s | %-12s | %-13s%n" ?n5 ?c5 ?p5 ?d5 ?s5)
+ (printout t crlf crlf))
+
+(defrule startup
+   =>
+ (printout t
+ "There are five houses, each of a different color, inhabited by men of"  crlf
+ "different nationalities, with different pets, drinks, and cigarettes."  crlf
+ crlf
+ "The Englishman lives in the red house.  The Spaniard owns the dog."     crlf
+ "The ivory house is immediately to the left of the green house, where"   crlf
+ "the coffee drinker lives.  The milk drinker lives in the middle house." crlf
+ "The man who smokes Old Golds also keeps snails.  The Ukrainian drinks"  crlf
+ "tea.  The Norwegian resides in the first house on the left.  The"       crlf)
+ (printout t
+ "Chesterfields smoker lives next door to the fox owner.  The Lucky"      crlf
+ "Strike smoker drinks orange juice.  The Japanese smokes Parliaments."   crlf
+ "The horse owner lives next to the Kools smoker, whose house is yellow." crlf
+ "The Norwegian lives next to the blue house."			     t
+ crlf
+  "Now, who drinks water?  And who owns the zebra?" crlf crlf)
+   (assert (value color red) 
+           (value color green) 
+           (value color ivory)
+           (value color yellow)
+           (value color blue)
+           (value nationality englishman)
+           (value nationality spaniard)
+           (value nationality ukrainian) 
+           (value nationality norwegian)
+           (value nationality japanese)
+           (value pet dog)
+           (value pet snails)
+           (value pet fox)
+           (value pet horse)
+           (value pet zebra)
+           (value drink water)
+           (value drink coffee)
+           (value drink milk)
+           (value drink orange-juice)
+           (value drink tea)
+           (value smokes old-golds)
+           (value smokes kools)
+           (value smokes chesterfields)
+           (value smokes lucky-strikes)
+           (value smokes parliaments)) 
+   )
+
+(defrule generate-combinations
+   ?f <- (value ?s ?e)
+   =>
+   (retract ?f)
+   (assert (avh (a ?s) (v ?e) (h 1))
+           (avh (a ?s) (v ?e) (h 2))
+           (avh (a ?s) (v ?e) (h 3))
+           (avh (a ?s) (v ?e) (h 4))
+           (avh (a ?s) (v ?e) (h 5))))
+
diff --git a/loptr.c b/loptr.c
new file mode 100644
index 0000000..2714882
--- /dev/null
+++ b/loptr.c
@@ -0,0 +1,194 @@
+/* loptr.c
+ *  Simple list-of-pointers handling library; this library is intended to
+ *  be directly included in the source file that would use it, without prior
+ *  or separated compilation. We use a hash table not just because we expect
+ *  to be likely to have many records in the list, but also hoping that in
+ *  many cases this will make it faster to find out whether or not a pointer
+ *  is already present.
+ *
+ * Even though this library is useless, it's however released under the LGPL.
+ *
+ * $Id: loptr.c 340 2008-02-21 00:39:34Z Franz $
+ * (c) 2008 - Francesco Garosi/JKS
+ */
+
+
+
+/* the kind of integers we will be dealing with */
+#define LOPTR_INT unsigned long
+#define LOPTR_BOOL int
+#define LOPTR_TRUE 1
+#define LOPTR_FALSE 0
+
+/* the following can be helpful when allocating objects */
+#ifdef USE_PYTHON_MEMMGR
+#define LOPTR_NEW(x) PyMem_New(x, 1)
+#define LOPTR_DELETE(x) PyMem_Del(x)
+#else
+#define LOPTR_NEW(x) ((x *)malloc(sizeof(x)))
+#define LOPTR_DELETE(x) free(x)
+#endif
+
+/* these functions are intended to be very fast and inlined */
+#ifdef F_INLINE
+#define LOPTR_INLINE F_INLINE
+#else
+#define LOPTR_INLINE
+#endif /* F_INLINE */
+
+/* size of hash table for sublists of pointers, should be a prime */
+#ifndef STRAY_FACTS_TABLE_SIZE
+#define STRAY_FACTS_TABLE_SIZE 211
+#endif
+#define LOPTR_HASH_TABLE_SIZE ((LOPTR_INT)STRAY_FACTS_TABLE_SIZE)
+#define LOPTR_HASH(_x) (((LOPTR_INT)_x) % LOPTR_HASH_TABLE_SIZE)
+
+/* decide whether or not to use register variables and pointers */
+#ifdef USE_REGISTER_VARIABLES
+#define LOPTR_REGISTER register
+#else
+#define LOPTR_REGISTER
+#endif
+
+
+/* will constitute the sublists of pointers */
+typedef struct __struct_LOPTR_ITEM {
+    void *elem;
+    struct __struct_LOPTR_ITEM *next;
+} LOPTR_ITEM;
+
+
+/* type of function accepted by LOPTR_apply */
+typedef LOPTR_BOOL(*LOPTR_FUNC)(void *);
+
+
+/* give a standardized way to create a hash table */
+#define LOPTR_HASH_TABLE(name) LOPTR_ITEM *name[LOPTR_HASH_TABLE_SIZE]
+#define INIT_LOPTR_HASH_TABLE(name) \
+	memset(name, 0, sizeof(LOPTR_ITEM *) * (LOPTR_HASH_TABLE_SIZE))
+#define COPY_LOPTR_HASH_TABLE(dst, src) \
+	memcpy((dst), (src), sizeof(LOPTR_ITEM *) * (LOPTR_HASH_TABLE_SIZE))
+
+
+/* functions to transparently manage the list */
+
+/* find an element */
+static LOPTR_INLINE LOPTR_ITEM *LOPTR_find(LOPTR_ITEM **t, void *elem) {
+    LOPTR_REGISTER LOPTR_ITEM *p = t[LOPTR_HASH(elem)];
+    
+    while(p) {
+        if(p->elem == elem)
+            return p;
+        else
+            p = p->next;
+    }
+    return NULL;
+}
+
+/* find the last item in the hash table for element */
+static LOPTR_INLINE LOPTR_ITEM *LOPTR_lastitem(LOPTR_ITEM **t, void *elem) {
+    LOPTR_REGISTER LOPTR_ITEM *p = t[LOPTR_HASH(elem)];
+    
+    if(p) {
+        while(p->next != NULL)
+            p = p->next;
+        return p;
+    } else
+        return NULL;
+}
+
+/* append an element in the hash table */
+static LOPTR_INLINE LOPTR_BOOL LOPTR_append(LOPTR_ITEM **t, void *elem) {
+    LOPTR_ITEM *p = NULL, *q = NULL;
+    
+    if(LOPTR_find(t, elem))
+        return LOPTR_FALSE;
+    else {
+        p = LOPTR_NEW(LOPTR_ITEM);
+        p->elem = elem;
+        p->next = NULL;
+        q = LOPTR_lastitem(t, elem);
+        if(q)
+            q->next = p;
+        else
+            t[LOPTR_HASH(elem)] = p;
+        return LOPTR_TRUE;
+    }
+}
+
+/* remove an element from the hash table */
+static LOPTR_INLINE LOPTR_BOOL LOPTR_remove(LOPTR_ITEM **t, void *elem) {
+    int h = LOPTR_HASH(elem);
+    LOPTR_REGISTER LOPTR_ITEM *p = t[h];
+    LOPTR_ITEM *q = NULL;
+
+    if(p) {
+        if(p->elem == elem) {
+            t[h] = p->next;  /* could be NULL */
+            LOPTR_DELETE(p);
+            return LOPTR_TRUE;
+        } else {
+            while(p) {
+                q = p;
+                p = p->next;
+                if(p->elem == elem) {
+                    q->next = p->next;  /* could be NULL either */
+                    LOPTR_DELETE(p);
+                    return LOPTR_TRUE;
+                }
+            }
+        }
+    }
+    return LOPTR_FALSE;
+}
+
+/* apply a bool-returning function to list elements ignoring result */
+static LOPTR_INLINE void LOPTR_apply(LOPTR_ITEM **t, LOPTR_FUNC f) {
+    int i = 0;
+    LOPTR_REGISTER LOPTR_ITEM *p = NULL;
+    
+    for(i = 0; i < LOPTR_HASH_TABLE_SIZE; i++) {
+        p = t[i];
+        while(p) {
+            f(p->elem);
+            p = p->next;
+        }
+    }
+}
+
+/* apply a bool-returning function to list elements returning failing result */
+static LOPTR_INLINE void *LOPTR_test_apply(LOPTR_ITEM **t, LOPTR_FUNC f) {
+    LOPTR_REGISTER int i = 0;
+    LOPTR_REGISTER LOPTR_ITEM *p = NULL;
+    
+    for(i = 0; i < LOPTR_HASH_TABLE_SIZE; i++) {
+        p = t[i];
+        while(p) {
+            if(!f(p->elem))
+                return p->elem;
+            p = p->next;
+        }
+    }
+    return NULL;
+}
+
+/* reset a hash table (only leave the array) removing all possible lists */
+static LOPTR_INLINE void LOPTR_reset_hash_table(LOPTR_ITEM **t) {
+    LOPTR_REGISTER int i = 0;
+    LOPTR_REGISTER LOPTR_ITEM *p = NULL;
+    LOPTR_ITEM *q = NULL;
+    
+    for(i = 0; i < LOPTR_HASH_TABLE_SIZE; i++) {
+        p = t[i];
+        while(p) {
+            q = p;
+            p = p->next;
+            LOPTR_DELETE(q);
+        }
+        t[i] = NULL;
+    }
+}
+
+
+
+/* end. */
diff --git a/optpatch/classexm.h-01.v6.23-test.diff b/optpatch/classexm.h-01.v6.23-test.diff
new file mode 100644
index 0000000..0914fce
--- /dev/null
+++ b/optpatch/classexm.h-01.v6.23-test.diff
@@ -0,0 +1,20 @@
+--- ../clipssrc_orig/classexm.h	Wed Jan 19 18:57:18 2005
++++ ../clipssrc/classexm.h	Wed May 31 15:55:50 2006
+@@ -35,7 +35,7 @@
+ 
+ #if ENVIRONMENT_API_ONLY
+ #define BrowseClasses(theEnv,a,b) EnvBrowseClasses(theEnv,a,b)
+-#define DescribeClass(theEnv,a,b) EnvBrowseClasses(theEnv,a,b)
++#define DescribeClass(theEnv,a,b) EnvDescribeClass(theEnv,a,b)
+ #define SlotDirectAccessP(theEnv,a,b) EnvSlotDirectAccessP(theEnv,a,b)
+ #define SlotExistP(theEnv,a,b,c) EnvSlotExistP(theEnv,a,b,c)
+ #define SlotInitableP(theEnv,a,b) EnvSlotInitableP(theEnv,a,b)
+@@ -45,7 +45,7 @@
+ #define SuperclassP(theEnv,a,b) EnvSuperclassP(theEnv,a,b)
+ #else
+ #define BrowseClasses(a,b) EnvBrowseClasses(GetCurrentEnvironment(),a,b)
+-#define DescribeClass(a,b) EnvBrowseClasses(GetCurrentEnvironment(),a,b)
++#define DescribeClass(a,b) EnvDescribeClass(GetCurrentEnvironment(),a,b)
+ #define SlotDirectAccessP(a,b) EnvSlotDirectAccessP(GetCurrentEnvironment(),a,b)
+ #define SlotExistP(a,b,c) EnvSlotExistP(GetCurrentEnvironment(),a,b,c)
+ #define SlotInitableP(a,b) EnvSlotInitableP(GetCurrentEnvironment(),a,b)
diff --git a/optpatch/cstrccom.c-01.v6.23-bgfx.diff b/optpatch/cstrccom.c-01.v6.23-bgfx.diff
new file mode 100644
index 0000000..61ce851
--- /dev/null
+++ b/optpatch/cstrccom.c-01.v6.23-bgfx.diff
@@ -0,0 +1,21 @@
+--- ../clipssrc_orig/cstrccom.c	Wed Feb  2 10:45:38 2005
++++ ../clipssrc/cstrccom.c	Sun Jan 22 15:47:58 2006
+@@ -29,6 +29,9 @@
+ /*                                                           */
+ /*            Correction for FalseSymbol/TrueSymbol. DR0859  */
+ /*                                                           */
++/*      6.24: Corrected an error when compiling as a C++     */
++/*            file.                                          */
++/*                                                           */
+ /*************************************************************/
+ 
+ #define _CSTRCCOM_SOURCE_
+@@ -834,7 +837,7 @@
+    /* Allocate the name buffer. */
+    /*===========================*/
+    
+-   buffer = genalloc(theEnv,bufferSize);
++   buffer = (char *) genalloc(theEnv,bufferSize);
+    
+    /*================================*/
+    /* Create the multifield value to */
diff --git a/optpatch/dffnxpsr.c-01.v6.23-bgfx.diff b/optpatch/dffnxpsr.c-01.v6.23-bgfx.diff
new file mode 100644
index 0000000..9ae3730
--- /dev/null
+++ b/optpatch/dffnxpsr.c-01.v6.23-bgfx.diff
@@ -0,0 +1,37 @@
+--- ../clipssrc_orig/dffnxpsr.c	Mon May 31 11:06:00 2004
++++ ../clipssrc/dffnxpsr.c	Wed May 31 15:38:28 2006
+@@ -165,6 +165,34 @@
+    actions = ParseProcActions(theEnv,"deffunction",readSource,
+                               &DeffunctionData(theEnv)->DFInputToken,parameterList,wildcard,
+                               NULL,NULL,&lvars,NULL);
++
++   /*=============================================================*/
++   /* Check for the closing right parenthesis of the deffunction. */
++   /*=============================================================*/
++
++   if ((DeffunctionData(theEnv)->DFInputToken.type != RPAREN) && /* DR0872 */
++       (actions != NULL))
++     {
++      SyntaxErrorMessage(theEnv,"deffunction");
++     
++      ReturnExpression(theEnv,parameterList);
++      ReturnPackedExpression(theEnv,actions);
++
++      if (overwrite)
++        {
++         dptr->minNumberOfParameters = owMin;
++         dptr->maxNumberOfParameters = owMax;
++        }
++
++      if ((dptr->busy == 0) && (! overwrite))
++        {
++         RemoveConstructFromModule(theEnv,(struct constructHeader *) dptr);
++         RemoveDeffunction(theEnv,dptr);
++        }
++
++      return(TRUE);
++     }
++
+    if (actions == NULL)
+      {
+       ReturnExpression(theEnv,parameterList);
diff --git a/optpatch/envrnmnt.c-01.v6.23-test.diff b/optpatch/envrnmnt.c-01.v6.23-test.diff
new file mode 100644
index 0000000..229c3e0
--- /dev/null
+++ b/optpatch/envrnmnt.c-01.v6.23-test.diff
@@ -0,0 +1,105 @@
+--- ../clipssrc_orig/envrnmnt.c	Mon Jun 16 20:33:00 2003
++++ ../clipssrc/envrnmnt.c	Sun May 28 20:09:14 2006
+@@ -35,6 +35,30 @@
+ 
+ #define SIZE_ENVIRONMENT_HASH  131
+ 
++
++/* use Python memory allocator when compiling PyCLIPS */
++#ifdef PYCLIPS
++#include <Python.h>
++void *PyCLIPS_Malloc(size_t s);
++void PyCLIPS_Free(void *p);
++#if !BLOCK_MEMORY
++   #undef malloc
++   #define malloc PyCLIPS_Malloc
++   #undef free
++   #define free PyCLIPS_Free
++#endif /* BLOCK_MEMORY */
++#endif /* PYCLIPS */
++
++
++/* enable inhibition of fatal environment errors */
++#ifdef PYCLIPS
++int PyCLIPS_EnableFatal();
++#define FPRINTF if(PyCLIPS_EnableFatal()) fprintf
++#else
++#define FPRINTF fprintf
++#endif /* PYCLIPS */
++
++
+ /***************************************/
+ /* LOCAL INTERNAL FUNCTION DEFINITIONS */
+ /***************************************/
+@@ -75,7 +99,7 @@
+    
+    if (size <= 0)
+      {
+-      printf("\n[ENVRNMNT1] Environment data position %d allocated with size of 0 or less.\n",position);      
++      FPRINTF(stderr, "\n[ENVRNMNT1] Environment data position %d allocated with size of 0 or less.\n",position);
+       return(FALSE);
+      }
+      
+@@ -85,7 +109,7 @@
+    
+    if (position >= MAXIMUM_ENVIRONMENT_POSITIONS)
+      {
+-      printf("\n[ENVRNMNT2] Environment data position %d exceeds the maximum allowed.\n",position);      
++      FPRINTF(stderr, "\n[ENVRNMNT2] Environment data position %d exceeds the maximum allowed.\n",position);
+       return(FALSE);
+      }
+      
+@@ -95,7 +119,7 @@
+    
+    if (theEnvironment->theData[position] != NULL)
+      {
+-      printf("\n[ENVRNMNT3] Environment data position %d already allocated.\n",position);      
++      FPRINTF(stderr, "\n[ENVRNMNT3] Environment data position %d already allocated.\n",position);
+       return(FALSE);
+      }
+      
+@@ -170,7 +194,7 @@
+ 
+    if (EnvironmentHashTable == NULL)
+      {
+-      printf("\n[ENVRNMNT4] Unable to initialize environment hash table.\n");      
++      FPRINTF(stderr, "\n[ENVRNMNT4] Unable to initialize environment hash table.\n");
+       return;
+      }
+ 
+@@ -269,7 +293,7 @@
+   
+    if (theEnvironment == NULL)
+      {
+-      printf("\n[ENVRNMNT5] Unable to create new environment.\n");
++      FPRINTF(stderr, "\n[ENVRNMNT5] Unable to create new environment.\n");
+       return(NULL);
+      }
+ 
+@@ -277,7 +301,7 @@
+    
+    if (theData == NULL)
+      {
+-      printf("\n[ENVRNMNT6] Unable to create environment data.\n");
++      FPRINTF(stderr, "\n[ENVRNMNT6] Unable to create environment data.\n");
+       return(NULL);
+      }
+ 
+@@ -301,7 +325,7 @@
+    
+    if (theData == NULL)
+      {
+-      printf("\n[ENVRNMNT7] Unable to create environment data.\n");
++      FPRINTF(stderr, "\n[ENVRNMNT7] Unable to create environment data.\n");
+       return(NULL);
+      }
+ 
+@@ -431,7 +455,7 @@
+      
+    if ((theMemData->MemoryAmount != 0) || (theMemData->MemoryCalls != 0))
+      {
+-      printf("\n[ENVRNMNT8] Environment data not fully deallocated.\n"); 
++      FPRINTF(stderr, "\n[ENVRNMNT8] Environment data not fully deallocated.\n");
+       rv = FALSE;     
+      }
+      
diff --git a/optpatch/envrnmnt.c-01.v6.24-test.diff b/optpatch/envrnmnt.c-01.v6.24-test.diff
new file mode 100644
index 0000000..d6a961c
--- /dev/null
+++ b/optpatch/envrnmnt.c-01.v6.24-test.diff
@@ -0,0 +1,114 @@
+--- ../clipssrc0624_orig/envrnmnt.c	Thu Jun 15 12:04:00 2006
++++ ../clipssrc/envrnmnt.c	Fri Jun 16 22:45:10 2006
+@@ -50,6 +50,30 @@
+ 
+ #define SIZE_ENVIRONMENT_HASH  131
+ 
++
++/* use Python memory allocator when compiling PyCLIPS */
++#ifdef PYCLIPS
++#include <Python.h>
++void *PyCLIPS_Malloc(size_t s);
++void PyCLIPS_Free(void *p);
++#if !BLOCK_MEMORY
++   #undef malloc
++   #define malloc PyCLIPS_Malloc
++   #undef free
++   #define free PyCLIPS_Free
++#endif /* BLOCK_MEMORY */
++#endif /* PYCLIPS */
++
++
++/* enable inhibition of fatal environment errors */
++#ifdef PYCLIPS
++int PyCLIPS_EnableFatal();
++#define FPRINTF if(PyCLIPS_EnableFatal()) fprintf
++#else
++#define FPRINTF fprintf
++#endif /* PYCLIPS */
++
++
+ /***************************************/
+ /* LOCAL INTERNAL FUNCTION DEFINITIONS */
+ /***************************************/
+@@ -92,7 +116,7 @@
+    
+    if (size <= 0)
+      {
+-      printf("\n[ENVRNMNT1] Environment data position %d allocated with size of 0 or less.\n",position);      
++      FPRINTF(stderr, "\n[ENVRNMNT1] Environment data position %d allocated with size of 0 or less.\n",position);
+       return(FALSE);
+      }
+      
+@@ -102,7 +126,7 @@
+    
+    if (position >= MAXIMUM_ENVIRONMENT_POSITIONS)
+      {
+-      printf("\n[ENVRNMNT2] Environment data position %d exceeds the maximum allowed.\n",position);      
++      FPRINTF(stderr, "\n[ENVRNMNT2] Environment data position %d exceeds the maximum allowed.\n",position);
+       return(FALSE);
+      }
+      
+@@ -112,7 +136,7 @@
+    
+    if (theEnvironment->theData[position] != NULL)
+      {
+-      printf("\n[ENVRNMNT3] Environment data position %d already allocated.\n",position);      
++      FPRINTF(stderr, "\n[ENVRNMNT3] Environment data position %d already allocated.\n",position);
+       return(FALSE);
+      }
+      
+@@ -123,7 +147,7 @@
+    theEnvironment->theData[position] = malloc(size);
+    if (theEnvironment->theData[position] == NULL)
+      {
+-      printf("\n[ENVRNMNT4] Environment data position %d could not be allocated.\n",position);      
++      FPRINTF(stderr, "\n[ENVRNMNT4] Environment data position %d could not be allocated.\n",position);
+       return(FALSE);
+      }
+    
+@@ -193,7 +217,7 @@
+ 
+    if (EnvironmentHashTable == NULL)
+      {
+-      printf("\n[ENVRNMNT4] Unable to initialize environment hash table.\n");      
++      FPRINTF(stderr, "\n[ENVRNMNT4] Unable to initialize environment hash table.\n");
+       return;
+      }
+ 
+@@ -318,7 +342,7 @@
+   
+    if (theEnvironment == NULL)
+      {
+-      printf("\n[ENVRNMNT5] Unable to create new environment.\n");
++      FPRINTF(stderr, "\n[ENVRNMNT5] Unable to create new environment.\n");
+       return(NULL);
+      }
+ 
+@@ -327,7 +351,7 @@
+    if (theData == NULL)
+      {
+       free(theEnvironment);
+-      printf("\n[ENVRNMNT6] Unable to create environment data.\n");
++      FPRINTF(stderr, "\n[ENVRNMNT6] Unable to create environment data.\n");
+       return(NULL);
+      }
+ 
+@@ -355,7 +379,7 @@
+      {
+       free(theEnvironment->theData);
+       free(theEnvironment);
+-      printf("\n[ENVRNMNT7] Unable to create environment data.\n");
++      FPRINTF(stderr, "\n[ENVRNMNT7] Unable to create environment data.\n");
+       return(NULL);
+      }
+ 
+@@ -540,7 +564,7 @@
+      
+    if ((theMemData->MemoryAmount != 0) || (theMemData->MemoryCalls != 0))
+      {
+-      printf("\n[ENVRNMNT8] Environment data not fully deallocated.\n"); 
++      FPRINTF(stderr, "\n[ENVRNMNT8] Environment data not fully deallocated.\n");
+       rv = FALSE;     
+      }
+      
diff --git a/optpatch/evaluatn.h-01.v6.23-ia64.diff b/optpatch/evaluatn.h-01.v6.23-ia64.diff
new file mode 100644
index 0000000..ff00fe7
--- /dev/null
+++ b/optpatch/evaluatn.h-01.v6.23-ia64.diff
@@ -0,0 +1,32 @@
+--- ../clipssrc_orig/evaluatn.h	Sat May 29 13:22:00 2004
++++ ../clipssrc/evaluatn.h	Sun May 28 20:09:14 2006
+@@ -84,10 +84,10 @@
+ #define GetDOEnd(target)          ((target).end + 1)
+ #define GetpDOBegin(target)       ((target)->begin + 1)
+ #define GetpDOEnd(target)         ((target)->end + 1)
+-#define SetDOBegin(target,val)   ((target).begin = (long) ((val) - 1))
+-#define SetDOEnd(target,val)     ((target).end = (long) ((val) - 1))
+-#define SetpDOBegin(target,val)   ((target)->begin = (long) ((val) - 1))
+-#define SetpDOEnd(target,val)     ((target)->end = (long) ((val) - 1))
++#define SetDOBegin(target,val)   ((target).begin = (long) ((long)(val) - 1))
++#define SetDOEnd(target,val)     ((target).end = (long) ((long)(val) - 1))
++#define SetpDOBegin(target,val)   ((target)->begin = (long) ((long)(val) - 1))
++#define SetpDOEnd(target,val)     ((target)->end = (long) ((long)(val) - 1))
+ 
+ #define EnvGetDOLength(theEnv,target)       (((target).end - (target).begin) + 1)
+ #define EnvGetpDOLength(theEnv,target)      (((target)->end - (target)->begin) + 1)
+@@ -95,10 +95,10 @@
+ #define EnvGetDOEnd(theEnv,target)          ((target).end + 1)
+ #define EnvGetpDOBegin(theEnv,target)       ((target)->begin + 1)
+ #define EnvGetpDOEnd(theEnv,target)         ((target)->end + 1)
+-#define EnvSetDOBegin(theEnv,target,val)   ((target).begin = (long) ((val) - 1))
+-#define EnvSetDOEnd(theEnv,target,val)     ((target).end = (long) ((val) - 1))
+-#define EnvSetpDOBegin(theEnv,target,val)   ((target)->begin = (long) ((val) - 1))
+-#define EnvSetpDOEnd(theEnv,target,val)     ((target)->end = (long) ((val) - 1))
++#define EnvSetDOBegin(theEnv,target,val)   ((target).begin = (long) ((long)(val) - 1))
++#define EnvSetDOEnd(theEnv,target,val)     ((target).end = (long) ((long)(val) - 1))
++#define EnvSetpDOBegin(theEnv,target,val)   ((target)->begin = (long) ((long)(val) - 1))
++#define EnvSetpDOEnd(theEnv,target,val)     ((target)->end = (long) ((long)(val) - 1))
+ 
+ #define DOPToString(target) (((struct symbolHashNode *) ((target)->value))->contents)
+ #define DOPToDouble(target) (((struct floatHashNode *) ((target)->value))->contents)
diff --git a/optpatch/evaluatn.h-01.v6.24-ia64.diff b/optpatch/evaluatn.h-01.v6.24-ia64.diff
new file mode 100644
index 0000000..232433b
--- /dev/null
+++ b/optpatch/evaluatn.h-01.v6.24-ia64.diff
@@ -0,0 +1,17 @@
+--- ../clipssrc0624_orig/evaluatn.h	Thu Jun 15 12:04:00 2006
++++ ../clipssrc/evaluatn.h	Fri Jun 16 19:56:07 2006
+@@ -88,10 +88,10 @@
+ #define GetDOEnd(target)          ((target).end + 1)
+ #define GetpDOBegin(target)       ((target)->begin + 1)
+ #define GetpDOEnd(target)         ((target)->end + 1)
+-#define SetDOBegin(target,val)   ((target).begin = (long) ((val) - 1))
+-#define SetDOEnd(target,val)     ((target).end = (long) ((val) - 1))
+-#define SetpDOBegin(target,val)   ((target)->begin = (long) ((val) - 1))
+-#define SetpDOEnd(target,val)     ((target)->end = (long) ((val) - 1))
++#define SetDOBegin(target,val)   ((target).begin = (long) ((long)(val) - 1))
++#define SetDOEnd(target,val)     ((target).end = (long) ((long)(val) - 1))
++#define SetpDOBegin(target,val)   ((target)->begin = (long) ((long)(val) - 1))
++#define SetpDOEnd(target,val)     ((target)->end = (long) ((long)(val) - 1))
+ 
+ #define EnvGetDOLength(theEnv,target)       (((target).end - (target).begin) + 1)
+ #define EnvGetpDOLength(theEnv,target)      (((target)->end - (target)->begin) + 1)
diff --git a/optpatch/factmngr.c-01.v6.23-test.diff b/optpatch/factmngr.c-01.v6.23-test.diff
new file mode 100644
index 0000000..5e9312c
--- /dev/null
+++ b/optpatch/factmngr.c-01.v6.23-test.diff
@@ -0,0 +1,10 @@
+--- ../clipssrc_orig/factmngr.c	Wed Feb  2 10:49:18 2005
++++ ../clipssrc/factmngr.c	Sun May 28 20:09:14 2006
+@@ -1056,6 +1056,7 @@
+         {
+          if (slotPtr->multislot)
+            {
++            theFact->theProposition.theFields[i].type = MULTIFIELD;
+             StoreInMultifield(theEnv,&theResult,slotPtr->defaultList,TRUE);
+             theFact->theProposition.theFields[i].value = DOToMultifield(theEnv,&theResult);
+            }
diff --git a/optpatch/factqury.c-01.v6.23-bgfx.diff b/optpatch/factqury.c-01.v6.23-bgfx.diff
new file mode 100644
index 0000000..356a8f7
--- /dev/null
+++ b/optpatch/factqury.c-01.v6.23-bgfx.diff
@@ -0,0 +1,154 @@
+--- ../clipssrc_orig/factqury.c	Thu Jan 20 09:16:20 2005
++++ ../clipssrc/factqury.c	Sun Jan 22 15:48:04 2006
+@@ -18,6 +18,8 @@
+ /* Revision History:                                         */
+ /*      6.23: Added fact-set queries.                        */
+ /*                                                           */
++/*      6.24: Corrected errors when compiling as a C++ file. */
++/*                                                           */
+ /*************************************************************/
+ 
+ /* =========================================
+@@ -181,7 +183,8 @@
+       position = 1;
+      }
+ 
+-   else if (FindSlot(theFact->whichDeftemplate,temp.value,&position) == NULL)
++   else if (FindSlot((struct deftemplate *) theFact->whichDeftemplate,
++                     (struct symbolHashNode *) temp.value,&position) == NULL)
+      {
+       SlotExistError(theEnv,ValueToString(temp.value),"fact-set query");
+       return;
+@@ -710,7 +713,7 @@
+   char *func,
+   DATA_OBJECT *val)
+   {
+-   struct deftemplate *template;
++   struct deftemplate *templatePtr;
+    QUERY_TEMPLATE *head,*bot,*tmp;
+    register long i,end; /* 6.04 Bug Fix */
+    char *templateName;
+@@ -720,7 +723,7 @@
+      {
+       IncrementDeftemplateBusyCount(theEnv,(void *) val->value);
+       head = get_struct(theEnv,query_template);
+-      head->template = (struct deftemplate *) val->value;
++      head->templatePtr = (struct deftemplate *) val->value;
+ 
+       head->chain = NULL;
+       head->nxt = NULL;
+@@ -735,17 +738,17 @@
+          module specifier is not given
+          =============================================== */
+          
+-      template = (struct deftemplate *)
++      templatePtr = (struct deftemplate *)
+                        FindImportedConstruct(theEnv,"deftemplate",NULL,DOPToString(val),
+                                              &count,TRUE,NULL);
+-      if (template == NULL)
++      if (templatePtr == NULL)
+         {
+          CantFindItemInFunctionErrorMessage(theEnv,"deftemplate",DOPToString(val),func);
+          return(NULL);
+         }
+-      IncrementDeftemplateBusyCount(theEnv,(void *) template);
++      IncrementDeftemplateBusyCount(theEnv,(void *) templatePtr);
+       head = get_struct(theEnv,query_template);
+-      head->template = template;
++      head->templatePtr = templatePtr;
+ 
+       head->chain = NULL;
+       head->nxt = NULL;
+@@ -761,11 +764,11 @@
+            {
+             templateName = ValueToString(GetMFValue(val->value,i));
+             
+-            template = (struct deftemplate *)
++            templatePtr = (struct deftemplate *)
+                        FindImportedConstruct(theEnv,"deftemplate",NULL,templateName,
+                                              &count,TRUE,NULL);
+ 
+-            if (template == NULL)
++            if (templatePtr == NULL)
+               {
+                CantFindItemInFunctionErrorMessage(theEnv,"deftemplate",templateName,func);
+                DeleteQueryTemplates(theEnv,head);
+@@ -777,9 +780,9 @@
+             DeleteQueryTemplates(theEnv,head);
+             return(NULL);
+            }
+-         IncrementDeftemplateBusyCount(theEnv,(void *) template);
++         IncrementDeftemplateBusyCount(theEnv,(void *) templatePtr);
+          tmp = get_struct(theEnv,query_template);
+-         tmp->template = template;
++         tmp->templatePtr = templatePtr;
+ 
+          tmp->chain = NULL;
+          tmp->nxt = NULL;
+@@ -815,12 +818,12 @@
+         {
+          tmp = qlist->chain;
+          qlist->chain = qlist->chain->chain;
+-         DecrementDeftemplateBusyCount(theEnv,(void *) tmp->template);
++         DecrementDeftemplateBusyCount(theEnv,(void *) tmp->templatePtr);
+          rtn_struct(theEnv,query_template,tmp);
+         }
+       tmp = qlist;
+       qlist = qlist->nxt;
+-      DecrementDeftemplateBusyCount(theEnv,(void *) tmp->template);
++      DecrementDeftemplateBusyCount(theEnv,(void *) tmp->templatePtr);
+       rtn_struct(theEnv,query_template,tmp);
+      }
+   }
+@@ -849,7 +852,7 @@
+      {
+       FactQueryData(theEnv)->AbortQuery = FALSE;
+ 
+-      if (TestForFirstFactInTemplate(theEnv,qptr->template,qchain,indx))
++      if (TestForFirstFactInTemplate(theEnv,qptr->templatePtr,qchain,indx))
+         { return(TRUE); }
+         
+       if ((EvaluationData(theEnv)->HaltExecution == TRUE) || (FactQueryData(theEnv)->AbortQuery == TRUE))
+@@ -871,14 +874,14 @@
+  *****************************************************************/
+ static int TestForFirstFactInTemplate(
+   void *theEnv,
+-  struct deftemplate *template,
++  struct deftemplate *templatePtr,
+   QUERY_TEMPLATE *qchain,
+   int indx)
+   {
+    struct fact *theFact;
+    DATA_OBJECT temp;
+ 
+-   theFact = template->factList;
++   theFact = templatePtr->factList;
+    while (theFact != NULL)
+      {
+       FactQueryData(theEnv)->QueryCore->solns[indx] = theFact;
+@@ -945,7 +948,7 @@
+      {
+       FactQueryData(theEnv)->AbortQuery = FALSE;
+ 
+-      TestEntireTemplate(theEnv,qptr->template,qchain,indx);
++      TestEntireTemplate(theEnv,qptr->templatePtr,qchain,indx);
+ 
+       if ((EvaluationData(theEnv)->HaltExecution == TRUE) || (FactQueryData(theEnv)->AbortQuery == TRUE))
+         return;
+@@ -967,14 +970,14 @@
+  *****************************************************************/
+ static void TestEntireTemplate(
+   void *theEnv,
+-  struct deftemplate *template,
++  struct deftemplate *templatePtr,
+   QUERY_TEMPLATE *qchain,
+   int indx)
+   {
+    struct fact *theFact;
+    DATA_OBJECT temp;
+ 
+-   theFact = template->factList;
++   theFact = templatePtr->factList;
+    while (theFact != NULL)
+      {
+       FactQueryData(theEnv)->QueryCore->solns[indx] = theFact;
diff --git a/optpatch/factqury.h-01.v6.23-bgfx.diff b/optpatch/factqury.h-01.v6.23-bgfx.diff
new file mode 100644
index 0000000..be118d0
--- /dev/null
+++ b/optpatch/factqury.h-01.v6.23-bgfx.diff
@@ -0,0 +1,20 @@
+--- ../clipssrc_orig/factqury.h	Wed Jan 19 19:11:38 2005
++++ ../clipssrc/factqury.h	Sun Jan 22 15:48:08 2006
+@@ -18,6 +18,8 @@
+ /* Revision History:                                         */
+ /*      6.23: Added fact-set queries.                        */
+ /*                                                           */
++/*      6.24: Corrected errors when compiling as a C++ file. */
++/*                                                           */
+ /*************************************************************/
+ 
+ #ifndef _H_factqury
+@@ -31,7 +33,7 @@
+ 
+ typedef struct query_template
+   {
+-   struct deftemplate *template;
++   struct deftemplate *templatePtr;
+    struct query_template *chain, *nxt;
+   } QUERY_TEMPLATE;
+ 
diff --git a/optpatch/genrcpsr.c-01.v6.23-bgfx.diff b/optpatch/genrcpsr.c-01.v6.23-bgfx.diff
new file mode 100644
index 0000000..e5f835a
--- /dev/null
+++ b/optpatch/genrcpsr.c-01.v6.23-bgfx.diff
@@ -0,0 +1,22 @@
+--- ../clipssrc_orig/genrcpsr.c	Mon Jun 16 20:35:00 2003
++++ ../clipssrc/genrcpsr.c	Wed May 31 15:40:25 2006
+@@ -283,6 +283,19 @@
+    actions = ParseProcActions(theEnv,"method",readSource,
+                               &DefgenericData(theEnv)->GenericInputToken,params,wildcard,
+                               NULL,NULL,&lvars,NULL);
++
++   /*===========================================================*/
++   /* Check for the closing right parenthesis of the defmethod. */
++   /*===========================================================*/
++
++   if ((DefgenericData(theEnv)->GenericInputToken.type != RPAREN) && /* DR0872 */
++       (actions != NULL))
++     {
++      DeleteTempRestricts(theEnv,params);
++      ReturnPackedExpression(theEnv,actions);
++      goto DefmethodParseError;
++     }
++
+    if (actions == NULL)
+      {
+       DeleteTempRestricts(theEnv,params);
diff --git a/optpatch/memalloc.c-01.v6.23-test.diff b/optpatch/memalloc.c-01.v6.23-test.diff
new file mode 100644
index 0000000..dc5fd96
--- /dev/null
+++ b/optpatch/memalloc.c-01.v6.23-test.diff
@@ -0,0 +1,33 @@
+--- ../clipssrc_orig/memalloc.c	Wed Feb  2 10:53:30 2005
++++ ../clipssrc/memalloc.c	Sun May 28 20:09:14 2006
+@@ -46,6 +46,21 @@
+ 
+ #define STRICT_ALIGN_SIZE sizeof(double)
+ 
++
++/* use Python memory allocator when compiling PyCLIPS */
++#ifdef PYCLIPS
++#include <Python.h>
++void *PyCLIPS_Malloc(size_t s);
++void PyCLIPS_Free(void *p);
++#if !BLOCK_MEMORY
++   #undef malloc
++   #define malloc PyCLIPS_Malloc
++   #undef free
++   #define free PyCLIPS_Free
++#endif /* BLOCK_MEMORY */
++#endif /* PYCLIPS */
++
++
+ #define SpecialMalloc(sz) malloc((STD_SIZE) sz)
+ #define SpecialFree(ptr) free(ptr)
+ 
+@@ -448,7 +463,7 @@
+            { YieldTime(theEnv); }
+         }
+       MemoryData(theEnv)->MemoryTable[i] = NULL;
+-      if (((amount > maximum) && (maximum > 0)) || EvaluationData(theEnv)->HaltExecution)
++      if ((amount > maximum) && (maximum > 0))
+         {
+          if (printMessage == TRUE)
+            { EnvPrintRouter(theEnv,WDIALOG,"*** MEMORY  DEALLOCATED ***\n"); }
diff --git a/optpatch/memalloc.c-01.v6.24-test.diff b/optpatch/memalloc.c-01.v6.24-test.diff
new file mode 100644
index 0000000..cbe1e23
--- /dev/null
+++ b/optpatch/memalloc.c-01.v6.24-test.diff
@@ -0,0 +1,24 @@
+--- ../clipssrc0624_orig/memalloc.c	Thu Jun 15 12:04:00 2006
++++ ../clipssrc/memalloc.c	Fri Jun 16 22:39:29 2006
+@@ -53,6 +53,21 @@
+ 
+ #define STRICT_ALIGN_SIZE sizeof(double)
+ 
++
++/* use Python memory allocator when compiling PyCLIPS */
++#ifdef PYCLIPS
++#include <Python.h>
++void *PyCLIPS_Malloc(size_t s);
++void PyCLIPS_Free(void *p);
++#if !BLOCK_MEMORY
++   #undef malloc
++   #define malloc PyCLIPS_Malloc
++   #undef free
++   #define free PyCLIPS_Free
++#endif /* BLOCK_MEMORY */
++#endif /* PYCLIPS */
++
++
+ #define SpecialMalloc(sz) malloc((STD_SIZE) sz)
+ #define SpecialFree(ptr) free(ptr)
+ 
diff --git a/optpatch/objrtmch.c-01.v6.24-bgfx.diff b/optpatch/objrtmch.c-01.v6.24-bgfx.diff
new file mode 100644
index 0000000..1d1fa0a
--- /dev/null
+++ b/optpatch/objrtmch.c-01.v6.24-bgfx.diff
@@ -0,0 +1,79 @@
+--- ../clipssrc0624_orig/objrtmch.c	Thu Jun 15 12:04:00 2006
++++ ../clipssrc/objrtmch.c	Fri Jun 23 15:17:46 2006
+@@ -1,7 +1,7 @@
+    /*******************************************************/
+    /*      "C" Language Integrated Production System      */
+    /*                                                     */
+-   /*               CLIPS Version 6.24  05/17/06          */
++   /*               CLIPS Version 6.25  06/22/06          */
+    /*                                                     */
+    /*          OBJECT PATTERN MATCHER MODULE              */
+    /*******************************************************/
+@@ -25,6 +25,14 @@
+ /*                                                            */
+ /*            Renamed BOOLEAN macro type to intBool.          */
+ /*                                                            */
++/*      6.25: Modified the QueueObjectMatchAction function    */
++/*            so that instance retract actions always occur   */
++/*            before instance assert and modify actions.      */
++/*            This prevents the pattern matching process      */
++/*            from attempting the evaluation of a join        */
++/*            expression that accesses the slots of a         */
++/*            retracted instance.                             */
++/*                                                            */
+ /**************************************************************/
+ /* =========================================
+    *****************************************
+@@ -393,6 +401,7 @@
+   int slotNameID)
+   {
+    OBJECT_MATCH_ACTION *prv,*cur,*newMatch;
++   OBJECT_MATCH_ACTION *prvRetract = NULL; /* DR0873 */
+ 
+    prv = NULL;
+    cur = ObjectReteData(theEnv)->ObjectMatchActionQueue;
+@@ -463,6 +472,9 @@
+ 
+          return;
+         }
++        
++      if (cur->type == OBJECT_RETRACT) /* DR0873 */ 
++        { prvRetract = cur; }          /* DR0873 */
+       prv = cur;
+       cur = cur->nxt;
+      }
+@@ -473,11 +485,33 @@
+       ================================================ */
+    newMatch = get_struct(theEnv,objectMatchAction);
+    newMatch->type = type;
+-   newMatch->nxt = cur;
++   newMatch->nxt = NULL; /* If we get here, cur should be NULL */
+    newMatch->slotNameIDs = (type != OBJECT_MODIFY) ? NULL :
+                        QueueModifySlotMap(theEnv,NULL,slotNameID);
+    newMatch->ins = ins;
+    newMatch->ins->busy++;
++   
++   /* DR0873 Begin */
++   /* Retract operations must be processed before assert and   */
++   /* modify actions, otherwise the pattern matching process   */
++   /* might attempt to access the slots of a retract instance. */
++
++   if (type == OBJECT_RETRACT)
++     {
++      if (prvRetract == NULL)
++        {
++         newMatch->nxt = ObjectReteData(theEnv)->ObjectMatchActionQueue;
++         ObjectReteData(theEnv)->ObjectMatchActionQueue = newMatch;
++        }
++      else
++        {
++         newMatch->nxt = prvRetract->nxt;
++         prvRetract->nxt = newMatch;
++        }
++     }
++   else
++   /* DR0873 End */
++   
+    if (prv == NULL)
+      ObjectReteData(theEnv)->ObjectMatchActionQueue = newMatch;
+    else
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..2bbee60
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,941 @@
+#!/usr/bin/env python
+# setup.py
+# setup program for clips module
+
+# (c) 2002-2008 Francesco Garosi/JKS
+#  The author's copyright is expressed through the following notice, thus
+#  giving effective rights to copy and use this software to anyone, as shown
+#  in the license text.
+#
+# NOTICE:
+#  This software is released under the terms of the GNU Lesser General Public
+#  license; a copy of the text has been released with this package (see file
+#  _license.py, where the license text also appears), and can be found on the
+#  GNU web site, at the following address:
+#
+#           http://www.gnu.org/copyleft/lesser.html
+#
+#  Please refer to the license text for any license information. This notice
+#  has to be considered part of the license, and should be kept on every copy
+#  integral or modified, of the source files. The removal of the reference to
+#  the license will be considered an infringement of the license itself.
+
+
+"""PyCLIPS
+A Python module to interface the CLIPS expert system shell library."""
+
+
+__revision__ = "$Id: setup.py 342 2008-02-22 01:17:23Z Franz $"
+print "Module 'clips': Python to CLIPS interface"
+print "Setup revision: %s" % __revision__
+
+
+# the following values generate the version number and some of them
+#  are modified via an automatic process; version information has been
+#  made this detailed in order to help setuptools to better decide
+#  whether or not to replace an existing package
+PYCLIPS_MAJOR = 1
+PYCLIPS_MINOR = 0
+PYCLIPS_PATCHLEVEL = 7
+PYCLIPS_INCREMENTAL = 348
+PYCLIPS_VERSION = "%s.%s.%s.%s" % (
+    PYCLIPS_MAJOR,
+    PYCLIPS_MINOR,
+    PYCLIPS_PATCHLEVEL,
+    PYCLIPS_INCREMENTAL)
+
+
+from glob import glob
+import os, sys, re, tempfile
+
+
+# remove unwanted patch sets from this list (not recommended)
+APPLY_PATCHSETS = [
+    'ia64',     # ia_64 related fixes
+    'bgfx',     # official patches to the CLIPS source
+    'test',     # "experimental" (unofficial) but useful patches
+    ]
+
+# this will be used to download CLIPS source if not found
+CLIPS_SRC_URL = "http://pyclips.sourceforge.net/files/CLIPSSrc.zip"
+
+# standard indentation for conversion (4 spaces)
+INDENT = " " * 4
+
+
+# a shortcut, since it appears many times
+_p = os.path.join
+
+# find Clips source directory and zip file
+zl, zd = os.listdir("."), {}
+for x in zl:
+    zd[x.lower()] = x
+try:
+    ClipsSrcZIP = _p('.', zd['clipssrc.zip'])
+except:
+    ClipsSrcZIP = "CLIPSSrc.zip"    # will obviously produce an error
+ClipsLIB_dir = _p('.', 'clipssrc')
+ClipsPATCH_dir = _p('.', 'optpatch')
+
+
+# make a new setup.h based on current platform (note: this file is a copy
+#  of the original setup.h file, and is subject to the license terms that
+#  can be found in all the original CLIPS source files). This is the only
+#  chunk of code which may not be subject to the same license as the others
+#  (although all of this code is released under an Open Source license)
+setup_h_templ = """\
+/*************************************************************/
+/* Principal Programmer(s):                                  */
+/*      Gary D. Riley                                        */
+/*      Brian L. Donnell                                     */
+/* Contributing Programmer(s):                               */
+/* Revision History:                                         */
+/*************************************************************/
+#ifndef _H_setup
+#define _H_setup
+
+#define GENERIC 0
+#define UNIX_V  %s
+#define UNIX_7  0
+#define MAC_MCW 0
+#define IBM_MCW 0
+#define IBM_MSC %s
+#define IBM_TBC 0
+#define IBM_GCC %s
+
+#define IBM_ZTC 0
+#define IBM_ICB 0
+#define IBM_SC  0
+#define MAC_SC6 0
+#define MAC_SC7 0
+#define MAC_SC8 0
+#define MAC_MPW 0
+#define VAX_VMS 0
+#define MAC_XCD 0
+
+#if IBM_ZTC || IBM_MSC || IBM_TBC || IBM_ICB || IBM_SC || IBM_MCW
+#define IBM 1
+#else
+#define IBM 0
+#endif
+
+#if MAC_SC6 || MAC_SC7 || MAC_SC8
+#define MAC_SC 1
+#else
+#define MAC_SC 0
+#endif
+
+#if MAC_SC || MAC_MPW || MAC_MCW || MAC_XCD
+#define MAC 1
+#else
+#define MAC 0
+#endif
+
+
+#if CLIPS_MAJOR >= 6
+
+#if CLIPS_MINOR < 23
+#error "Cannot build using CLIPS version less than 6.23"
+#endif /* CLIPS_MINOR >= 23 */
+
+#define VOID     void
+#define VOID_ARG void
+#define STD_SIZE size_t
+
+#if CLIPS_MINOR < 24
+#define BOOLEAN int
+#else
+#define intBool int
+#endif /* CLIPS_MINOR < 24 */
+
+#define globle
+
+#define ALLOW_ENVIRONMENT_GLOBALS 1
+#define BASIC_IO 1
+#define BLOAD 0
+#define BLOAD_AND_BSAVE 1
+#define BLOAD_ONLY 0
+#define BLOAD_INSTANCES 1
+#define BLOCK_MEMORY 0
+#define BSAVE_INSTANCES 1
+#define CONFLICT_RESOLUTION_STRATEGIES 1
+#define CONSTRUCT_COMPILER 0
+#define DEBUGGING_FUNCTIONS 1
+#define DEFFACTS_CONSTRUCT 1
+#define DEFFUNCTION_CONSTRUCT 1
+#define DEFGENERIC_CONSTRUCT 1
+#define DEFGLOBAL_CONSTRUCT 1
+#define DEFINSTANCES_CONSTRUCT 1
+#define DEFMODULE_CONSTRUCT 1
+#define DEFRULE_CONSTRUCT 1
+#define DEFTEMPLATE_CONSTRUCT 1
+#define EMACS_EDITOR 0
+#define ENVIRONMENT_API_ONLY 0
+#define EX_MATH 1
+#define EXT_IO 1
+#define FACT_SET_QUERIES 1
+#define HELP_FUNCTIONS 0
+#define INSTANCE_SET_QUERIES 1
+#define MULTIFIELD_FUNCTIONS 1
+#define OBJECT_SYSTEM 1
+#define PROFILING_FUNCTIONS 1
+#define RUN_TIME 0
+#define STRING_FUNCTIONS 1
+#define TEXTPRO_FUNCTIONS 1
+#define WINDOW_INTERFACE 1
+
+#define DEVELOPER 0
+
+#if CLIPS_MINOR < 24
+#define AUXILIARY_MESSAGE_HANDLERS 1
+#define DYNAMIC_SALIENCE 1
+#define IMPERATIVE_MESSAGE_HANDLERS 1
+#define IMPERATIVE_METHODS 1
+#define INCREMENTAL_RESET 1
+#define INSTANCE_PATTERN_MATCHING 1
+#define LOGICAL_DEPENDENCIES  1
+#define SHORT_LINK_NAMES 0
+#endif  /* CLIPS_MINOR < 24 */
+
+#else   /* CLIPS_MAJOR >= 6 */
+#error "Cannot build using CLIPS version less than 6.23"
+#endif
+
+#include "envrnmnt.h"
+
+#define Bogus(x)
+#define PrintCLIPS(x,y) EnvPrintRouter(GetCurrentEnvironment(),x,y)
+#define GetcCLIPS(x,y) EnvGetcRouter(GetCurrentEnvironment(),x)
+#define UngetcCLIPS(x,y) EnvUngetcRouter(GetCurrentEnvironment(),x,y)
+#define ExitCLIPS(x) EnvExitRouter(GetCurrentEnvironment(),x)
+#define CLIPSSystemError(x,y) SystemError(x,y)
+#define CLIPSFunctionCall(x,y,z) FunctionCall(x,y,z)
+#define InitializeCLIPS() InitializeEnvironment()
+#define WCLIPS WPROMPT
+#define CLIPSTrueSymbol SymbolData(GetCurrentEnvironment())->TrueSymbol
+#define CLIPSFalseSymbol SymbolData(GetCurrentEnvironment())->FalseSymbol
+#define EnvCLIPSTrueSymbol(theEnv) SymbolData(theEnv)->TrueSymbol
+#define EnvCLIPSFalseSymbol(theEnv) SymbolData(theEnv)->FalseSymbol
+#define CLIPS_FALSE 0
+#define CLIPS_TRUE 1
+#if BLOCK_MEMORY
+#define INITBLOCKSIZE 32000
+#define BLOCKSIZE 32000
+#endif
+
+#include "usrsetup.h"
+
+#endif  /* _H_setup */
+"""
+
+
+
+# find out symbols that are imported from clipsmodule.c: if we keep
+#  using this "protocol" for declaring symbols, it could be used also
+#  to read other possible C source files; we define IMPORTED_SYMBOLS
+#  here just because it is used as global in some functions below
+IMPORTED_SYMBOLS = []
+def find_imported_symbols(filename):
+    f = open(filename)
+    li = [x for x in map(str.strip, f.readlines())
+          if x.startswith('ADD_MANIFEST_CONSTANT(')
+          or x.startswith('MMAP_ENTRY(')]
+    f.close()
+    li1 = []
+    for x in li:
+        if x.startswith('ADD_MANIFEST_CONSTANT('):
+            x = x.replace('ADD_MANIFEST_CONSTANT(d,', '')
+            x = x.replace(');', '').strip()
+        else:
+            x = x.replace('MMAP_ENTRY(', '')
+            x = x.split(',')[0].strip()
+        li1.append(x)
+    return li1
+
+
+
+
+# parts of the companion module file
+MODULE_TEMPLATE = '''\
+# _eclips_wrap.py
+# environment aware functions for CLIPS, embedded in an Environment class
+
+# (c) 2002-2008 Francesco Garosi/JKS
+#  The Author's copyright is expressed through the following notice, thus
+#  giving actual rights to copy and use this software to anyone, as expressed
+#  in the license text.
+#
+# NOTICE:
+# This software is released under the terms of the GNU Lesser General Public
+#  license; a copy of the text has been released with this package (see file
+#  license.py), and can be found on the GNU web site, at the following
+#  address:
+#
+#           http://www.gnu.org/copyleft/lesser.html
+#
+#  Please refer to the license text for any license information. This notice
+#  has to be considered part of the license, and should be kept on every copy
+#  integral or modified, of the source files. The removal of the reference to
+#  the license will be considered an infringement of the license itself.
+
+"""\
+clips - high-level interface to the CLIPS engine module
+        (c) 2002-2008 Francesco Garosi/JKS
+"""
+
+# standard imports
+import sys as _sys
+
+import os as  _os
+import types as _types
+
+# the low-level module
+import _clips as _c
+
+
+# ========================================================================== #
+# globals
+
+# bring the CLIPS Exception object at top level
+ClipsError = _c.ClipsError
+
+
+# redeclare manifest constants here in order to avoid having to
+#  reference the ones defined in te low-level module _clips
+
+# check Python version, and issue an exception if not supported
+if _sys.version[:3] < "2.4":
+    raise _c.ClipsError("M99: Python 2.4 or higher required")
+
+
+# these globals are redefined instead of reimported for sake of speed
+LOCAL_SAVE = _c.LOCAL_SAVE
+VISIBLE_SAVE = _c.VISIBLE_SAVE
+
+WHEN_DEFINED = _c.WHEN_DEFINED
+WHEN_ACTIVATED = _c.WHEN_ACTIVATED
+EVERY_CYCLE = _c.EVERY_CYCLE
+
+NO_DEFAULT = _c.NO_DEFAULT
+STATIC_DEFAULT = _c.STATIC_DEFAULT
+DYNAMIC_DEFAULT = _c.DYNAMIC_DEFAULT
+
+DEPTH_STRATEGY = _c.DEPTH_STRATEGY
+BREADTH_STRATEGY = _c.BREADTH_STRATEGY
+LEX_STRATEGY = _c.LEX_STRATEGY
+MEA_STRATEGY = _c.MEA_STRATEGY
+COMPLEXITY_STRATEGY = _c.COMPLEXITY_STRATEGY
+SIMPLICITY_STRATEGY = _c.SIMPLICITY_STRATEGY
+RANDOM_STRATEGY = _c.RANDOM_STRATEGY
+
+CONVENIENCE_MODE = _c.CONVENIENCE_MODE
+CONSERVATION_MODE = _c.CONSERVATION_MODE
+
+
+# import adequate symbols from _clips_wrap
+from _clips_wrap import Nil, Integer, Float, String, Symbol, InstanceName, \\
+                        Multifield, _cl2py, _py2cl, _py2clsyntax, \\
+                        ClipsIntegerType, ClipsFloatType, ClipsStringType, \\
+                        ClipsSymbolType, ClipsInstanceNameType, \\
+                        ClipsMultifieldType, ClipsNilType, \\
+                        _setStockClasses, _accepts_method, _forces_method, \\
+                        AROUND, BEFORE, PRIMARY, AFTER
+
+
+
+# environment class:
+class Environment(object):
+    """class representing an environment: implements all global classes"""
+
+%(MEMBER_CLASSES)s
+
+    # constructor possibly sets the "borrowed" flag, to state that this
+    #  is a Python class around an existing object: in this case the
+    #  underlying CLIPS environment is not attempted to be destroyed on
+    #  deletion
+    def __init__(self, o=None):
+        """environment constructor"""
+        if o is None:
+            self.__env = _c.createEnvironment()
+            self.__borrowed = False
+        else:
+            if _c.isEnvironment(o):
+                self.__env = o
+                self.__borrowed = True
+            else:
+                raise TypeError("invalid argument for constructor")
+%(CLASS_INIT)s
+        # if o is not None, then this is an internal object and its status
+        #  should not be modified by the user, nor the stock objects be
+        #  accessible for direct inspection or subclassing (as this could
+        #  be the current environment and might be corrupted)
+        if o is None:
+            self.EngineConfig = self._clips_Status()
+            self.DebugConfig = self._clips_Debug()
+
+%(MEMBER_FUNCTIONS)s
+
+    def __del__(self):
+        """environment destructor"""
+        if not self.__borrowed:
+            try:
+                _c.destroyEnvironment(self.__env)
+            except ClipsError:
+                pass
+
+    def __repr__(self):
+        """representation of environment, borrowed by underlying object"""
+        return "<Environment: " + repr(self.__env)[1:-1] + ">"
+
+    def __property_getIndex(self):
+        return _c.getEnvironmentIndex(self.__env)
+    Index = property(__property_getIndex, None, None,
+                     "Return index of this Environment")
+
+    def SetCurrent(self):
+        """Make this Environment the current Environment"""
+        _c.setCurrentEnvironment(self.__env)
+        _setStockClasses()
+
+
+
+# A function that returns current Environment
+def CurrentEnvironment():
+    """Return current Environment"""
+    cenv = _c.getCurrentEnvironment()
+    env = Environment(cenv)
+    env.EngineConfig = env._clips_Status()
+    env.DebugConfig = env._clips_Debug()
+    return env
+
+
+
+# end.
+'''
+
+
+# this is what all the functions in the low-level module look like
+func_re = re.compile(r"(_c\.\w+\()")
+func_re_NA = re.compile(r"(_c\.\w+\(\))")
+class_re = re.compile(r"^class\ ")
+def_re = re.compile(r"def\ (\w+\()")
+def_re_NA = re.compile(r"def\ (\w+\(\))")
+
+
+# ========================================================================== #
+
+ALL_CLASSES = {}
+ALL_FUNCTIONS = {}
+
+def useful_line(s):
+    s1 = s.strip()
+    return bool(s1 and not s1.startswith('#'))
+
+def remove_leading_underscore(s):
+    while s[0] == "_":
+        s = s[1:]
+    return s
+
+# read the module (which contains the special class/function markers) and
+#  extract all top-level functions and classes to be put in Environment
+def _i_read_module(f):
+    global ALL_CLASSES, ALL_FUNCTIONS
+    li = f.readlines()
+    for i in range(len(li)):
+        l = li[i]
+        if l.strip() == "#{{CLASS":
+            while not li[i].strip().startswith('class'):
+                i += 1
+            classname = li[i].split('(', 1)[0].replace('class', '').strip()
+            text = [li[i]]
+            i += 1
+            while li[i].strip() != "#}}":
+                if useful_line(li[i]):
+                    text.append(li[i])
+                i += 1
+            ALL_CLASSES[classname] = text
+        elif l.strip() == "#{{FUNCTION":
+            text = []
+            while not li[i].strip().startswith('def'):
+                if li[i].strip().startswith('@'):
+                    text.append(li[i])
+                i += 1
+            funcname = li[i].split('(', 1)[0].replace('def', '').strip()
+            text.append(li[i])
+            i += 1
+            while li[i].strip() != "#}}":
+                if useful_line(li[i]):
+                    text.append(li[i])
+                i += 1
+            ALL_FUNCTIONS[funcname] = text
+        i += 1
+
+# hack to convert direct instantiations of classes in return values
+def _i_convert_classinstantiation_c(s):
+    if s.split()[0] == 'class':
+        return s
+    for x in ALL_CLASSES.keys():
+        s = s.replace(" %s(" % x, " self.__envobject.%s(" % x)
+        s = s.replace("(%s(" % x, "(self.__envobject.%s(" % x)
+    return s
+
+def _i_convert_classinstantiation(s):
+    if s.split()[0] == 'class':
+        return s
+    for x in ALL_CLASSES.keys():
+        s = s.replace(" %s(" % x, " self.%s(" % x)
+        s = s.replace("(%s(" % x, "(self.%s(" % x)
+    return s
+
+
+# convert a single line of code and return it indented
+def _i_convert_line(s, cvtdef=False):
+    if s.strip() == "":
+        return ""
+    if s.strip()[0] == "#":
+        return ""
+    s1 = s
+    if not s1.strip().startswith("def "):
+        s1 = s1.replace(" _cl2py(", " self._cl2py(")
+        s1 = s1.replace(" _py2cl(", " self._py2cl(")
+        s1 = s1.replace("(_cl2py(", "(self._cl2py(")
+        s1 = s1.replace("(_py2cl(", "(self._py2cl(")
+    if s1.strip().startswith("@"):
+        s1 = s1.replace("@_accepts(", "@_accepts_method(")
+        s1 = s1.replace("@_forces(", "@_forces_method(")
+    mo = func_re.search(s1)
+    if mo:
+        li = mo.groups()
+        for x in li:
+            t = x[3:-1]
+            if "env_%s" % t in IMPORTED_SYMBOLS:
+                if func_re_NA.search(s1):
+                    s1 = s1.replace(x, "_c.env_%s(self.__env" % t)
+                else:
+                    s1 = s1.replace(x, "_c.env_%s(self.__env, " % t)
+    if cvtdef:
+        mo = def_re.search(s1)
+        if mo:
+            if def_re_NA.search(s1):
+                s1 = def_re.sub(mo.group(0) + "self", s1)
+            else:
+                s1 = def_re.sub(mo.group(0) + "self, ", s1)
+        for x in ALL_CLASSES.keys():
+            s1 = s1.replace(" %s(" % x, " self.%s(" % x)
+            s1 = s1.replace(" %s:" % x, " self.%s:" % x)
+            s1 = s1.replace("(%s(" % x, "(self.%s(" % x)
+    return INDENT + _i_convert_classinstantiation(s1)
+
+def _i_convert_classline(s):
+    if s.strip() == "":
+        return ""
+    if s.strip()[0] == "#":
+        return ""
+    s1 = s
+    if not s1.strip().startswith("def "):
+        s1 = s1.replace(" _cl2py(", " self.__envobject._cl2py(")
+        s1 = s1.replace(" _py2cl(", " self.__envobject._py2cl(")
+        s1 = s1.replace("(_cl2py(", "(self.__envobject._cl2py(")
+        s1 = s1.replace("(_py2cl(", "(self.__envobject._py2cl(")
+    if s1.strip().startswith("@"):
+        s1 = s1.replace("@_accepts(", "@_accepts_method(")
+        s1 = s1.replace("@_forces(", "@_forces_method(")
+    mo = func_re.search(s1)
+    if mo:
+        li = mo.groups()
+        for x in li:
+            t = x[3:-1]
+            if "env_%s" % t in IMPORTED_SYMBOLS:
+                if func_re_NA.search(s1):
+                    s1 = s1.replace(x, "_c.env_%s(self.__env" % t)
+                else:
+                    s1 = s1.replace(x, "_c.env_%s(self.__env, " % t)
+    return INDENT + INDENT + _i_convert_classinstantiation_c(s1)
+
+# convert an entire class, provided as a list of lines
+def _i_convert_fullclass(name, li):
+    li1 = li[1:]
+    docs = []
+    while li1[0].strip()[0] in ['"', "'"]:
+        docs.append(li1[0])
+        li1 = li1[1:]
+    head1 = INDENT + "def %s(self, private_environment):\n" % name
+    head2 = INDENT + INDENT + "environment_object = self\n"
+    head3 = INDENT + INDENT + "class %s(object):\n" % name
+    head4 = INDENT + INDENT + INDENT + "__env = private_environment\n"
+    head5 = INDENT + INDENT + INDENT + "__envobject = environment_object\n"
+    foot1 = INDENT + INDENT + "return %s\n"  % name
+    return [head1, head2, head3] + map(_i_convert_classline, docs) \
+       + [head4, head5] + map(_i_convert_classline, li1) + [foot1]
+
+# convert an entire function, provided as a list of lines
+def _i_convert_fullfunction(name, li):
+    return map(lambda x: _i_convert_line(x, True), li)
+
+# create the list of lines that build inner classes in Environment.__init__
+def _i_create_inner_classes():
+    inner = []
+    kclasses = ALL_CLASSES.keys()
+    kclasses.sort()
+    for x in kclasses:
+        inner.append(
+            INDENT + INDENT + "self.%s = self.%s(self.__env)\n" % (x, x))
+    return inner
+
+
+# macro to convert all the read module
+def convert_module(filename):
+    f = open(filename)
+    _i_read_module(f)
+    f.close()
+    classes = []
+    kclasses = ALL_CLASSES.keys()
+    kclasses.sort()
+    for x in kclasses:
+        classes += _i_convert_fullclass(x, ALL_CLASSES[x])
+    initclasses = _i_create_inner_classes()
+    functions = []
+    kfunctions = ALL_FUNCTIONS.keys()
+    kfunctions.sort()
+    for x in kfunctions:
+        functions += _i_convert_fullfunction(x, ALL_FUNCTIONS[x])
+    return MODULE_TEMPLATE % {
+        'MEMBER_CLASSES': "".join(classes),
+        'CLASS_INIT': "".join(initclasses),
+        'MEMBER_FUNCTIONS': "".join(functions),
+        }
+
+# ========================================================================== #
+
+
+# This retrieves the CLIPS version looking up headers
+def get_clips_version(fn):
+    li = open(fn).readlines()
+    cre = re.compile(r"\#define\ VERSION_STRING\ \"([0-9]+\.[0-9]+)\"")
+    vno = "unknown"
+    for s in li:
+        f = cre.search(s)
+        if f:
+            vno = f.groups(1)
+            break
+    return "%s" % vno
+
+
+
+# Actual distutils setup routine
+
+# check for CLIPS library files, and eventually uncompress them from
+#  the CLIPS source - to be found at CLIPS website. In case no ZIP
+#  file is even present here, notice the user that it has to be
+#  downloaded and put here, in the directory where this file resides
+nozip_notice = """\
+ERROR: setup.py could not find the CLIPS source files. These files
+       are necessary to build the CLIPS interface module: please
+       download the archive (%s) and copy it to the directory
+       where setup.py resides. The setup program will take care of
+       unpacking the necessary source files in an appropriate place.
+"""
+
+badzip_notice = """\
+ERROR: setup.py could not read one or more file(s) from the source
+       archive. Please provide a good copy of the archive (%s).
+"""
+
+
+# this is used to normalize end-of-line characters across systems, since we
+#  use the ZIP version of the archive (which is for Win32/DOS systems). The
+#  use of TemporaryFile is a hack, but so we can read lines letting Python
+#  do the dirty job of removing bad EOLs.
+def normalize_eols(t):
+    def _remove_badchars(x):
+        t = ""
+        x = x.replace('\t', " " * 8)
+        for c in x:
+            if ord(c) >= 32 and ord(c) < 128:
+                t += c
+        return t
+    tf = tempfile.TemporaryFile()
+    tf.write(t)
+    tf.seek(0)
+    li = tf.readlines()
+    tf.close()
+    li = map(lambda x: x.rstrip(), li)
+    li = map(_remove_badchars, li)
+    return li
+
+
+if not os.path.exists(ClipsLIB_dir):
+    if not os.path.exists(ClipsSrcZIP):
+        # try to download file from official site
+        import urllib
+        print "CLIPS source archive (%s) not found, " \
+              "trying to download it for you..." % ClipsSrcZIP
+        try:
+            f = urllib.urlopen(CLIPS_SRC_URL)
+            s = f.read()
+            if not s:
+                raise   # anyway we'll answer that the source wasn't found
+            f = open(ClipsSrcZIP, 'wb')
+            f.write(s)
+            f.close()
+            print "Download successful, continuing build."
+            print "Please review CLIPS license in the downloaded ZIP file!"
+        except:
+            print "Download FAILED!"
+            print nozip_notice % ClipsSrcZIP
+            sys.exit(2)
+    import zipfile
+    try:
+        print "Opening CLIPS source archive (%s)..." % ClipsSrcZIP
+        zf = zipfile.ZipFile(ClipsSrcZIP)
+        os.mkdir(ClipsLIB_dir)
+        li = zf.namelist()
+        for x in li:
+            n = _p(ClipsLIB_dir, os.path.basename(x))
+            if n.endswith('.h') or n.endswith('.c'):
+                sys.stdout.write("\tExtracting %s... " % n)
+                li = normalize_eols(zf.read(x))
+                f = open(n, 'w')
+                for t in li:
+                    f.write("%s\n" % t)
+                f.close()
+                sys.stdout.write("done.\n")
+        zf.close()
+        print "All CLIPS source files extracted, continuing build."
+    except zipfile.error:
+        print badzip_notice % ClipsSrcZIP
+        sys.exit(2)
+    except:
+        print nozip_notice % ClipsSrcZIP
+        sys.exit(2)
+
+
+
+# ----------------------------------------------------------------------------
+# -- 8-< -- CUT FROM HERE --------------------------------------------- >-8 --
+
+bad_platform = """\
+setup.py: setup provided only for posix/win32 systems
+NOTE: If you want to provide your own setup.h file, please remove the lines
+      between the CUT ... HERE markers and edit your setup.h file using the
+      original file (setup.h or setup.h.m_ORIG). Please be cautious doing so,
+      since the module expects all the constructs and functions defined in
+      the ad-hoc configuration file to be available: modifying setup.h by
+      yourself may lead to an inconsistent module or compilation errors.
+"""
+if sys.platform == "win32":
+    defines = (0, 1, 0)
+elif os.name == "posix":
+    defines = (0, 0, 1)
+else:
+    sys.stderr.write(bad_platform)
+    sys.exit(2)
+
+setup_h = setup_h_templ % defines
+
+# rename setup.h to setup.h.ORIG to keep a copy of original file; if the
+#  copy already exists, we are supposed to already have built the new
+#  CLIPS setup file, thus we do not
+setup_orig_name = _p(ClipsLIB_dir, 'setup.h')
+setup_copy_name = _p(ClipsLIB_dir, 'setup.h.m_ORIG')
+if os.path.exists(setup_orig_name) and not os.path.exists(setup_copy_name):
+    sys.stdout.write("copying setup.h to setup.h.m_ORIG, making new header...")
+    os.rename(setup_orig_name, setup_copy_name)
+    f = open(setup_orig_name, 'w')
+    f.write(setup_h)
+    f.close()
+    sys.stdout.write("Done.\n")
+
+# -- 8-< -- CUT UP TO HERE -------------------------------------------- >-8 --
+# ----------------------------------------------------------------------------
+
+
+# here we remove the (exit) function from CLIPS to prevent aborting Python
+routerc_orig_name = _p(ClipsLIB_dir, 'router.c')
+routerc_copy_name = _p(ClipsLIB_dir, 'router.c.m_ORIG')
+if os.path.exists(routerc_orig_name) and not os.path.exists(routerc_copy_name):
+    sys.stdout.write("copying router.c to router.c.m_ORIG, making new source...")
+    f = open(routerc_orig_name)
+    li = f.readlines()
+    f.close()
+    os.rename(routerc_orig_name, routerc_copy_name)
+    badline_re = re.compile(
+        "\s*EnvDefineFunction2.+exit.+ExitCommand.+ExitCommand.+")
+    f = open(routerc_orig_name, 'w')
+    for l in li:
+        if badline_re.match(l):
+            f.write("/* INTENTIONALLY SKIPPED */\n")
+            f.write("#ifndef PYCLIPS\n")
+            f.write(l)
+            f.write("#endif /* PYCLIPS */\n")
+        else:
+            f.write(l)
+    f.close()
+    sys.stdout.write("Done.\n")
+
+
+# remove some source files as they interfere with clipsmodule.c
+TO_REMOVE = [
+    'main.c',
+    'userfunctions.c',
+    ]
+
+all_clipssrc = glob(_p(ClipsLIB_dir, '*.c'))
+main_clipssrc = ['clipsmodule.c', 'clips_or.c']
+for x in all_clipssrc:
+    if os.path.basename(x) in TO_REMOVE:
+        all_clipssrc.remove(x)
+
+
+# actually build "companion" module: first we calculate the list of
+#  all symbols that are imported from the low-level module, and then
+#  we read the environment-unaware high-level module to build the
+#  environment-aware part using the above helpers
+sys.stdout.write("finding low-level module symbols... ")
+IMPORTED_SYMBOLS = find_imported_symbols(_p('.', 'clipsmodule.c'))
+sys.stdout.write("Done!\nbuilding environment-aware submodule... ")
+s = convert_module(_p('clips', '_clips_wrap.py'))
+f = open(_p('clips', '_eclips_wrap.py'), 'w')
+f.write(s)
+f.close()
+sys.stdout.write("Done!\n")
+
+
+# retrieve used CLIPS version
+clips_version = get_clips_version(_p("clipssrc", "constant.h"))
+print "Found CLIPS version: %s" % clips_version
+maj, min = clips_version.split('.', 1)
+CFLAGS = [
+    '-DPYCLIPS',
+    '-DCLIPS_MAJOR=%s' % maj,
+    '-DCLIPS_MINOR=%s' % min,
+    '-DPYCLIPS_MAJOR=%s' % PYCLIPS_MAJOR,
+    '-DPYCLIPS_MINOR=%s' % PYCLIPS_MINOR,
+    '-DPYCLIPS_PATCHLEVEL=%s' % PYCLIPS_PATCHLEVEL,
+    '-DPYCLIPS_INCREMENTAL=%s' % PYCLIPS_INCREMENTAL,
+    ]
+
+
+# if we are using GCC we must set an extra option; for now we assume that
+#  GCC is used unless, on Win32, compiler is explicitly specified as one
+#  of 'unix', 'mingw32', 'cygwin'; note that this will force to *always*
+#  specify compiler even when using setuptools and the default compiler
+#  is set to be one of the above; maybe one day I will discover a better
+#  way to determine which compiler is used without having to rewrite all
+#  of distutils
+if sys.platform == 'win32':
+    try:
+        find_compiler = sys.argv.index('-c') + 1
+    except ValueError:
+        find_compiler = 0
+    uses_gcc = (
+        (find_compiler and
+            find_compiler < len(sys.argv) and
+            sys.argv[find_compiler] in (
+                'unix', 'mingw32', 'cygwin')) or
+        ('--compiler=unix' in sys.argv) or
+        ('--compiler=mingw32' in sys.argv) or
+        ('--compiler=cygwin' in sys.argv))
+else:
+    uses_gcc = True
+if uses_gcc:
+    CFLAGS.append('-fno-strict-aliasing')
+
+
+# apply "optional" patches
+i, o, e = os.popen3("patch --version")
+vs = o.read()
+o.close()
+e.close()
+if vs:
+    print "'patch' utility found, applying selected patchsets..."
+    import shutil
+    def apply_patchset(ps):
+        print "Applying patchset '%s':" % ps
+        pattern = "*.[ch]-??.v%s-%s.diff" % (clips_version, ps)
+        for x in glob(_p(ClipsPATCH_dir, pattern)):
+            pfn = os.path.basename(x)
+            sourcefile = pfn.split('-', 1)[0]
+            if not os.path.exists(_p(ClipsLIB_dir, "%s.ORIG" % sourcefile)):
+                sys.stdout.write(
+                    "patching %s (original in %s.ORIG)... " % (
+                        sourcefile, sourcefile))
+                shutil.copy(
+                    _p(ClipsLIB_dir, sourcefile),
+                    _p(ClipsLIB_dir, "%s.ORIG" % sourcefile)
+                    )
+                patchcmd = "patch -l -s -p0 %s < %s" % (
+                    _p(ClipsLIB_dir, sourcefile), x)
+                if not os.system(patchcmd):
+                    print "ok."
+                else:
+                    print "FAILED"
+    for x in APPLY_PATCHSETS:
+        apply_patchset(x)
+
+
+# create the version submodule
+sys.stdout.write("Creating version number: ")
+f = open(_p('clips', '_version.py'), 'w')
+f.write("""# version number
+version_string = "%s"
+version = (%s, %s, %s, %s)
+""" % (PYCLIPS_VERSION, PYCLIPS_MAJOR,
+       PYCLIPS_MINOR, PYCLIPS_PATCHLEVEL,
+       PYCLIPS_INCREMENTAL))
+f.close()
+
+# start setup
+print "Standard setup in progress:"
+
+
+# The following is a warning to users of ez_setup when using GCC (for
+# instance MinGW) and it is set as the default compiler, since it is
+# difficult for me to detect which compiler is used.
+warn_default_gcc = """
+WARNING: if you are using setuptools and GCC (eg. MinGW) as your default
+         compiler, it has not been detected. This can lead to unexpected
+         behaviours such as crashes. If you experience such behaviours,
+         please rebuild the module specifying, for instance, the option
+         '--compiler=mingw32' on the setup command line.
+"""
+
+# possibly use ez_setup/setuptools, or standard distutils if not possible
+# and if not using a debug executable (this is mainly because it would
+# pollute MY setup): the following way to discover under what circumstances
+# we are running is definitely hideous
+DEBUGGING = bool(
+    sys.executable.endswith('_d')
+    or sys.executable.endswith('_d.exe'))
+if not DEBUGGING:
+    try:
+        import ez_setup
+        ez_setup.use_setuptools()
+        from setuptools import setup, Extension
+        print "Using setuptools instead of distutils..."
+        if not uses_gcc:
+            print warn_default_gcc
+    except:
+        from distutils.core import setup, Extension
+else:
+    from distutils.core import setup, Extension
+
+
+setup(name="pyclips",
+      version="%s-clips_%s" % (PYCLIPS_VERSION, clips_version),
+      description="Python CLIPS interface",
+      long_description=__doc__,
+      author="Francesco Garosi",
+      author_email="franzg at users.sourceforge.net",
+      url="http://pyclips.sourceforge.net",
+      packages=['clips'],
+      ext_modules=[
+          Extension('clips._clips',
+                    main_clipssrc + all_clipssrc,
+                    extra_compile_args=CFLAGS,
+                    include_dirs=[ClipsLIB_dir]),
+          ],
+     )
+
+
+# end.
diff --git a/testsuite/test_00.py b/testsuite/test_00.py
new file mode 100644
index 0000000..a744c2e
--- /dev/null
+++ b/testsuite/test_00.py
@@ -0,0 +1,56 @@
+# test_00.py
+# initial (hence the name '00') definitions for testing purposes
+
+
+"""\
+TESTS:
+
+CurrentEnvironment
+Environment
+"""
+
+
+import clips, unittest
+import gc
+
+
+class ctestcase(unittest.TestCase):
+    """base class for pyclips unit test cases"""
+
+    def setUp(self):
+        """set up testing environment"""
+        e1 = clips.Environment()
+        self.envdict = {
+            'clips': clips,
+            'env': e1,
+            }
+        clips.DebugConfig.WatchAll()
+        e1.DebugConfig.WatchAll()
+
+    def tearDown(self):
+        clips.DebugConfig.UnwatchAll()
+        self.envdict['env'].DebugConfig.UnwatchAll()
+        s = clips.TraceStream.Read()
+        fc = open("trace.out", 'a')
+        fc.write("=" * 78 + "\n")
+        fc.write("--> %s\n" % self.__class__.__name__)
+        fc.write("-" * 78 + "\n")
+        fc.write("%s" % s)
+        fc.write("\n\n\n")
+        fc.close()
+        s = clips.ErrorStream.Read()
+        fc = open("error.out", 'a')
+        fc.write("=" * 78 + "\n")
+        fc.write("--> %s\n" % self.__class__.__name__)
+        fc.write("-" * 78 + "\n")
+        fc.write("%s" % s)
+        fc.write("\n\n\n")
+        fc.close()
+        o = gc.collect()
+        fc = open("garbage.out", 'a')
+        fc.write("%s --> %s unreached objects\n" % (
+            self.__class__.__name__, o))
+        fc.close()
+
+
+# end.
diff --git a/testsuite/test_class.py b/testsuite/test_class.py
new file mode 100644
index 0000000..4fbf59f
--- /dev/null
+++ b/testsuite/test_class.py
@@ -0,0 +1,394 @@
+# test_classes.py
+
+
+"""revision $Id: test_class.py 306 2006-06-22 00:15:55Z Franz $
+TESTS:
+
+BuildClass
+BuildInstance
+ClassList
+FindClass
+LoadInstancesFromString
+FindInstance
+BuildMessageHandler
+
+Class:
+  IsSuperclassOf
+  IsSubclassOf
+  Subclasses
+  Abstract
+  Reactive
+  Deletable
+  Description
+  PPForm
+  Name
+  Module
+  BuildSubclass
+  Deletable
+  WatchSlots
+  WatchInstances
+  MessageHandlerIndex
+  MessageHandlerWatched
+  UnwatchMessageHandler
+  WatchMessageHandler
+  MessageHandlerName
+  MessageHandlerType
+  NextMessageHandlerIndex
+  MessageHandlerDeletable
+  AddMessageHandler
+  RemoveMessageHandler
+  MessageHandlerPPForm
+  BuildInstance
+  RawInstance
+
+Class.Slots
+  Names
+  NamesDefined
+  Exists
+  ExistsDefined
+  Cardinality
+  AllowedValues
+  AllowedClasses
+  Types, Slots.Sources
+  IsPublic
+  IsInitable
+  Range
+  IsWritable
+  HasDirectAccess
+  Facets
+  DefaultValue
+
+Instance:
+  Slots
+  GetSlot
+  PutSlot
+  PPForm
+  Class
+  Name
+"""
+
+
+default_classes = """\
+MAIN::FLOAT
+MAIN::INTEGER
+MAIN::SYMBOL
+MAIN::STRING
+MAIN::MULTIFIELD
+MAIN::EXTERNAL-ADDRESS
+MAIN::FACT-ADDRESS
+MAIN::INSTANCE-ADDRESS
+MAIN::INSTANCE-NAME
+MAIN::OBJECT
+MAIN::PRIMITIVE
+MAIN::NUMBER
+MAIN::LEXEME
+MAIN::ADDRESS
+MAIN::INSTANCE
+MAIN::USER
+MAIN::INITIAL-OBJECT""".split()
+
+
+class ctc_Class(ctestcase):
+    """test Class objects"""
+
+    def ctf_Class_01(self):
+        """Testing: BuildClass, FindClass, ClassList, {...}\n""" \
+        """         Class.IsSubclassOf, Class.IsSuperclassOf,\n""" \
+        """         Class.Subclasses, Class.Superclasses,\n""" \
+        """         Class.Abstract, Class.Reactive"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            li = e.ClassList()
+            self.assertEqual(default_classes, map(str, li))
+            c0 = e.FindClass("USER")
+            c1 = e.FindClass("OBJECT")
+            c2 = e.BuildClass("C", "(is-a USER)", "New Class")
+            for name in c2.Superclasses():
+                c = e.FindClass(name)
+                self.assert_(c.IsSuperclassOf(c2))
+                self.assert_(c2.IsSubclassOf(c))
+            for name in c0.Subclasses():
+                c = e.FindClass(name)
+                self.assert_(c.IsSubclassOf(c0))
+                self.assert_(c0.IsSuperclassOf(c))
+            self.assert_(not c2.Abstract)
+            self.assert_(c2.Reactive)
+            self.assert_(c1.Abstract)
+            self.assert_(not c1.Reactive)
+
+    def ctf_Class_02(self):
+        """Testing: Clear, Reset, Class.PPForm, Class.Description, Class.Module"""
+        e0 = self.envdict['clips']
+        e2 = self.envdict['env']
+        for e in [e0, e2]:
+            e.Clear()
+            e.Reset()
+        c0 = e0.BuildClass("C2", "(is-a USER)", "New Class")
+        e2.Build(c0.PPForm())
+        c2 = e2.FindClass("C2")
+        self.assertEqual(c0.Description(), c2.Description())
+        self.assertEqual(c0.Module, c2.Module)
+
+    def ctf_Class_03(self):
+        """Testing: Class.BuildSubclass"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            D = C.BuildSubclass("D")
+            self.assert_(C.IsSuperclassOf(D))
+
+    def ctf_Class_04(self):
+        """Testing: Class.WatchSlots, Class.WatchInstances"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            self.assert_(C.WatchSlots)
+            self.assert_(C.WatchInstances)
+
+    def ctf_Class_05(self):
+        """Testing: Class.MessageHandlerIndex, Class.MessageHandlerWatched"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass(
+                "C", "(is-a USER)(slot s1 (create-accessor read-write))")
+            self.assertEqual(C.MessageHandlerIndex("get-s1", "primary"), 1)
+            self.assertEqual(C.MessageHandlerIndex("put-s1", "primary"), 2)
+            self.assert_(C.MessageHandlerWatched(1))
+            self.assert_(C.MessageHandlerWatched(2))
+
+    def ctf_Class_06(self):
+        """Testing: Class.UnwatchMessageHandler, Class.WatchMessageHandler"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass(
+                "C", "(is-a USER)(slot s1 (create-accessor read-write))")
+            C.UnwatchMessageHandler(1)
+            self.assert_(not C.MessageHandlerWatched(1))
+            C.WatchMessageHandler(1)
+            self.assert_(C.MessageHandlerWatched(1))
+
+    def ctf_Class_07(self):
+        """Testing: Class.MessageHandlerName, Class.MessageHandlerType"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass(
+                "C", "(is-a USER)(slot s1 (create-accessor read-write))")
+            self.assertEqual(C.MessageHandlerName(1), "get-s1")
+            self.assertEqual(C.MessageHandlerName(2), "put-s1")
+            self.assertEqual(C.MessageHandlerType(1), "primary")
+            self.assertEqual(C.MessageHandlerType(2), "primary")
+
+    def ctf_Class_08(self):
+        """Testing: Class.NextMessageHandlerIndex, Class.MessageHandlerDeletable"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass(
+                "C", "(is-a USER)(slot s1 (create-accessor read-write))")
+            self.assertEqual(C.NextMessageHandlerIndex(1), 2)
+            self.assert_(not C.MessageHandlerDeletable(1))
+            self.assert_(not C.MessageHandlerDeletable(2))
+
+    def ctf_Class_09(self):
+        """Testing: BuildMessageHandler, Class.AddMessageHandler, {...}"""
+        """         Class.RemoveMessageHandler, Class.MessageHandlerPPForm"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            self.assertEqual(C.AddMessageHandler("m1", "", "(return nil)"), 1)
+            self.assertEqual(e.BuildMessageHandler("m2", C, "", "(return nil)"), 2)
+            anonppf1 = C.MessageHandlerPPForm(1).replace("1", "??")
+            anonppf2 = C.MessageHandlerPPForm(2).replace("2", "??")
+            self.assertEqual(anonppf1, anonppf2)
+            self.assert_(C.MessageHandlerDeletable(1))
+            C.RemoveMessageHandler(2)
+
+    def ctf_Class_10(self):
+        """Testing: Class.BuildInstance, Class.RawInstance"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            i1 = C.BuildInstance("i1")
+            i2 = C.RawInstance("i2")
+            self.assertEqual(i1.Class.Name, i2.Class.Name)
+
+    def ctf_Class_11(self):
+        """Testing: Class.MessageHandlerList, Class.AllMessageHandlerList"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            C.AddMessageHandler("m1", "", "(return nil)")
+            D = C.BuildSubclass("D")
+            D.AddMessageHandler("m2", "", "(return nil)")
+            liD = D.MessageHandlerList()
+            liAD = D.AllMessageHandlerList()
+            self.assert_(len(liD) < len(liAD))
+
+    def ctf_Instance_01(self):
+        """Testing: BuildInstance, Class.Deletable, Instance.Slots, Instance.PPForm"""
+        d1 = []
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            c = e.BuildClass("C3", """
+                (is-a USER)
+                (slot ts1 (type SYMBOL))
+                (multislot ts2)
+            """)
+            self.assert_(c.Deletable)
+            s1 = clips.Symbol(e.Eval("(gensym*)"))
+            s2 = clips.Symbol(e.Eval("(gensym*)"))
+            s3 = clips.Symbol(e.Eval("(gensym*)"))
+            m1 = clips.Multifield([s2, s3])
+            i = e.BuildInstance("test", c)
+            self.assert_(not c.Deletable)
+            i.Slots['ts1'] = s1
+            i.PutSlot('ts2', m1)
+            rs1 = i.GetSlot('ts1')
+            rm1 = i.Slots['ts2']
+            self.assertEqual(rs1, s1)
+            self.assertEqual(rm1, m1)
+            self.assertEqual(len(i.Slots.keys()), 2)
+            d1.append(i.PPForm())
+        self.assertEqual(d1[0], d1[-1])
+
+    def ctf_Instance_02(self):
+        """Testing: FindInstance, Instance.Class, Instance.Name"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            c = e.BuildClass("C4", "(is-a USER)")
+            i = e.BuildInstance("test-%s" % x, c)
+            i0 = e.FindInstance("test-%s" % x)
+            self.assertEqual(i.Name, "test-%s" % x)
+            self.assertEqual(i.Class.Name, "C4")
+            self.assertEqual(i.PPForm(), i0.PPForm())
+
+    def ctf_Instance_03(self):
+        """Testing: LoadInstancesFromString"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            c = e.BuildClass("C4", "(is-a USER)")
+            e.LoadInstancesFromString("(d of C4)(f of C4)")
+            d = e.FindInstance('d')
+            f = e.FindInstance('f')
+            self.assertEqual(d.Class.Name, "C4")
+            self.assertEqual(f.Class.Name, "C4")
+
+    def ctf_Slots_01(self):
+        """Testing: Slots.Names, Slots.Exists, Slots.ExistsDefined, {...}"""
+        """         Slots.NamesDefined"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass(
+                "C", "(is-a USER)(slot s1 (type INTEGER))(slot s2 (type STRING))")
+            D = C.BuildSubclass("D", "(slot s3 (type INTEGER)(default 1))")
+            li = D.Slots.Names()
+            li1 = D.Slots.NamesDefined()
+            self.assertEqual(len(li), 3)
+            self.assertEqual(len(li1), 1)
+            self.assert_(not C.Slots.Exists(li[2]))
+            self.assert_(D.Slots.Exists(li[2]))
+
+    def ctf_Slots_02(self):
+        """Testing: Slots.Cardinality, Slots.AllowedValues"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass(
+                "C", "(is-a USER)(slot s1 (type INTEGER))(slot s2 (type STRING))")
+            D = C.BuildSubclass("D", "(multislot s3 (type INTEGER)(default 1))")
+            self.assertEqual(len(D.Slots.Cardinality("s3")), 2)
+            self.assertEqual(len(D.Slots.Cardinality("s1")), 0)
+            self.assert_(not D.Slots.AllowedValues("s1"))
+
+    def ctf_Slots_03(self):
+        """Testing: Slots.Types, Slots.Sources"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass(
+                "C", "(is-a USER)(slot s1 (type INTEGER))(slot s2 (type STRING))")
+            D = C.BuildSubclass("D", "(slot s3 (type INTEGER)(default 1))")
+            self.assertEqual(D.Slots.Types("s1")[0], "INTEGER")
+            self.assertEqual(D.Slots.Sources("s1")[0], "C")
+
+    def ctf_Slots_04(self):
+        """Testing: Slots.IsPublic, Slots.IsInitable, Slots.Range"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass(
+                "C", """(is-a USER)
+                        (slot s1 (create-accessor read-write)
+                                 (type INTEGER) (range 0 1)
+                                 (visibility public))
+                        """)
+            self.assert_(C.Slots.IsPublic("s1"))
+            self.assert_(C.Slots.IsInitable("s1"))
+            self.assertEqual(int(C.Slots.Range("s1")[0]), 0)
+            self.assertEqual(int(C.Slots.Range("s1")[1]), 1)
+
+    def ctf_Slots_05(self):
+        """Testing: Slots.IsWritable, Slots.HasDirectAccess, Slots.Facets"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass(
+                "C", "(is-a USER)(slot s1 (create-accessor read-write))")
+            self.assert_(C.Slots.IsWritable("s1"))
+            self.assert_(C.Slots.HasDirectAccess("s1"))
+            self.assert_(clips.Symbol("put-s1") in C.Slots.Facets("s1"))
+
+    def ctf_Slots_06(self):
+        """Testing: Slots.DefaultValue, Slots.AllowedClasses"""
+        if clips.CLIPS_VERSION < "6.24":
+            sys.stderr.write("SKIPPED ")
+            return
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass(
+                "C", """(is-a USER)
+                        (slot s1 (allowed-classes INTEGER STRING)
+                                 (default 42))
+                        """)
+            self.assertEqual(len(C.Slots.AllowedClasses("s1")), 2)
+            self.assert_('INTEGER' in map(str, C.Slots.AllowedClasses("s1")))
+            self.assert_('STRING' in map(str, C.Slots.AllowedClasses("s1")))
+            self.assertEqual(42, int(C.Slots.DefaultValue("s1")))
+
+
+
+
+# end.
diff --git a/testsuite/test_cycnlst.py b/testsuite/test_cycnlst.py
new file mode 100644
index 0000000..e176a20
--- /dev/null
+++ b/testsuite/test_cycnlst.py
@@ -0,0 +1,613 @@
+# test_cycnlst.py
+
+import sys, re
+
+"""revision $Id: test_cycnlst.py 277 2006-05-27 17:04:33Z Franz $
+TESTS:
+FactList
+InitialFact
+InitialClass
+FindClass
+ClassList
+InstancesChanged
+InitialInstance
+InitialRule
+InitialDeffacts
+FindDeffacts
+RuleList
+FindRule
+InitialTemplate
+TemplateList
+FindTemplate
+BuildGeneric
+BuildDeffacts
+MethodList
+InitialDefinstances
+DefinstancesList
+BuildDefinstances
+BuildGeneric
+InitialGeneric
+GenericList
+FindGeneric
+InitialGlobal
+GlobalList
+FindGlobal
+BuildGlobal
+GlobalsChanged
+InitialFunction
+FunctionList
+FindFunction
+
+Function
+  Next
+  Name
+  PPForm
+  Watch
+  Deletable
+  Module
+
+Global
+  Watch
+  Deletable
+  Next
+  Name
+  PPForm
+  Value
+  ValueForm
+  Module
+
+Generic
+  Name
+  PPForm
+  Watch
+  Deletable
+  Module
+  MethodList
+  AddMethod
+  InitialMethod
+  NextMethod
+  MethodPPForm
+
+Definstances
+  Name
+  Next
+  PPForm
+  Deletable
+  Module
+
+Deffacts:
+  Name
+  Next
+  PPForm
+  Deletable
+  Module
+
+Template:
+  Name
+  Next
+  Module
+  Deletable
+  Watch
+
+Rule:
+  Next
+  Name
+  PPForm
+  Name
+  Deletable
+  Remove
+  Module
+
+Instance:
+  Next
+  FindInstance
+  Class
+  Slots
+  Send
+  IsValid
+  Remove
+  DirectRemove
+
+Class:
+  Next
+  InitialInstance
+  InitialSubclassInstance
+  NextInstance
+  NextSubclassInstance
+
+Fact:
+  Next
+  Index
+"""
+
+
+class ctc_CyclesAndLists(ctestcase):
+    """test Initial, Next and List functions"""
+
+    def ctf_CyclesFact_01(self):
+        """Testing: FactList, InitialFact, Fact.Next, Fact.Index"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.Assert("(tf1)")
+            e.Assert("(tf2)")
+            e.Assert("(tf3)")
+            e.Assert("(tf4)")
+            li = e.FactList()
+            f0 = e.InitialFact()
+            for f in li:
+                self.assertEqual(f.PPForm(), f0.PPForm())
+                f0 = f0.Next()
+            self.assertEqual(li[-1].Index, 4)
+            self.assert_(f0 is None)
+
+    def ctf_CyclesClass_01(self):
+        """Testing: ClassList, InitialClass, FindClass, Class.Next"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            D = e.BuildClass("D", "(is-a C)")
+            E = e.BuildClass("E", "(is-a D)")
+            li = e.ClassList()
+            cl0 = e.InitialClass()
+            for cln in li:
+                if cln in ['C', 'D', 'E']:
+                    cl = e.FindClass(cln)
+                    self.assertEqual(cl.PPForm(), cl0.PPForm())
+                cl0 = cl0.Next()
+            self.assert_(cl0 is None)
+
+    def ctf_CyclesInstance_01(self):
+        """Testing: InstancesChanged, InitialInstance, FindInstance, Instance.Next"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            e.InstancesChanged()
+            io = e.FindInstance('initial-object')
+            c1 = e.BuildInstance("c1", "C")
+            c2 = e.BuildInstance("c2", "C")
+            c3 = e.BuildInstance("c3", "C")
+            self.assert_(e.InstancesChanged())
+            li = [io, c1, c2, c3]
+            i0 = e.InitialInstance()
+            for i in li:
+                self.assertEqual(i.PPForm(), i0.PPForm())
+                i0 = i0.Next()
+            self.assert_(i0 is None)
+
+    def ctf_CyclesInstance_02(self):
+        """Testing: Instance.IsValid, Instance.Remove, Instance.DirectRemove"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            e.InstancesChanged()
+            c1 = e.BuildInstance("c1", "C")
+            c2 = e.BuildInstance("c2", "C")
+            self.assert_(c2.IsValid())
+            c2.Remove()
+            self.assert_(not c2.IsValid())
+            self.assert_(c1.IsValid())
+            c1.DirectRemove()
+            self.assert_(not c1.IsValid())
+
+    def ctf_CyclesInstance_03(self):
+        """Testing: Instance.Class, Instance.Slots, Instance.Send"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C",
+                             """(is-a USER)
+                                (slot s1 (default 0)
+                                         (create-accessor read-write))""")
+            e.InstancesChanged()
+            c1 = e.BuildInstance("c1", "C")
+            self.assertEqual(c1.Class.Name, C.Name)
+            self.assertEqual(c1.Send('get-s1'), 0)
+            c1.Send('put-s1', '42')
+            self.assertEqual(c1.Slots['s1'], 42)
+
+    def ctf_CyclesInstance_04(self):
+        """Testing: Class.InitialInstance, Class.InitialSubclassInstance, {...}"""
+        """         Class.NextInstance, Class.NextSubclassInstance"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            D = e.BuildClass("D", "(is-a C)")
+            d1 = e.BuildInstance("d1", "D")
+            d2 = e.BuildInstance("d2", "D")
+            c1 = e.BuildInstance("c1", "C")
+            c2 = e.BuildInstance("c2", "C")
+            i00 = C.InitialInstance()
+            i01 = C.NextInstance(i00)
+            i10 = C.InitialSubclassInstance()
+            i11 = C.NextSubclassInstance(i10)
+            i12 = C.NextSubclassInstance(i11)
+            i13 = C.NextSubclassInstance(i12)
+            i20 = D.InitialInstance()
+            i21 = D.NextInstance(i20)
+            i30 = D.InitialSubclassInstance()
+            i31 = D.NextSubclassInstance(i30)
+            self.assert_(i01 is not None)
+            self.assert_(i13 is not None)
+            self.assert_(i21 is not None)
+            self.assert_(i31 is not None)
+            self.assertEqual(i01.PPForm(), c2.PPForm())
+            self.assertEqual(i31.PPForm(), d2.PPForm())
+            self.assertEqual(i20.PPForm(), i30.PPForm())
+            self.assertEqual(i21.PPForm(), i31.PPForm())
+            lppf = [d1.PPForm(), d2.PPForm(), c1.PPForm(), c2.PPForm()]
+            for i in [i10, i11, i12, i13]:
+                ippf = i.PPForm()
+                if ippf in lppf:
+                    lppf.remove(ippf)
+            self.assert_(not lppf)
+            self.assert_(C.NextInstance(i01) is None)
+            self.assert_(D.NextInstance(i21) is None)
+            self.assert_(C.NextSubclassInstance(i13) is None)
+            self.assert_(D.NextSubclassInstance(i31) is None)
+
+    def ctf_CyclesRule_01(self):
+        """Testing: InitialRule, RuleList, FindRule, Rule.Next, Rule.PPForm"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.BuildRule("r1", "(f1)", "")
+            e.BuildRule("r2", "(f2)", "")
+            li = e.RuleList()
+            r0 = e.InitialRule()
+            for r in li:
+                self.assertEqual(r0.PPForm(), e.FindRule(r).PPForm())
+                r0 = r0.Next()
+            self.assert_(r0 is None)
+
+    def ctf_CyclesRule_02(self):
+        """Testing: Rule.Name, Rule.Deletable, Rule.Remove, Rule.Module"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            r1 = e.BuildRule("r1", "(f1)", "")
+            r2 = e.BuildRule("r2", "(f2)", "")
+            self.assert_(r1.Deletable)
+            self.assert_(r2.Deletable)
+            li = e.RuleList()
+            r0 = e.InitialRule()
+            for r in li:
+                self.assertEqual(r0.Name, e.FindRule(r).Name)
+                self.assertEqual(r0.Module, "MAIN")
+                r0 = r0.Next()
+            self.assert_(r0 is None)
+            r1.Remove()
+            r2.Remove()
+
+    def ctf_CyclesRule_03(self):
+        """Testing: Rule.WatchActivations, Rule.WatchFirings"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            r1 = e.BuildRule("r1", "(f1)", "")
+            r2 = e.BuildRule("r2", "(f2)", "")
+            li = e.RuleList()
+            r0 = e.InitialRule()
+            for r in li:
+                self.assert_(r0.WatchActivations)
+                self.assert_(r0.WatchFirings)
+                r0 = r0.Next()
+            self.assert_(r0 is None)
+
+    def ctf_CyclesTemplate_01(self):
+        """Testing: InitialTemplate, TemplateList, FindTemplate, Template.Next"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            t1 = e.BuildTemplate("tf1", "(slot s1)")
+            t2 = e.BuildTemplate("tf2", "(slot s2)")
+            li = e.TemplateList()
+            t0 = e.InitialTemplate()
+            for t in li:
+                self.assertEqual(t0.Name, e.FindTemplate(t).Name)
+                t0 = t0.Next()
+
+    def ctf_CyclesTemplate_02(self):
+        """Testing: Template.Deletable, Template.Module, Template.Watch"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            t1 = e.BuildTemplate("tf1", "(slot s1)")
+            t2 = e.BuildTemplate("tf2", "(slot s2)")
+            self.assert_(t1.Deletable)
+            self.assert_(t2.Deletable)
+            li = e.TemplateList()
+            t0 = e.InitialTemplate()
+            for t in li:
+                self.assertEqual(t0.Name, e.FindTemplate(t).Name)
+                self.assertEqual(t0.Module, "MAIN")
+                self.assert_(t0.Watch)
+                t0 = t0.Next()
+
+    def ctf_CyclesMessageHandler_01(self):
+        """Testing: MessageHandlerList"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            ws = """init
+                    delete
+                    create
+                    print
+                    direct-modify
+                    message-modify
+                    direct-duplicate
+                    message-duplicate""".split()
+            li = e.MessageHandlerList()
+            for s in li:
+                w = str(s[1])
+                if w in ws:
+                    ws.remove(w)
+            self.assert_(not ws)
+
+    def ctf_CyclesMethod_01(self):
+        """Testing: BuildGeneric, MethodList, Generic.MethodList, Generic.AddMethod"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g = e.BuildGeneric("g")
+            g.AddMethod("(?a INTEGER)", "(+ ?a ?a)")
+            g.AddMethod("(?a STRING)", "(str-cat ?a ?a)")
+            li = e.MethodList()
+            lig = g.MethodList()
+            self.assertEqual(len(li), 2)
+            self.assertEqual(len(lig), 2)
+            for i in range(len(li)):
+                self.assertEqual(li[i][0], clips.Symbol("g"))
+                self.assertEqual(li[i][1], lig[i])
+                if li[i][1] == 1: self.assertEqual(e.Call("g", 21), 42)
+                elif li[i][1] == 2:
+                    self.assertEqual(
+                        e.Call("g", clips.String("spam")), "spam" * 2)
+                else: self.assert_(False)
+
+    def ctf_CyclesMethod_02(self):
+        """Testing: Generic.InitialMethod, Generic.NextMethod, Generic.MethodPPForm"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g = e.BuildGeneric("g")
+            g.AddMethod("(?a INTEGER)", "(+ ?a ?a)")
+            g.AddMethod("(?a STRING)", "(str-cat ?a ?a)")
+            lig = g.MethodList()
+            m0 = g.InitialMethod()
+            for m in lig:
+                self.assertEqual(g.MethodPPForm(m), g.MethodPPForm(m0))
+                m0 = g.NextMethod(m0)
+            self.assertEqual(m0, 0)
+
+    def ctf_CyclesDeffacts_01(self):
+        """Testing: InitialDeffacts, DeffactsList, Deffacts.Next, Deffacts.Name"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            df1 = e.BuildDeffacts("df1", "(f11)(f12)")
+            df2 = e.BuildDeffacts("df2", "(f21)(f22)")
+            li = e.DeffactsList()
+            df0 = e.InitialDeffacts()
+            for d in li:
+                self.assertEqual(d.replace("MAIN::", ""), df0.Name)
+                df0 = df0.Next()
+            self.assert_(df0 is None)
+
+    def ctf_CyclesDeffacts_02(self):
+        """Testing: FindDeffacts, Deffacts.PPForm, Deffacts.Deletable, {...}"""
+        """         Deffacts.Module"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            df1 = e.BuildDeffacts("df1", "(f11)(f12)")
+            df2 = e.BuildDeffacts("df2", "(f21)(f22)")
+            li = e.DeffactsList()
+            df0 = e.InitialDeffacts()
+            for d in li:
+                if d.replace("MAIN::", "") != "initial-fact":
+                    self.assertEqual(e.FindDeffacts(d).PPForm(), df0.PPForm())
+                self.assert_(df0.Deletable)
+                self.assertEqual(df0.Module, "MAIN")
+                df0 = df0.Next()
+            self.assert_(df0 is None)
+
+    def ctf_CyclesDefinstances_01(self):
+        """Testing: InitialDefinstances, DefinstancesList, Definstances.Next, {...}"""
+        """         Definstances.PPForm, BuildDefinstances"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            di1 = e.BuildDefinstances("di1", "(di11 of C)(di12 of C)")
+            di2 = e.BuildDefinstances("di2", "(di21 of C)(di22 of C)")
+            li = e.DefinstancesList()
+            di0 = e.InitialDefinstances()
+            for d in li:
+                if d.replace("MAIN::", "") != "initial-object":
+                    self.assertEqual(e.FindDefinstances(d).PPForm(), di0.PPForm())
+                self.assert_(di0.Deletable)
+                di0 = di0.Next()
+            self.assert_(di0 is None)
+
+    def ctf_CyclesDefinstances_02(self):
+        """Testing: Definstances.Name, Definstances.Module, Definstances.Deletable"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C1 = e.BuildClass("C1", "(is-a USER)")
+            di1 = e.BuildDefinstances("di1", "(di11 of C1)(di12 of C1)")
+            di2 = e.BuildDefinstances("di2", "(di21 of C1)(di22 of C1)")
+            li = e.DefinstancesList()
+            di0 = e.InitialDefinstances()
+            for d in li:
+                self.assertEqual(d.replace("MAIN::", ""), di0.Name)
+                self.assertEqual(e.FindDefinstances(d).Module, di0.Module)
+                self.assert_(di0.Deletable)
+                di0 = di0.Next()
+            self.assert_(di0 is None)
+
+    def ctf_CyclesGeneric_01(self):
+        """Testing: BuildGeneric, Generic.Name, Generic.PPForm, Generic.Watch"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g1 = e.BuildGeneric("g1")
+            g2 = e.BuildGeneric("g2")
+            li = e.GenericList()
+            g0 = e.InitialGeneric()
+            for g in li:
+                self.assertEqual(g.replace("MAIN::", ""), g0.Name)
+                self.assertEqual(e.FindGeneric(g).PPForm(), g0.PPForm())
+                self.assert_(g0.Watch)
+                g0 = g0.Next()
+            self.assert_(g0 is None)
+
+    def ctf_CyclesGeneric_02(self):
+        """Testing: InitialGeneric, GenericList, FindGeneric, {...}"""
+        """         Generic.Deletable, Generic.Module"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g1 = e.BuildGeneric("g1")
+            g2 = e.BuildGeneric("g2")
+            li = e.GenericList()
+            g0 = e.InitialGeneric()
+            for g in li:
+                self.assert_(g0.Deletable)
+                self.assertEqual(e.FindGeneric(g).Module, g0.Module)
+                g0 = g0.Next()
+            self.assert_(g0 is None)
+
+    def ctf_CyclesGlobal_01(self):
+        """Testing: BuildGlobal, Global.Name, Global.PPForm, {...}"""
+        """         GlobalsChanged, Global.ValueForm"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.GlobalsChanged()
+            self.assert_(not e.GlobalsChanged())
+            g1 = e.BuildGlobal("g1", clips.Integer(42))
+            g2 = e.BuildGlobal("g2", clips.Symbol("FORTY-TWO"))
+            self.assert_(e.GlobalsChanged())
+            li = e.GlobalList()
+            g0 = e.InitialGlobal()
+            for g in li:
+                self.assertEqual(g.replace("MAIN::", ""), g0.Name)
+                self.assertEqual(e.FindGlobal(g).PPForm(), g0.PPForm())
+                self.assertEqual(e.FindGlobal(g).ValueForm(), g0.ValueForm())
+                g0 = g0.Next()
+            self.assert_(g0 is None)
+
+    def ctf_CyclesGlobal_02(self):
+        """Testing: InitialGlobal, GlobalList, FindGlobal, Global.Watch, {...}"""
+        """         Global.Deletable, Global.Next, Global.Module, Global.Value"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g1 = e.BuildGlobal("g1", clips.Integer(42))
+            g2 = e.BuildGlobal("g2", clips.Symbol("FORTY-TWO"))
+            li = e.GlobalList()
+            g0 = e.InitialGlobal()
+            for g in li:
+                self.assertEqual(e.FindGlobal(g).Value, g0.Value)
+                self.assertEqual(e.FindGlobal(g).Module, g0.Module)
+                self.assert_(g0.Watch)
+                self.assert_(g0.Deletable)
+                g0 = g0.Next()
+            self.assert_(g0 is None)
+
+    def ctf_CyclesFunction_01(self):
+        """Testing: InitialFunction, FunctionList, Function.Name, Function.Next"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            f1 = e.BuildFunction("f1", ("?a", "?b"), "(+ ?a ?b)")
+            f2 = e.BuildFunction("f2", ("?a", "?b"), "(+ ?a ?b)")
+            li = e.FunctionList()
+            f0 = e.InitialFunction()
+            for f in li:
+                self.assertEqual(e.Eval("(%s 21 21)" % f.replace("MAIN::", "")), 42)
+                self.assertEqual(e.Eval("(%s 21 21)" % f0.Name), 42)
+                f0 = f0.Next()
+            self.assert_(f0 is None)
+
+    def ctf_CyclesFunction_02(self):
+        """Testing: FindFunction, Function.PPForm, Function.Watch, {...}"""
+        """         Function.Deletable, Function.Module"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            f1 = e.BuildFunction("f1", ("?a", "?b"), "(+ ?a ?b)")
+            f2 = e.BuildFunction("f2", ("?a", "?b"), "(+ ?a ?b)")
+            li = e.FunctionList()
+            f0 = e.InitialFunction()
+            for f in li:
+                self.assertEqual(e.FindFunction(f).Name, f0.Name)
+                self.assertEqual(e.FindFunction(f).Module, f0.Module)
+                self.assertEqual(e.FindFunction(f).PPForm(), f0.PPForm())
+                self.assert_(f0.Watch)
+                self.assert_(f0.Deletable)
+                f0 = f0.Next()
+            self.assert_(f0 is None)
+
+    def ctf_CyclesModule_01(self):
+        """Testing: InitialModule, BuildModule, FindModule, Module.Name"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            m = e.InitialModule()
+            self.assertEqual(m.Name, "MAIN")
+            e.BuildModule("NEW_MODULE")
+            m1 = e.FindModule("NEW_MODULE")
+            self.assertEqual(m1.Name, "NEW_MODULE")
+
+    def ctf_CyclesModule_02(self):
+        """Testing: ModuleList, Module.PPForm, Module.Next"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            M1 = e.BuildModule("M1")
+            M2 = e.BuildModule("M2")
+            li = e.ModuleList()
+            M0 = e.InitialModule()
+            for m in li:
+                self.assertEqual(m, M0.Name)
+                if m != "MAIN":
+                    self.assertEqual(e.FindModule(m).PPForm(), M0.PPForm())
+                M0 = M0.Next()
+            self.assert_(M0 is None)
+
+
+
+# end.
diff --git a/testsuite/test_fact.py b/testsuite/test_fact.py
new file mode 100644
index 0000000..74b862e
--- /dev/null
+++ b/testsuite/test_fact.py
@@ -0,0 +1,411 @@
+# test_fact.py
+
+"""revision $Id: test_fact.py 321 2006-10-10 16:22:00Z Franz $
+TESTS:
+
+Assert
+BuildTemplate
+BuildRule
+FactList
+StdoutStream
+FactListChanged
+InitialFact
+LoadFactsFromString
+RefreshAgenda
+ReorderAgenda
+
+Rule
+  Refresh
+
+Fact:
+  Fact
+  Assert
+  Index
+  PPForm
+  CleanPPForm
+  Retract
+  Exists
+  Slots
+  AssignSlotDefaults
+  Next
+  ImpliedSlots
+
+Template:
+  Name
+  Deletable
+  Module
+  InitialFact
+  NextFact
+
+Template.Slots:
+  AllowedValues
+  Cardinality
+  HasDefault
+  DefaultValue
+  Exists
+  Range
+  Names
+  Types
+  IsSinglefield
+  IsMultifield
+
+"""
+
+
+class ctc_Fact(ctestcase):
+    """test Fact objects"""
+
+    def ctf_Fact_01(self):
+        """Testing: Assert, FactList, Fact.PPForm"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.Assert("(duck)")
+            li = e.FactList()
+            for f in li:
+                if str(f) == 'f-1':
+                    self.assertEqual(f.PPForm().split(None, 1)[1], "(duck)")
+
+    def ctf_Fact_02(self):
+        """Testing: Fact.Index, Fact.Exists, Fact.Retract"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.Assert("(duck)")
+            li = e.FactList()
+            for f in li:
+                if f.Index == 1:
+                    f1 = f
+            self.assert_(f1.Exists)
+            f1.Retract()
+            self.assert_(not f1.Exists)
+            li = e.FactList()
+            self.assertEqual(len(li), 1)
+
+    def ctf_Fact_03(self):
+        """Testing: FactListChanged"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            f = e.Assert("(duck)")
+            self.assert_(e.FactListChanged())
+            f.Retract()
+            self.assert_(e.FactListChanged())
+
+    def ctf_Fact_04(self):
+        """Testing: InitialFact, Fact.Next, Fact.CleanPPForm"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            f = e.Assert("(duck)")
+            f1 = e.InitialFact()
+            f2 = f1.Next()
+            self.assertEqual(f2.CleanPPForm(), "(duck)")
+
+    def ctf_Fact_05(self):
+        """Testing: LoadFactsFromString"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            f = e.LoadFactsFromString("(duck)(quack)")
+            f1 = e.InitialFact()
+            f2 = f1.Next()
+            f3 = f2.Next()
+            self.assertEqual(f3.CleanPPForm(), "(quack)")
+
+    def ctf_Fact_06(self):
+        """Testing: Fact.ImpliedSlots"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            f = e.Assert("(duck 42)")
+            self.assertEqual(f.ImpliedSlots[0], 42)
+
+    def ctf_Fact_07(self):
+        """Testing: Rule.Refresh"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            dr = e.BuildRule("dr", "(duck)", """
+                (bind ?fn (sym-cat q- (gensym*)))
+                (assert (quack ?fn))""")
+            e.Assert("(duck)")
+            self.assert_(e.Run())
+            self.assert_(not e.Run())
+            dr.Refresh()
+            self.assert_(e.Run())
+            self.assert_(not e.Run())
+
+    def ctf_Fact_08(self):
+        """Testing: RefreshAgenda, ReorderAgenda"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            dr1 = e.BuildRule("dr1", "(duck)", "(assert (quack1))")
+            dr2 = e.BuildRule("dr2", "(duck)", "(assert (quack1))(assert (quack2))")
+            e.Assert("(duck)")
+            e.EngineConfig.Strategy = clips.COMPLEXITY_STRATEGY
+            e.RefreshAgenda()
+            a1 = e.InitialActivation()
+            e.EngineConfig.Strategy = clips.DEPTH_STRATEGY
+            e.ReorderAgenda()
+            a2 = e.InitialActivation()
+            self.assert_(a1.Name != a2.Name)
+
+    def ctf_Template_01(self):
+        """Testing: BuildTemplate, BuildRule, Run, Fact, Fact.Slots, Fact.Assert"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            t1 = e.BuildTemplate(
+                "t1", "(slot s1) (slot s2)", "test template")
+            r1 = e.BuildRule("test-rule", """
+                ?f <- (t1 (s1 ?a) (s2 ?b))
+                (test (eq ?a ?b))
+            """, """
+                (retract ?f)
+                (assert (it-works))
+            """, "arises on two equal slots")
+            f1 = e.Fact(t1)
+            f1.Slots['s1'] = clips.String("test1")
+            f1.Slots['s2'] = clips.String("test1")
+            f1.Assert()
+            e.Run()
+            w0 = e.FactList()
+            fs = w0[-1].CleanPPForm()
+            self.assertEqual(fs, "(it-works)")
+
+    def ctf_Template_02(self):
+        """Testing: Fact.AssignSlotDefaults, Template.Module"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            t1 = e.BuildTemplate(
+                "t1", """
+                (slot s1 (default 1))
+                (slot s2 (default 1))
+                """, "test template")
+            self.assertEqual(t1.Module, "MAIN")
+            r1 = e.BuildRule("test-rule", """
+                ?f <- (t1 (s1 ?a) (s2 ?b))
+                (test (eq ?a ?b))
+            """, """
+                (retract ?f)
+                (assert (it-works))
+            """, "arises on two equal slots")
+            f1 = e.Fact(t1)
+            f1.AssignSlotDefaults()
+            self.assertEqual(int(f1.Slots['s1']), int(f1.Slots['s2']))
+            self.assertEqual(int(f1.Slots['s1']), 1)
+            f1.Assert()
+            e.Run()
+            w0 = e.FactList()
+            fs = w0[-1].CleanPPForm()
+            self.assertEqual(fs, "(it-works)")
+
+    def ctf_Template_03(self):
+        """Testing: Template.Name, Template.Deletable, StdoutStream.Read"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            t1 = e.BuildTemplate(
+                "t1", """
+                (slot s1 (default 1))
+                (slot s2 (default 1))
+                """, "test template")
+            self.assert_(t1.Deletable)
+            r1 = e.BuildRule("test-rule", """
+                ?f <- (t1 (s1 ?a) (s2 ?b))
+                (test (eq ?a ?b))
+            """, """
+                (retract ?f)
+                (printout t (+ ?a ?b))
+            """, "arises on two equal slots")
+            self.assert_(not t1.Deletable)
+            self.assertEqual(t1.Name, "t1")
+            f1 = e.Fact(t1)
+            f1.AssignSlotDefaults()
+            f1.Assert()
+            clips.StdoutStream.Read()
+            e.Run()
+            i = int(clips.StdoutStream.Read())
+            self.assertEqual(i, 2)
+
+    def ctf_Template_04(self):
+        """Testing: Template.InitialFact, Template.NextFact"""
+        if clips.CLIPS_VERSION < "6.23":
+            sys.stderr.write("SKIPPED ")
+            return
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            t1 = e.BuildTemplate(
+                "t1", """
+                (slot s1 (default 1))
+                (slot s2 (default 1))
+                """, "test template")
+            f1 = e.Fact(t1)
+            f1.AssignSlotDefaults()
+            f1.Assert()
+            f2 = e.Fact(t1)
+            f2.Slots['s1'] = 2
+            f2.Slots['s2'] = 2
+            f2.Assert()
+            ff1 = t1.InitialFact()
+            self.assertEqual(ff1.Slots['s1'], 1)
+            self.assertEqual(ff1.Slots['s2'], 1)
+            ff2 = t1.NextFact(ff1)
+            self.assertEqual(ff2.Slots['s1'], 2)
+            self.assertEqual(ff2.Slots['s2'], 2)
+
+    def ctf_Template_05(self):
+        """Testing: Template.Slots.AllowedValues, Template.Slots.Cardinality"""
+        if clips.CLIPS_VERSION < "6.24":
+            sys.stderr.write("SKIPPED ")
+            return
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            t1 = e.BuildTemplate(
+                "t1", """
+                (slot s1)
+                (slot s2 (allowed-integers 42 13)
+                         (allowed-symbols foo)
+                         )
+                (multislot s3 (cardinality ?VARIABLE 42))
+                """, "test template")
+            c = t1.Slots.Cardinality("s3")
+            self.assert_(not t1.Slots.AllowedValues("s1"))
+            self.assertEqual(len(t1.Slots.AllowedValues("s2")), 3)
+            self.assertEqual(c[0], 0)
+            self.assertEqual(c[1], 42)
+
+    def ctf_Template_06(self):
+        """Testing: Template.Slots.HasDefault, Template.Slots.DefaultValue"""
+        if clips.CLIPS_VERSION < "6.24":
+            sys.stderr.write("SKIPPED ")
+            return
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            t1 = e.BuildTemplate(
+                "t1", """
+                (slot s0)
+                (slot s1 (default ?NONE))
+                (slot s2 (default 42))
+                (slot s3 (default-dynamic (gensym)))
+                """, "test template")
+            self.assertEqual(t1.Slots.HasDefault("s0"), clips.STATIC_DEFAULT)
+            self.assertEqual(t1.Slots.HasDefault("s1"), clips.NO_DEFAULT)
+            self.assertEqual(t1.Slots.HasDefault("s2"), clips.STATIC_DEFAULT)
+            self.assertEqual(t1.Slots.DefaultValue("s2"), 42)
+            self.assertEqual(t1.Slots.HasDefault("s3"), clips.DYNAMIC_DEFAULT)
+
+    def ctf_Template_07(self):
+        """Testing: Template.Slots.Exists, Template.Slots.Range"""
+        if clips.CLIPS_VERSION < "6.24":
+            sys.stderr.write("SKIPPED ")
+            return
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            t1 = e.BuildTemplate(
+                "t1", """
+                (slot s0)
+                (slot s1 (type SYMBOL))
+                (slot s2 (range 13 42))
+                """, "test template")
+            self.assert_(t1.Slots.Exists("s0"))
+            self.assert_(t1.Slots.Exists("s1"))
+            self.assert_(t1.Slots.Exists("s2"))
+            self.assert_(not t1.Slots.Exists("s3"))
+            rs0 = t1.Slots.Range("s0")
+            self.assertEqual(rs0[0], '-oo')
+            self.assertEqual(rs0[1], '+oo')
+            self.assert_(not t1.Slots.Range("s1"))
+            rs2 = t1.Slots.Range("s2")
+            self.assertEqual(rs2[0], 13)
+            self.assertEqual(rs2[1], 42)
+
+    def ctf_Template_08(self):
+        """Testing: Template.Slots.Names, Template.Slots.Types"""
+        if clips.CLIPS_VERSION < "6.24":
+            sys.stderr.write("SKIPPED ")
+            return
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            t1 = e.BuildTemplate(
+                "t1", """
+                (slot s0)
+                (slot s1 (type LEXEME))
+                (slot s2 (type INTEGER))
+                """, "test template")
+            n = map(str, t1.Slots.Names())
+            self.assert_('s0' in n)
+            self.assert_('s1' in n)
+            self.assert_('s2' in n)
+            self.assert_('s3' not in n)
+            t = map(str, t1.Slots.Types("s1"))
+            self.assert_('STRING' in t)
+            self.assert_('SYMBOL' in t)
+            self.assert_('INTEGER' not in t)
+            t = map(str, t1.Slots.Types("s2"))
+            self.assert_('SYMBOL' not in t)
+            self.assert_('INTEGER' in t)
+
+    def ctf_Template_09(self):
+        """Testing: Template.Slots.IsSinglefield, Template.Slots.IsMultifield"""
+        if clips.CLIPS_VERSION < "6.24":
+            sys.stderr.write("SKIPPED ")
+            return
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            t1 = e.BuildTemplate(
+                "t1", """
+                (slot s1)
+                (multislot s2)
+                """, "test template")
+            self.assert_(t1.Slots.IsSinglefield('s1'))
+            self.assert_(not t1.Slots.IsMultifield('s1'))
+            self.assert_(not t1.Slots.IsSinglefield('s2'))
+            self.assert_(t1.Slots.IsMultifield('s2'))
+
+    def ctf_Template_10(self):
+        """Testing: Template Facts coherence between assertions"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            t1 = e.BuildTemplate(
+                "t1", """
+                (slot s1)
+                """, "test template")
+            f11 = t1.BuildFact()
+            f11.Slots['s1'] = clips.Symbol("sym13")
+            f12 = t1.BuildFact()
+            f12.Slots['s1'] = clips.Symbol("sym42")
+            f11.Assert()
+            self.assertEqual(f11.Slots['s1'], clips.Symbol("sym13"))
+            self.assertEqual(f12.Slots['s1'], clips.Symbol("sym42"))
+
+
+# end.
diff --git a/testsuite/test_funcgenr.py b/testsuite/test_funcgenr.py
new file mode 100644
index 0000000..81a8437
--- /dev/null
+++ b/testsuite/test_funcgenr.py
@@ -0,0 +1,163 @@
+# test_funcgenr.py
+
+
+"""revision: $Id: test_funcgenr.py 215 2004-11-26 16:10:56Z Franz $
+TESTS:
+BuildFunction
+RegisterPythonFunction
+UnregisterPythonFunction
+BuildGeneric
+FindFunction
+FindGeneric
+
+Function:
+  Name
+  Module
+  Deletable
+  Watch
+
+Generic:
+  AddMethod
+  RemoveMethod
+  MethodList
+  Module
+  Watch
+  MethodWatched
+  WatchMethod
+  UnwatchMethod
+  MethodDeletable
+
+"""
+
+
+
+class ctc_Function(ctestcase):
+    """test Function objects"""
+
+    def ctf_Function_01(self):
+        """Testing: BuildFunction, Function.Name, Function.Module"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            f1 = e.BuildFunction("tf", "?a ?b", "(str-cat ?a ?b)")
+            self.assertEqual(f1.Module, "MAIN")
+            self.assertEqual(e.Eval('(%s "s1" "s2")' % f1.Name), "s1s2")
+
+    def ctf_Function_02(self):
+        """Testing: RegisterPythonFunction, UnregisterPythonFunction"""
+        def tfunc(a, b):
+            return a + b
+        clips.RegisterPythonFunction(tfunc)
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            self.assertEqual(e.Eval("(python-call tfunc 13 29)"), 42)
+            self.assertEqual(e.Eval('(python-call tfunc "4" "2")'), "42")
+        clips.UnregisterPythonFunction(tfunc)
+
+    def ctf_Function_03(self):
+        """Testing: FindFunction, Function.Deletable, Function.Watch, {...}"""
+        """         Function.PPForm"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            f1 = e.BuildFunction("tf", "?a ?b", "(str-cat ?a ?b)")
+            f2 = e.BuildFunction("tfd", "?a ?b", "(tf ?a ?b)")
+            self.assert_(f2.Deletable)
+            self.assert_(not f1.Deletable)
+            self.assert_(f1.Watch)
+            self.assert_(f2.Watch)
+            self.assertEqual(e.FindFunction("tfd").PPForm(), f2.PPForm())
+
+
+class ctc_Generic(ctestcase):
+    """test Generic objects"""
+
+    def ctf_Generic_01(self):
+        """Testing: BuildGeneric, Generic.AddMethod, Generic.Name, Generic.Watch"""
+        def mulstr(s, n):
+            return clips.String(s * n)
+        clips.RegisterPythonFunction(mulstr)
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g1 = e.BuildGeneric("g1")
+            self.assertEqual(g1.Name, "g1")
+            self.assert_(g1.Watch)
+            g1.AddMethod(
+                [('?p1', clips.ClipsStringType), ('?p2', clips.ClipsStringType)],
+                '(str-cat ?p1 ?p2)')
+            g1.AddMethod(
+                ['?p1 STRING', '?p2 INTEGER'], "(python-call mulstr ?p1 ?p2)")
+            g1.AddMethod("(?p1 NUMBER)(?p2 NUMBER)", "(+ ?p1 ?p2)")
+            self.assertEqual(e.Eval("(g1 13 29)"), clips.Integer(42))
+            self.assertEqual(e.Eval("(g1 13.0 29.0)"), clips.Float(42.0))
+            self.assertEqual(e.Eval('(g1 "sp" "am")'), "spam")
+            self.assertEqual(len(e.Eval('(g1 "spam" 42)')) / len("spam"), 42)
+            g1.RemoveMethod(0)
+            self.assertEqual(len(g1.MethodList()), 0)
+
+    def ctf_Generic_02(self):
+        """Testing: Generic.MethodList, Generic.RemoveMethod, Generic.Module"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g1 = e.BuildGeneric("g1")
+            self.assertEqual(g1.Module, "MAIN")
+            g1.AddMethod('(?p1 STRING)(?p2 STRING)', "(str-cat ?p1 ?p2)")
+            g1.AddMethod("(?p1 NUMBER)(?p2 NUMBER)", "(+ ?p1 ?p2)")
+            self.assertEqual(len(g1.MethodList()), 2)
+            for i in g1.MethodList():
+                g1.RemoveMethod(int(i))
+            self.assertEqual(len(g1.MethodList()), 0)
+
+    def ctf_Generic_03(self):
+        """Testing: FindGeneric, Generic.Deletable, Generic.PPForm"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g1 = e.BuildGeneric("g1")
+            g1.AddMethod("(?p1 NUMBER)(?p2 NUMBER)", "(+ ?p1 ?p2)")
+            self.assert_(g1.Deletable)
+            f1 = e.BuildFunction("f1", "?a ?b", "(g1 ?a ?b)")
+            self.assert_(not g1.Deletable)
+            self.assertEqual(e.FindGeneric("g1").PPForm(), g1.PPForm())
+
+    def ctf_Generic_04(self):
+        """Testing: Generic.MethodWatched, Generic.WatchMethod, {...}"""
+        """         Generic.UnwatchMethod, Generic.MethodDeletable"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g1 = e.BuildGeneric("g1")
+            g1.AddMethod("(?p1 NUMBER)(?p2 NUMBER)", "(+ ?p1 ?p2)")
+            self.assert_(g1.MethodDeletable(1))
+            g1.UnwatchMethod(1)
+            self.assert_(not g1.MethodWatched(1))
+            g1.WatchMethod(1)
+            self.assert_(g1.MethodWatched(1))
+
+    def ctf_Generic_05(self):
+        """Testing: Generic.MethodRestrictions, Generic.MethodDescription"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g1 = e.BuildGeneric("g1")
+            g1.AddMethod("(?p1 NUMBER)(?p2 NUMBER)", "(+ ?p1 ?p2)")
+            self.assertEqual(
+                e.Eval("(get-method-restrictions g1 1)"),
+                g1.MethodRestrictions(1))
+            mdesc = g1.MethodDescription(1).split(None, 1)[1]
+            self.assertEqual(mdesc, "(NUMBER) (NUMBER)")
+
+
+
+# end.
diff --git a/testsuite/test_module.py b/testsuite/test_module.py
new file mode 100644
index 0000000..7da505d
--- /dev/null
+++ b/testsuite/test_module.py
@@ -0,0 +1,207 @@
+# test_module.py
+
+"""revision $Id: test_module.py 297 2006-06-15 00:46:44Z Franz $
+TESTS:
+BuildModule
+FocusStack
+PopFocus
+ClearFocusStack
+
+Module
+  SetCurrent
+  BuildTemplate
+  BuildRule
+  FactList
+  BuildFunction
+  BuildGeneric
+  FunctionList
+  GenericList
+  TemplateList
+  BuildClass
+  ClassList
+  BuildInstance
+  RuleList
+  BuildDeffacts
+  DeffactsList
+  BuildDefinstances
+  DefinstancesList
+  RefreshAgenda
+  ReorderAgenda
+
+"""
+
+
+class ctc_Module(ctestcase):
+    """test Module objects"""
+
+    def ctf_Module_01(self):
+        """Testing: BuildModule, FocusStack, PopFocus, Module.SetCurrent"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEST")
+            mo.SetCurrent()
+            self.assertEqual(e.FocusStack()[0], "MAIN")
+            e.PopFocus()
+            self.assertEqual(len(e.FocusStack()), 0)
+
+    def ctf_Module_02(self):
+        """Testing: ClearFocusStack"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEST")
+            self.assertEqual(e.CurrentModule().Name, "TEST")
+            mo.SetCurrent()
+            self.assertEqual(len(e.FocusStack()), 1)
+            e.ClearFocusStack()
+            self.assertEqual(len(e.FocusStack()), 0)
+
+    def ctf_Module_03(self):
+        """Testing: Module.BuildTemplate, Module.BuildRule, Module.FactList"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            MAIN = e.BuildModule("MAIN", "(export ?ALL)")
+            e.Reset()
+            t = MAIN.BuildTemplate("t", "(slot s)")
+            r = MAIN.BuildRule("r", "(start)", "(assert (t (s 42))) (focus TEST)")
+            TEST = e.BuildModule("TEST", "(import MAIN deftemplate t)")
+            tr = TEST.BuildRule("tr", "(t (s 42))", "(assert (success))")
+            MAIN.SetCurrent()
+            e.Assert("(start)")
+            self.assertEqual(e.Run(), 2)
+            f2 = e.FactList()[-1]
+            self.assertEqual(f2.Relation, "success")
+            f1 = TEST.FactList()[-1]
+            self.assertEqual(f1.Relation, "success")
+
+    def ctf_Module_04(self):
+        """Testing: Module.BuildFunction, Module.FunctionList"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEST", "(export ?ALL)")
+            f = mo.BuildFunction("f", "?a", "(+ ?a ?a)")
+            self.assertEqual(e.Eval("(f 21)"), 42)
+            self.assertEqual(f.Module, "TEST")
+            li = mo.FunctionList()
+            self.assertEqual(li[-1], f.Name)
+
+    def ctf_Module_05(self):
+        """Testing: Module.BuildGeneric, Module.GenericList"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEST", "(export ?ALL)")
+            g = mo.BuildGeneric("g")
+            self.assertEqual(g.Module, "TEST")
+            li = mo.GenericList()
+            self.assertEqual(li[-1], g.Name)
+
+    def ctf_Module_06(self):
+        """Testing: Module.BuildGlobal, Module.GlobalList"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEST", "(export ?ALL)")
+            g = mo.BuildGlobal("g", 42)
+            self.assertEqual(g.Module, "TEST")
+            self.assertEqual(g.Value, 42)
+            li = mo.GlobalList()
+            self.assertEqual(li[-1], g.Name)
+
+    def ctf_Module_07(self):
+        """Testing: Module.TemplateList"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEST")
+            t = mo.BuildTemplate("t", "(slot s)")
+            self.assertEqual(t.Module, "TEST")
+            li = mo.TemplateList()
+            self.assertEqual(li[-1], t.Name)
+
+    def ctf_Module_08(self):
+        """Testing: Module.BuildClass, Module.ClassList, Module.BuildInstance"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEST", "(export ?ALL)")
+            C = mo.BuildClass("C", "(is-a USER)")
+            self.assertEqual(C.Module, "TEST")
+            li = mo.ClassList()
+            self.assertEqual(li[-1], C.Name)
+            i = mo.BuildInstance("i", C)
+            self.assert_(i)
+
+    def ctf_Module_09(self):
+        """Testing: Module.RuleList"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEST", "(export ?ALL)")
+            r = mo.BuildRule("r", "(duck)", "(assert (quack))")
+            li = mo.RuleList()
+            self.assertEqual(li[-1], r.Name)
+
+    def ctf_Module_10(self):
+        """Testing: Module.BuildDeffacts, Module.DeffactsList"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEST", "(export ?ALL)")
+            df = mo.BuildDeffacts("df", "(duck)")
+            li = mo.DeffactsList()
+            self.assertEqual(li[-1], df.Name)
+
+    def ctf_Module_11(self):
+        """Testing: Module.BuildDefinstances, Module.DefinstancesList"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEST", "(export ?ALL)")
+            C = mo.BuildClass("C", "(is-a USER)")
+            di = mo.BuildDefinstances("di", "([c] of C)")
+            li = mo.DefinstancesList()
+            self.assertEqual(li[-1], di.Name)
+
+    def ctf_Module_12(self):
+        """Testing: Module.RefreshAgenda, Module.ReorderAgenda"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEST", "(export ?ALL)")
+            dr1 = mo.BuildRule("dr1", "(duck)", "(assert (quack1))")
+            dr2 = mo.BuildRule("dr2", "(duck)", "(assert (quack1))(assert (quack2))")
+            e.Assert("(duck)")
+            e.EngineConfig.Strategy = clips.COMPLEXITY_STRATEGY
+            e.RefreshAgenda()
+            a1 = e.InitialActivation()
+            e.EngineConfig.Strategy = clips.DEPTH_STRATEGY
+            e.ReorderAgenda()
+            a2 = e.InitialActivation()
+            self.assert_(a1.Name != a2.Name)
+
+    def ctf_Module_13(self):
+        """Testing: Module.FocusStack"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEST", "(export ?ALL)")
+            mo.SetFocus()
+            self.assertEqual(e.FocusStack()[0], "TEST")
+
+# end.
diff --git a/testsuite/test_print.py b/testsuite/test_print.py
new file mode 100644
index 0000000..24e5416
--- /dev/null
+++ b/testsuite/test_print.py
@@ -0,0 +1,258 @@
+# test_print.py
+
+import sys, re, StringIO
+
+"""revision $Id: test_print.py 247 2005-02-23 00:28:47Z Franz $
+TESTS:
+BuildGlobal
+PrintFacts
+PrintRules
+PrintAgenda
+PrintClasses
+PrintDeffacts
+PrintDefinstances
+PrintModules
+PrintInstances
+PrintGlobals
+PrintGenerics
+PrintSubclassInstances
+PrintAgenda
+PrintBreakpoints
+PrintMessageHandlers
+BrowseClasses
+
+Generic
+  PrintMethods
+
+Rule
+  PrintMatches
+
+Class
+  PrintMessageHandlers
+  PrintAllMessageHandlers
+  PreviewSend
+
+"""
+
+
+def i_returnOutput(func, args=None, kwargs=None):
+    """execute a function while redirecting stdout"""
+    io = StringIO.StringIO()
+    save_stdout = sys.stdout
+    sys.stdout = io
+    try:
+        if args is None:
+            if kwargs is None: r = func()
+            else: r = func(**kwargs)
+        else:
+            if kwargs is None: r = func(*args)
+            else: r = func(*args, **kwargs)
+        s = io.getvalue().strip()
+        sys.stdout = save_stdout
+        return r, s
+    except:
+        sys.stdout = save_stdout
+        raise
+
+
+def i_checkContains(s, rex):
+    """check whether or not the given string contains the supplied RE"""
+    return bool(re.search(rex, s) is not None)
+
+
+
+class ctc_Print(ctestcase):
+    """test debug output functions"""
+
+    def ctf_Print_01(self):
+        """Testing: PrintFacts"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.Assert("(f1)")
+            r, s = i_returnOutput(e.PrintFacts)
+            self.assert_(i_checkContains(s, r"f\-\d\s+\(initial\-fact\)"))
+            self.assert_(i_checkContains(s, r"f\-\d\s+\(f1\)"))
+
+    def ctf_Print_02(self):
+        """Testing: PrintRules, PrintAgenda"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.BuildRule("f1-rule", "(f1)", "(assert (f2))")
+            e.Assert("(f1)")
+            r, s = i_returnOutput(e.PrintRules)
+            self.assert_(i_checkContains(s, r"f1\-rule"))
+            r, s = i_returnOutput(e.PrintAgenda)
+            self.assert_(i_checkContains(s, r"\d\s+f1\-rule"))
+
+    def ctf_Print_03(self):
+        """Testing: PrintClasses, PrintDeffacts, PrintDefinstances, PrintModules"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            r, s = i_returnOutput(e.PrintClasses)
+            self.assert_(i_checkContains(s, r"INITIAL\-OBJECT"))
+            self.assert_(i_checkContains(s, r"USER"))
+            self.assert_(i_checkContains(s, r"INSTANCE"))
+            self.assert_(i_checkContains(s, r"ADDRESS"))
+            self.assert_(i_checkContains(s, r"LEXEME"))
+            self.assert_(i_checkContains(s, r"NUMBER"))
+            self.assert_(i_checkContains(s, r"PRIMITIVE"))
+            self.assert_(i_checkContains(s, r"OBJECT"))
+            # ...
+            self.assert_(i_checkContains(s, r"FLOAT"))
+            r, s = i_returnOutput(e.PrintDeffacts)
+            self.assert_(i_checkContains(s, r"initial\-fact"))
+            r, s = i_returnOutput(e.PrintDefinstances)
+            self.assert_(i_checkContains(s, r"initial\-object"))
+            r, s = i_returnOutput(e.PrintModules)
+            self.assert_(i_checkContains(s, r"MAIN"))
+
+    def ctf_Print_04(self):
+        """Testing: PrintTemplates, PrintMessageHandlers"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            r, s = i_returnOutput(e.PrintTemplates)
+            self.assert_(i_checkContains(s, r"initial\-fact"))
+            r, s = i_returnOutput(e.PrintMessageHandlers)
+            self.assert_(i_checkContains(s, r"message\-duplicate"))
+            self.assert_(i_checkContains(s, r"direct\-duplicate"))
+            self.assert_(i_checkContains(s, r"message\-modify"))
+            self.assert_(i_checkContains(s, r"direct\-modify"))
+            self.assert_(i_checkContains(s, r"print"))
+            self.assert_(i_checkContains(s, r"create"))
+            self.assert_(i_checkContains(s, r"delete"))
+            self.assert_(i_checkContains(s, r"init"))
+
+    def ctf_Print_05(self):
+        """Testing: BuildGlobal, PrintGlobals, PrintGenerics"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g = e.BuildGlobal("g", 42)
+            r, s = i_returnOutput(e.PrintGlobals)
+            self.assert_(i_checkContains(s, "g"))
+            g1 = e.BuildGeneric("g1")
+            r, s = i_returnOutput(e.PrintGenerics)
+            self.assert_(i_checkContains(s, "g1"))
+
+    def ctf_Print_06(self):
+        """Testing: PrintInstances, PrintSubclassInstances"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            c = e.BuildInstance("c", C)
+            D = e.BuildClass("D", "(is-a C)")
+            d = e.BuildInstance("d", D)
+            r, s2 = i_returnOutput(e.PrintInstances, (C,))
+            r, s3 = i_returnOutput(e.PrintInstances, (D,))
+            r, s4 = i_returnOutput(e.PrintSubclassInstances, (C,))
+            self.assert_(not i_checkContains(s2, re.escape(d.PPForm())))
+            self.assert_(i_checkContains(s3, re.escape(d.PPForm())))
+            self.assert_(not i_checkContains(s3, re.escape(c.PPForm())))
+            self.assert_(i_checkContains(s4, re.escape(c.PPForm())))
+            self.assert_(i_checkContains(s4, re.escape(d.PPForm())))
+
+    def ctf_Print_07(self):
+        """Testing: PrintAgenda, PrintBreakpoints, PrintFocusStack"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            dr = e.BuildRule("dr", "(duck)", "(assert (quack))")
+            f0 = e.Assert("(duck)")
+            rex = r"0\s+%s:\s+f-%s" % (dr.Name, f0.Index)
+            r, s = i_returnOutput(e.PrintAgenda)
+            self.assert_(i_checkContains(s, rex))
+            r, s = i_returnOutput(e.PrintBreakpoints)
+            self.assertEqual(s.strip(), "MAIN:")
+            dr.Breakpoint = True
+            r, s = i_returnOutput(e.PrintBreakpoints)
+            self.assert_(i_checkContains(s, "dr"))
+            m = e.BuildModule("MNEW", "")
+            m.SetFocus()
+            r, s = i_returnOutput(e.PrintFocusStack)
+            self.assert_(i_checkContains(s, "MNEW"))
+            self.assert_(i_checkContains(s, "MAIN"))
+
+    def ctf_Print_08(self):
+        """Testing: Generic.PrintMethods"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g = e.BuildGeneric("g")
+            g.AddMethod("(?a NUMBER)", "(+ ?a ?a)")
+            g.AddMethod("(?a STRING)", "(str-cat ?a \"+\" ?a)")
+            r, s = i_returnOutput(g.PrintMethods)
+            self.assert_(i_checkContains(s, r"g.+\(NUMBER\)"))
+            self.assert_(i_checkContains(s, r"g.+\(STRING\)"))
+
+    def ctf_Print_09(self):
+        """Testing: Rule.PrintMatches"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            r = e.BuildRule("dr", "(duck)", "(assert (quack))")
+            f = e.Assert("(duck)")
+            r, s = i_returnOutput(r.PrintMatches)
+            self.assert_(i_checkContains(s, r"Matches for Pattern 1\s+f\-1"))
+            self.assert_(i_checkContains(s, r"Activations\s+f\-1"))
+
+    def ctf_Print_10(self):
+        """Testing: Class.PrintMessageHandlers, Class.PrintAllMessageHandlers"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass(
+                "C", "(is-a USER)(slot s1 (create-accessor read-write))")
+            D = e.BuildClass(
+                "D", "(is-a C)(slot s2 (create-accessor read-write))")
+            r, s = i_returnOutput(D.PrintMessageHandlers)
+            self.assert_(i_checkContains(s, r"get-s2\ .*\ class"))
+            self.assert_(i_checkContains(s, r"put-s2\ .*\ class"))
+            self.assert_(not i_checkContains(s, r"get-s1\ .*\ class"))
+            self.assert_(not i_checkContains(s, r"put-s1\ .*\ class"))
+            r, s = i_returnOutput(D.PrintAllMessageHandlers)
+            self.assert_(i_checkContains(s, r"get-s2\ .*\ class"))
+            self.assert_(i_checkContains(s, r"put-s2\ .*\ class"))
+            self.assert_(i_checkContains(s, r"get-s1\ .*\ class"))
+            self.assert_(i_checkContains(s, r"put-s1\ .*\ class"))
+
+    def ctf_Print_11(self):
+        """Testing: BrowseClasses, Class.PreviewSend"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            C.AddMessageHandler("mh", "", "(return nil)")
+            r, s = i_returnOutput(C.PreviewSend, ("mh",))
+            self.assert_(i_checkContains(s, r"\>\> mh primary in class C"))
+            self.assert_(i_checkContains(s, r"\<\< mh primary in class C"))
+            r, s = i_returnOutput(e.BrowseClasses, ("USER",))
+            self.assert_(i_checkContains(s, r"USER\s+INITIAL\-OBJECT\s+C"))
+
+    def ctf_Print_12(self):
+        """Testing: Module.BuildGlobal, Module.ShowGlobals"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            mo = e.BuildModule("TEst", "(export ?ALL)")
+            g = mo.BuildGlobal("g", 42)
+            r, s = i_returnOutput(mo.ShowGlobals)
+            self.assert_(i_checkContains(s, re.escape("?*g* = 42")))
+
+# end.
diff --git a/testsuite/test_remove.py b/testsuite/test_remove.py
new file mode 100644
index 0000000..c2fda7b
--- /dev/null
+++ b/testsuite/test_remove.py
@@ -0,0 +1,127 @@
+# test_remove.py
+
+
+"""revision $Id: test_remove.py 215 2004-11-26 16:10:56Z Franz $
+TESTS:
+Assert
+BuildRule
+BuildTemplate
+BuildDeffacts
+BuildDefinstances
+BuildGeneric
+BuildGlobal
+
+Fact:
+  Retract
+
+Rule:
+  Remove
+
+Template:
+  Remove
+
+Deffacts:
+  Remove
+
+Definstances:
+  Remove
+
+Generic:
+  Remove
+
+Global:
+  Remove
+"""
+
+
+class ctc_Removals(ctestcase):
+    """test builds and removals"""
+
+    def ctf_RemovalsFact_01(self):
+        """Testing: Assert, Fact.Retract"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            o = e.Assert('(a)')
+            self.assert_(o.PPForm())
+            o.Retract()
+            self.assertRaises(clips.ClipsError, o.PPForm)
+            self.assertRaises(clips.ClipsError, o.Retract)
+
+    def ctf_RemovalsRule_01(self):
+        """Testing: BuildRule, Rule.Remove"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            o = e.BuildRule('tr', '(a)', '(assert (b))')
+            self.assert_(o.PPForm())
+            o.Remove()
+            self.assertRaises(clips.ClipsError, o.PPForm)
+            self.assertRaises(clips.ClipsError, o.Remove)
+
+    def ctf_RemovalsTemplate_01(self):
+        """Testing: BuildTemplate, Template.Remove"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            o = e.BuildTemplate('tdt', '(slot s1)')
+            self.assert_(o.PPForm())
+            o.Remove()
+            self.assertRaises(clips.ClipsError, o.PPForm)
+            self.assertRaises(clips.ClipsError, o.Remove)
+
+    def ctf_RemovalsDeffacts_01(self):
+        """Testing: BuildDeffacts, Deffacts.Remove"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            o = e.BuildDeffacts('tdf', '(a)')
+            self.assert_(o.PPForm())
+            o.Remove()
+            self.assertRaises(clips.ClipsError, o.PPForm)
+            self.assertRaises(clips.ClipsError, o.Remove)
+
+    def ctf_RemovalsDefinstances_01(self):
+        """Testing: BuildDefinstances, Definstances.Remove"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            o = e.BuildDefinstances('tdi', '(tdi1 of C)')
+            self.assert_(o.PPForm())
+            o.Remove()
+            self.assertRaises(clips.ClipsError, o.PPForm)
+            self.assertRaises(clips.ClipsError, o.Remove)
+
+    def ctf_RemovalsGeneric_01(self):
+        """Testing: BuildGeneric, Generic.Remove"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            o = e.BuildGeneric('g')
+            self.assert_(o.PPForm())
+            o.Remove()
+            self.assertRaises(clips.ClipsError, o.PPForm)
+            self.assertRaises(clips.ClipsError, o.Remove)
+
+    def ctf_RemovalsGlobal_01(self):
+        """Testing: BuildGlobal, Global.Remove"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            o = e.BuildGlobal('g', clips.Integer(42))
+            self.assert_(o.PPForm())
+            o.Remove()
+            self.assertRaises(clips.ClipsError, o.PPForm)
+            self.assertRaises(clips.ClipsError, o.Remove)
+
+
+
+# end.
diff --git a/testsuite/test_retpass.py b/testsuite/test_retpass.py
new file mode 100644
index 0000000..1f103ea
--- /dev/null
+++ b/testsuite/test_retpass.py
@@ -0,0 +1,70 @@
+# test_retpass.py
+
+"""revision: $Id: test_retpass.py 335 2008-01-13 01:50:50Z Franz $
+TESTS:
+passing Fact objects as arguments
+passing Instance objects as arguments
+Fact objects as return values
+Instance objects as return values
+"""
+
+class ctc_RetPass(ctestcase):
+    """test Class objects"""
+
+    def ctf_PassFacts_01(self):
+        """Testing: Fact objects as arguments"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g = e.BuildGlobal("g")
+            f = e.Assert("(a)")
+            g.Value = f
+            e.SendCommand("(ppfact ?*g*)")
+            self.assertEqual(clips.StdoutStream.Read().strip(), "(a)")
+
+    def ctf_PassInstances_01(self):
+        """Testing: Instance objects as arguments"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            g = e.BuildGlobal("g")
+            c = e.BuildClass("C", "(is-a USER)", "New Class")
+            i = c.BuildInstance("i")
+            g.Value = i
+            e.SendCommand("(send ?*g* print)")
+            self.assertEqual(
+                e.Eval("(instance-name ?*g*)"), clips.InstanceName('i'))
+
+    def ctf_RetFacts_01(self):
+        """Testing: Fact objects as return values"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.SendCommand("(defglobal ?*g* = nil)")
+            e.SendCommand("""(defrule r
+                                ?f <- (a)
+                            =>
+                                (bind ?*g* ?f))""")
+            e.SendCommand("(deffunction f () (return ?*g*))")
+            e.Assert("(a)")
+            e.Run()
+            f = clips.Eval("(f)")
+            self.assertEqual(f.Relation, clips.Symbol('a'))
+
+    def ctf_RetInstances_01(self):
+        """Testing: Instance objects as return values"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.SendCommand("(defclass C (is-a USER))")
+            e.SendCommand("(make-instance [i] of C)")
+            i = clips.Eval("(instance-address [i])")
+            self.assertEqual(i.Name, clips.InstanceName('i'))
+
+
+
+# end.
diff --git a/testsuite/test_toplev.py b/testsuite/test_toplev.py
new file mode 100644
index 0000000..3e36b1a
--- /dev/null
+++ b/testsuite/test_toplev.py
@@ -0,0 +1,192 @@
+# test_toplev.py
+
+
+"""revision $Id: test_toplev.py 321 2006-10-10 16:22:00Z Franz $
+TESTS:
+BatchStar
+AgendaChanged
+Assert
+Run
+Save
+Load
+SaveFacts
+LoadFacts
+BSave
+BLoad
+Build
+Eval
+
+"""
+
+
+file01 = """
+(defrule duck-rule "The Duck Rule"
+    ?f <- (duck)
+=>
+    (retract ?f)
+    (assert (quack)))
+"""
+
+
+class ctc_Toplevel(ctestcase):
+    """test Class objects"""
+
+    def ctf_Top_01(self):
+        """Testing: BatchStar, Save, BSave"""
+        f = open("t.clp", 'w')
+        f.write(file01)
+        f.close()
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.BatchStar("t.clp")
+            e.Assert("(duck)")
+            self.assert_(e.AgendaChanged())
+            e.Run()
+            self.assertEqual(e.FactList()[-1].CleanPPForm(), "(quack)")
+            e.Save("i_%s_c.dat" % x)
+            e.BSave("i_%s_c.bdat" % x)
+
+    def ctf_Top_02(self):
+        """Testing: Load, SaveFacts"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.Load("i_%s_c.dat" % x)
+            e.Assert("(duck)")
+            self.assert_(e.AgendaChanged())
+            e.Run()
+            self.assertEqual(e.FactList()[-1].CleanPPForm(), "(quack)")
+            e.SaveFacts("i_%s_f.dat" % x)
+
+    def ctf_Top_03(self):
+        """Testing: LoadFacts"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.LoadFacts("i_%s_f.dat" % x)
+            self.assertEqual(e.FactList()[-1].CleanPPForm(), "(quack)")
+
+    def ctf_Top_04(self):
+        """Testing: BLoad"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.BLoad("i_%s_c.bdat" % x)
+            e.Assert("(duck)")
+            self.assert_(e.AgendaChanged())
+            e.Run()
+            self.assertEqual(e.FactList()[-1].CleanPPForm(), "(quack)")
+
+    def ctf_Top_05(self):
+        """Testing: Build"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            e.Build(file01)
+            e.Assert("(duck)")
+            self.assert_(e.AgendaChanged())
+            e.Run()
+            self.assertEqual(e.FactList()[-1].CleanPPForm(), "(quack)")
+
+    def ctf_Top_06(self):
+        """Testing: Eval"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            i = e.Eval("(+ 1 1)")
+            self.assertEqual(int(i), 2)
+
+    def ctf_Top_07(self):
+        """Testing: Call"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            i1 = e.Call('+', "1 1")
+            i2 = e.Call('+', (1, 1))
+            s1 = e.Call('sym-cat', "egg spam")
+            s2 = e.Call('sym-cat', ("egg", "spam"))
+            self.assertEqual(int(i1), 2)
+            self.assertEqual(int(i2), 2)
+            self.assertEqual(str(s1), "eggspam")
+            self.assertEqual(str(s2), "eggspam")
+
+    def ctf_Top_08(self):
+        """Testing: SaveInstances, LoadInstances"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            i1 = C.BuildInstance("i1")
+            i2 = C.BuildInstance("i2")
+            e.SaveInstances("i_%s_inst.dat" % x)
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            e.LoadInstances("i_%s_inst.dat" % x)
+            self.assertEqual(e.FindInstance("i1").Name, "i1")
+            self.assertEqual(e.FindInstance("i2").Name, "i2")
+
+    def ctf_Top_09(self):
+        """Testing: BSaveInstances, BLoadInstances"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            i1 = C.BuildInstance("i1")
+            i2 = C.BuildInstance("i2")
+            e.BSaveInstances("i_%s_inst.bdat" % x)
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            e.BLoadInstances("i_%s_inst.bdat" % x)
+            self.assertEqual(e.FindInstance("i1").Name, "i1")
+            self.assertEqual(e.FindInstance("i2").Name, "i2")
+
+    def ctf_Top_10(self):
+        """Testing: Class.BuildInstance, FindInstanceLocal"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            i1 = C.BuildInstance("i1")
+            self.assertEqual(e.FindInstanceLocal("i1").Name, i1.Name)
+
+    def ctf_Top_11(self):
+        """Testing: RestoreInstancesFromString"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)")
+            e.RestoreInstancesFromString("([i1] of C) ([i2] of C)")
+            self.assert_(e.FindInstance("i1"))
+            self.assert_(e.FindInstance("i2"))
+
+
+    def ctf_TopCurrentEnvironment_01(self):
+        """Testing: CurrentEnvironment, Environment.SetCurrent, Environment.Index"""
+        clips.Clear()
+        clips.Assert("(duck)")
+        ce = clips.CurrentEnvironment()
+        e = clips.Environment()
+        self.assert_(e.Index != ce.Index)
+        e.SetCurrent()
+        clips.Reset()
+        ce.SetCurrent()
+        f = clips.FactList()[0]
+        self.assertEqual(f.CleanPPForm(), "(duck)")
+
+
+
+# end.
diff --git a/testsuite/test_zz_submitted.py b/testsuite/test_zz_submitted.py
new file mode 100644
index 0000000..d3520e8
--- /dev/null
+++ b/testsuite/test_zz_submitted.py
@@ -0,0 +1,115 @@
+# test_submitted.py
+
+"""revision $Id: test_zz_submitted.py 348 2008-03-09 01:25:16Z Franz $
+
+TESTS:
+COOL rule execution coherence on SYMBOL
+
+"""
+
+
+class ctc_Submitted(ctestcase):
+    """tests submitted by users"""
+
+    def ctf_Submitted01(self):
+        """Testing: COOL rule execution coherence on SYMBOL"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)(slot a1)")
+            c = C.BuildInstance("c")
+            c.Slots['a1'] = clips.Symbol("HELLO")
+            r = e.BuildRule(
+                "r1",
+                """(object (is-a C) (a1 ?a1&HELLO))""",
+                """(assert (success))"""
+                )
+            e.Run()
+            f = e.InitialFact()
+            while f.Next():
+                f = f.Next()
+            self.assertEqual(f.Relation, clips.Symbol("success"))
+
+
+    def ctf_Submitted02(self):
+        """Testing: COOL rule execution coherence on STRING"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            C = e.BuildClass("C", "(is-a USER)(slot a1)")
+            c = C.BuildInstance("c")
+            c.Slots['a1'] = clips.String("HELLO")
+            r = e.BuildRule(
+                "r1",
+                """
+                    (object (is-a C) (a1 ?a1))
+                    (test (eq (str-compare  ?a1 "HELLO") 0))
+                """,
+                """(assert (success))"""
+                )
+            e.Run()
+            f = e.InitialFact()
+            while f.Next():
+                f = f.Next()
+            self.assertEqual(f.Relation, clips.Symbol("success"))
+
+
+    def ctf_Submitted03(self):
+        """Testing: multiple environment consistency"""
+        env1 = clips.Environment()
+        env2 = clips.Environment()
+        t1 = env1.BuildTemplate("t1", "(slot s1)")
+        t2 = env2.BuildTemplate("t2", "(slot s2)")
+        f1 = t1.BuildFact()
+        f2 = t2.BuildFact()
+        f1.Slots["s1"] = "1"
+        f2.Slots["s2"] = "2"
+        env1.Reset()
+        env2.Reset()
+        f1.Assert()
+        f2.Assert()
+        self.assertEqual(f1.Index, f2.Index)
+        self.assertEqual(f1.Slots["s1"], clips.String("1"))
+        self.assertEqual(f2.Slots["s2"], clips.String("2"))
+    
+    def ctf_AcceptsForces01(self):
+        """Testing: parameter checking and enforcement (Case 1)"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            S1 = unicode("S1")
+            S2 = unicode("S2")
+            t1 = e.BuildTemplate(
+                "t1", """
+                (slot S1
+                    (type SYMBOL)
+                    (default TEST0))
+                (slot S2
+                    (type SYMBOL)
+                    (allowed-values TEST1 TEST2))
+                """)
+            self.assertEqual(t1.Slots.DefaultValue(S1), clips.Symbol("TEST0"))
+            self.assertEqual(t1.Slots.AllowedValues(S2)[0], clips.Symbol("TEST1"))
+            self.assertEqual(t1.Slots.AllowedValues(S2)[1], clips.Symbol("TEST2"))
+
+    def ctf_AcceptsForces02(self):
+        """Testing: parameter checking and enforcement (Case 2)"""
+        for x in self.envdict.keys():
+            e = self.envdict[x]
+            e.Clear()
+            e.Reset()
+            S0 = unicode("S0")
+            t1 = e.BuildTemplate(
+                "t1", "(slot S0)")
+            f = t1.BuildFact()
+            f.Slots[S0] = 42
+            self.assertEqual(f.Slots['S0'], 42)
+            
+            
+
+
+
+# end.
diff --git a/testsuite/tests.py b/testsuite/tests.py
new file mode 100644
index 0000000..210c39c
--- /dev/null
+++ b/testsuite/tests.py
@@ -0,0 +1,25 @@
+# tests.py
+# perform some unit tests
+# revision $Id: tests.py 188 2004-11-10 20:04:34Z Franz $
+
+import unittest
+import glob
+
+execfile('test_00.py')
+for x in glob.glob("test_[a-z]*.py"): execfile(x)
+def is_test_class(x):
+    try: return issubclass(eval(x), ctestcase)
+    except: return False
+def is_test_function(x):
+    try: return x.startswith('ctf_')
+    except: return False
+
+suite = unittest.TestSuite()
+for x in filter(is_test_class, dir()):
+    for y in filter(is_test_function, dir(eval(x))):
+        suite.addTest(eval("%s('%s')" % (x, y)))
+
+unittest.TextTestRunner(verbosity=2).run(suite)
+
+
+# end.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/python-clips.git



More information about the debian-med-commit mailing list